Jump to content

  • Log In with Google      Sign In   
  • Create Account


#Actualpinebanana

Posted 16 December 2012 - 11:58 PM

After many hours of confusion on how I should implement my Entity System; it has finally been completed (at like 4 in the morning) Posted Image. This framework is based of the Java Entity System, Artemis, however it's a bit different with the way it is implemented, but you will find similarities. Unfortunately it is not entirely complete, I believe the only thing left to do is the SceneDirector, however, that's not really a required class in the framework, it's more of an add-on to help you manage Scene* objects.

*If you are familiar with the Artemis framework, a Scene is a World.

Features:
- Unlimited component-types
- Fast retrieval of components
- Creation of components, entity-systems and entity-managers through a string

If you are going to try this framework out, please submit ANY bugs and feel free to add suggestions. I have put issues in my BitBucket repo available for the public, so please submit bugs/suggestions there. There are no known bugs at the moment, I have resolved them.

NOTE:
If you are unsure what an Entity System is, I recommend reading this basic tutorial and preferably a blog, such as this one, before reading the tutorial, which describes what one is.

EDIT: Moved to tutorial to the public wiki on BitBucket, here.

#2pinebanana

Posted 15 December 2012 - 12:36 AM

After many hours of confusion on how I should implement my Entity System; it has finally been completed (at like 4 in the morning) Posted Image. This framework is based of the Java Entity System, Artemis, however it's a bit different with the way it is implemented, but you will find similarities. Unfortunately it is not entirely complete, I believe the only thing left to do is the SceneDirector, however, that's not really a required class in the framework, it's more of an add-on to help you manage Scene* objects.

*If you are familiar with the Artemis framework, a Scene is a World.

Features:
- Unlimited component-types
- Fast retrieval of components
- Creation of components, entity-systems and entity-managers through a string

If you are going to try this framework out, please submit ANY bugs and feel free to add suggestions. I have put issues in my BitBucket repo available for the public, so please submit bugs/suggestions there. There are no known bugs at the moment, I have resolved them.

NOTE:
If you are unsure what an Entity System is, I recommend reading this basic tutorial and preferably a blog, such as this one, before reading the tutorial, which describes what one is.

Basic Tutorial for usage:

Scene

What is a Scene?
A Scene resembles a Scene, or the World in your game. It has multiple Entity objects inside of it. It can create, destroy, activate, enable and disable entities.

Entity

What is an Entity?
An Entity is a game object, they describe objects within your Scene. Such as a character, model, particle system, etc.

Creating an Entity
To create an Entity, you must first have a Scene object created.
Scene scene; // create a Scene
Now we can create one by calling the method
Scene.createEntity();
This method returns an EntityPtr, so we must store it in a variable (if we don't we'll actually get a leak, perhaps I should alter this behaviour):
EntityPtr entity = scene.createEntity(); // create an Entity

Now we may use this Entity to resemble complex objects in our game.

Common Entity functions:
- enable() - enables the Entity (entities are enabled by default, this will make EntitySystem objects possibly process this Entity)
- disable() - disables the Entity (this will make EntitySystem objects not process this Entity)
- kill() - kills the Entity
- isEnabled() - returns true if the Entity is enabled

Components

What is a Component?

A Component is what represents data for an Entity, this component may store transform information (position, rotation, scale, etc.), how fast the Entity may be going (it's velocity), collision data, or anything else you can think of.

Creating custom Components to attach to our Entity object


To create a Component, you must publicly derive from the class ac::es::Component, and you MUST define the macro AC_ES_COMPONENT(classname) INSIDE your Component. You may also define the optional macro, AC_ES_REGISTER_COMPONENT(classname) (outside the namespace out of where the class is defined), this is used for instantiating Components through a string. For example:

namespace exampleNamespace
{
	 class VelocityComponent
		 : public ac::es::Component
	 {
		  AC_ES_COMPONENT(VelocityComponent) // this macro is REQUIRED
	 public:

		  vec3 velocity; // the velocity of the object
  
		  // constructors etc.
	 };
}

AC_ES_REGISTER_COMPONENT(exampleNamespace::VelocityComponent) // optional macro

The optional macro, as stated earlier, is used to instantiate components through a string. What I mean by this is:
Component* velocityComp = Component::Create("exampleNamespace::VelocityComponent");
I recommend if possible, creating a Component with the new operator, instead of through a string. I only made this possibly for loading/saving components to a file.

Modifying our Entity object
You may modify the Entity object, by adding/removing components. After you have added/removed components from an Entity, you must activate it or refresh it (if activate has been called previously).

Adding a Component to an Entity

To add a Component to an Entity, simply call the method addComponent, through the Entity object.
For example:
entity->addComponent(new VelocityComponent(10, 0, 0)); // make it move 10 units in the x direction by default

An Entity may only have one type of component attached; it is not possible to have multiple components of the same type attached to an entity.

Removing a Component from an Entity

To remove a Component from an Entity, simply call the removeComponent method in the Entity object. You may remove a Component by it's type or passing in the Component you wish to remove as a paramater. Example:

Removing a Component by type:
entity->removeComponent<VelocityComponent>();
Removing a Component by passing it in as a parameter:
entity->removeComponent(someComponentPtr);

Determining whether an Entity contains a Component

To determine whether an Entity contains a Component, you simply call the containsComponent method for the Entity, this is very much like the removeComponent method, as you may determine if a component exists by type OR by passing in a paramter. Example:

Determining if a Component exists by type:
if(entity->containsComponent<VelocityComponent>())
{
	// ... do something with the velocity component
}
Determining if a Component exists by passing it in as a parameter:
if(entity->containsComponent(someComponentPtr))
{
	 // .. do something
}

Systems

What is a System?

A system is where all the magic happens, what I mean by magic is, it defines logic for how the game will play. For example, you may have a MovementSystem which moves all Entity objects with the VelocityComponent and PositionComponent components attached to it.

Defining a custom System

Much like defining components, you must derive from a base class and define two macros. The base class can either of:
EntitySystem - this lets you loop through all the entities to process (some of the entities you are processing may be null pointers)
EntityProcessingSystem - processes one Entity at at time (these entities that you process one at a time will NOT be pointers)

I suggest inheriting from the EntityProcessingSystem whenever you can, as it's much simpler since you do not have to deal with the loop yourself, which will lead to less bugs.

The two macros that you must define are behave exactly the same as the Component macros, except they are called: AC_ES_ENTITY_SYSTEM(classname) and AC_ES_REGISTER_ENTITY_SYSTEM(classname).

If you are processing the EntitySystem class, in order to process entities, you must override the processEntities(const ac::es::EntityArray& entities) method, note that some of the Entities in the array may be a NULL pointer, so it's best to check before you do so. If you are inheriting from the EntityProcessingSystem class, you must override the process(ac::es::Entity& entity) method.

Filtering out Components

To provide what type of Entity objects you would like to process, you set the ComponentFilter for the EntitySystem, you can do this in the constructor, by calling the parent's constructor and passing in a ComponentFilter object.

For example, our MovementSystem requires an Entity with a PositionComponent and VelocityComponent:
namespace exampleNamespace
{
	 class MovementSystem
		  : public ac::es::EntityProcessingSystem
	 {
		  AC_ES_ENTITY_SYSTEM(MovementSystem)
	 public:
	
	 	 MovementSystem()
			   : ac::es::EntityProcessingSystem(ac::es::ComponentFilter::Requires<PositionComponent>().requires<VelocityComponent>())
	 	 {
	 	 }

	 protected:
	
	 	 virtual void process(Entity& e)
	 	 {
			   PositionComponent* positionComp = e.getComponent<PositionComponent>();
			   VelocityComponent* velocityComp = e.getComponent<VelocityComponent>();
		
			   // translate the object
			   positionComp->position += velocityComp.velocity;
	 	 }
	 };
}

// register the MovementSystem
AC_ES_REGISTER_ENTITY_SYSTEM(exampleNamespace::MovementSystem)

#1pinebanana

Posted 15 December 2012 - 12:27 AM

After many hours of confusion on how I should implement my Entity System; it has finally been completed (at like 4 in the morning) Posted Image. This framework is based of the Java Entity System, Artemis, however it's a bit different with the way it is implemented, but you will find similarities. Unfortunately it is not entirely complete, I believe the only thing left to do is the SceneDirector, however, that's not really a required class in the framework, it's more of an add-on to help you manage Scene* objects.

*If you are familiar with the Artemis framework, a Scene is a World.

Features:
- Unlimited component-types
- Fast retrieval of components
- Creation of components, entity-systems and entity-managers through a string

If you are going to try this framework out, please submit ANY bugs and feel free to add suggestions. I have put issues in my BitBucket repo available for the public, so please submit bugs/suggestions there. There are no known bugs at the moment, I have resolved them.

NOTE:
If you are unsure what an Entity System is, I recommend reading this basic tutorial and preferably a blog, such as this one, before reading the tutorial, which describes what one is.

Basic Tutorial for usage:

Scene

What is a Scene?
A Scene resembles a Scene, or the World in your game. It has multiple Entity objects inside of it. It can create, destroy, activate, enable and disable entities.

Entity

What is an Entity?
An Entity is a game object, they describe objects within your Scene. Such as a character, model, particle system, etc.

Creating an Entity
To create an Entity, you must first have a Scene object created.
Scene scene; // create a Scene
Now we can create one by calling the method
Scene.createEntity();
This method returns an EntityPtr, so we must store it in a variable (if we don't we'll actually get a leak, perhaps I should alter this behaviour):
EntityPtr entity = scene.createEntity(); // create an Entity

Now we may use this Entity to resemble complex objects in our game.

Common Entity functions:
- enable() - enables the Entity (entities are enabled by default, this will make EntitySystem objects possibly process this Entity)
- disable() - disables the Entity (this will make EntitySystem objects not process this Entity)
- kill() - kills the Entity
- isEnabled() - returns true if the Entity is enabled

Components

Creating custom Components to attach to our Entity object

A Component is what represents data for an Entity, this component may store transform information (position, rotation, scale, etc.), how fast the Entity may be going (it's velocity), collision data, or anything else you can think of.

To create a Component, you must publicly derive from the class ac::es::Component, and you MUST define the macro AC_ES_COMPONENT(classname) INSIDE your Component. You may also define the optional macro, AC_ES_REGISTER_COMPONENT(classname) (outside the namespace out of where the class is defined), this is used for instantiating Components through a string. For example:

namespace exampleNamespace
{
	 class VelocityComponent
		 : public ac::es::Component
	 {
		  AC_ES_COMPONENT(VelocityComponent) // this macro is REQUIRED
	 public:

		  vec3 velocity; // the velocity of the object
  
		  // constructors etc.
	 };
}

AC_ES_REGISTER_COMPONENT(exampleNamespace::VelocityComponent) // optional macro

The optional macro, as stated earlier, is used to instantiate components through a string. What I mean by this is:
Component* velocityComp = Component::Create("exampleNamespace::VelocityComponent");
I recommend if possible, creating a Component with the new operator, instead of through a string. I only made this possibly for loading/saving components to a file.

Modifying our Entity object
You may modify the Entity object, by adding/removing components. After you have added/removed components from an Entity, you must activate it or refresh it (if activate has been called previously).

Adding a Component to an Entity

To add a Component to an Entity, simply call the method addComponent, through the Entity object.
For example:
entity->addComponent(new VelocityComponent(10, 0, 0)); // make it move 10 units in the x direction by default

An Entity may only have one type of component attached; it is not possible to have multiple components of the same type attached to an entity.

Removing a Component from an Entity

To remove a Component from an Entity, simply call the removeComponent method in the Entity object. You may remove a Component by it's type or passing in the Component you wish to remove as a paramater. Example:

Removing a Component by type:
entity->removeComponent<VelocityComponent>();
Removing a Component by passing it in as a parameter:
entity->removeComponent(someComponentPtr);

Determining whether an Entity contains a Component

To determine whether an Entity contains a Component, you simply call the containsComponent method for the Entity, this is very much like the removeComponent method, as you may determine if a component exists by type OR by passing in a paramter. Example:

Determining if a Component exists by type:
if(entity->containsComponent<VelocityComponent>())
{
	// ... do something with the velocity component
}
Determining if a Component exists by passing it in as a parameter:
if(entity->containsComponent(someComponentPtr))
{
	 // .. do something
}

Systems

What is a System?

A system is where all the magic happens, what I mean by magic is, it defines logic for how the game will play. For example, you may have a MovementSystem which moves all Entity objects with the VelocityComponent and PositionComponent components attached to it.

Defining a custom System

Much like defining components, you must derive from a base class and define two macros. The base class can either of:
EntitySystem - this lets you loop through all the entities to process (some of the entities you are processing may be null pointers)
EntityProcessingSystem - processes one Entity at at time (these entities that you process one at a time will NOT be pointers)

I suggest inheriting from the EntityProcessingSystem whenever you can, as it's much simpler since you do not have to deal with the loop yourself, which will lead to less bugs.

The two macros that you must define are behave exactly the same as the Component macros, except they are called: AC_ES_ENTITY_SYSTEM(classname) and AC_ES_REGISTER_ENTITY_SYSTEM(classname).

If you are processing the EntitySystem class, in order to process entities, you must override the processEntities(const ac::es::EntityArray& entities) method, note that some of the Entities in the array may be a NULL pointer, so it's best to check before you do so. If you are inheriting from the EntityProcessingSystem class, you must override the process(ac::es::Entity& entity) method.

Filtering out Components

To provide what type of Entity objects you would like to process, you set the ComponentFilter for the EntitySystem, you can do this in the constructor, by calling the parent's constructor and passing in a ComponentFilter object.

For example, our MovementSystem requires an Entity with a PositionComponent and VelocityComponent:
namespace exampleNamespace
{
	 class MovementSystem
		  : public ac::es::EntityProcessingSystem
	 {
		  AC_ES_ENTITY_SYSTEM(MovementSystem)
	 public:
	
	 	 MovementSystem()
			   : ac::es::EntityProcessingSystem(ac::es::ComponentFilter::Requires<PositionComponent>().requires<VelocityComponent>())
	 	 {
	 	 }

	 protected:
	
	 	 virtual void process(Entity& e)
	 	 {
			   PositionComponent* positionComp = e.getComponent<PositionComponent>();
			   VelocityComponent* velocityComp = e.getComponent<VelocityComponent>();
		
			   // translate the object
			   positionComp->position += velocityComp.velocity;
	 	 }
	 };
}

// register the MovementSystem
AC_ES_REGISTER_ENTITY_SYSTEM(exampleNamespace::MovementSystem)

PARTNERS