Giter Club home page Giter Club logo

component-entity-system's People

Contributors

laarz avatar skylarbpayne avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Forkers

ufosky

component-entity-system's Issues

Entity Factory

The EntityFactory should be able to take a configuration file (in Lua) and construct an Entity from it. Lua entity scripts will be in a format like:

Entity =
{
Render =
{
...Render component data
}
...Other components
}

The EntityFactory should have a Create method that returns an Entity and takes a lua file as a parameter.

For the EntityFactory to not have to be constantly changed with each component addition, Further components will have to implement a Load function (not a member method) which will take a Lua state and load it's own data from the lua state: IComponent* Load(lua_State* L)

The scene that instantiates the EntityFactory should register all component types to the hash table in the EntityFactory. This Hash table will have keys representing the component type (which should be the same name used in the Lua config file), and the associated value will be a function pointer (likely wrapped in the nice std::function).

The Create function will work something like this:

Entity* e = new Entity();
luaState* L = lua_newstate();
lua_getglobal(L, "Entity");
lua_pushnil(L);

while(lua_next(L, 1) != 0)
{
auto function = functions[lua_tostring(L, -2)];
if(!function) error
IComponent* c = function(L);
e->AttachComponent(c);
lua_pop(L, 1);
}
lua_close(L);
AddEntity(e);

And the load function for components will look something like:

ComponentType* c = new ComponentType();
lua_pushnil(L);
while(lua_next(L, -2) != 0)
{
//table is at index -3... Remember, table of tables!
lua_pushstring("variable_name");
lua_gettable(L, -3); //this should get table[variable_name]
variable_name = lua_tonumber(L, -1); // <-- this is your value
...
}
return c;

Use sf::Time over explicit time in System::Update

System::Update accepts an unsigned int that is supposed to be interpreted as microseconds. However, some systems may want to use millseconds or seconds. Passing an sf::Time object instead (which is returned from sf::getElapsedTime anyway) will make the code easier to use and also provide greater flexibility.

IResourceCaches do not implement "Unload" method

The "Unload" method in the IResourceCache interface is not purely virtual and all subsequent derived classes do not implement it currently.

Due to this, the resource caches are never cleared during scene changes.

Simply mark the Unload method as pure virtual, and implement it in all deriving classes to fix it. (There may even be an easier general way to do it within the IResourceCache Unload method)

Entity ID fluctuates in scripts

Every other frame the ID is wrong. Perhaps allow each scriptable behavior to run on its own thread? that way globals won't change as often and only a single load call is needed.

Passing Data between Scenes

Since the scene is instantiated with the creation of a ChangeSceneMessage, at that point the necessary data should be appropriately set.

System Manager does not update Last Time

The time slice (dt) passed to all Systems update methods is the current time rather than the actual time splice because the Last time variable is never updated.

A simple LastTime = CurrentTime will fix it.

IRenderComponent needs virtual destructor

When you use the delete operator on a pointer to IRenderComponent (which you cannot actually have an object of, so it must be pointing to an object of a class that derives from IRenderComponent) the destructors will only be properly called if the IRenderComponent destructor is virtual.

RenderComponent::GetCircle

RenderComponent.h: GetCircle method uses copy constructor. Use pointer or reference (reference preferred).

SpriteComponent

Write a new SpriteComponent that uses the IRenderComponent interface. Make sure to have some general accessors.

Freeze due to Entity placement

When an entity is created on top of another entity, the CollisionSystem tries to resolve the collision. However, if we have a situation like:

xxx
xxx and you try to place an entity on top of the center x and the lease significant
x x overlap is downward, then entity will be pushed down. But this causes another collision with entities on the right and left, and since the collision only occurs between right and left, the entity is continuously pushed back and forth and the entity becomes stuck and the game freezes.

Crashes when entity Lua script doesn't define Behaviors

EntityFactory.cpp: When calling lua_getglobal(L, "Behaviors), check to see that the global was received. Should probably do that for components as well.

More important for behavior because all entities will have components, but not all entities will have behaviors.

Pass strings as std::string const&

In TextComponent and SpriteComponent, pass strings as std::string const&. There's no reason to copy the string, so it's fine to just pass a reference to it.

Calling base class constructor in initializer list with no parameters is redundant

If you have an inheritance chain like: A->B->C (such that C inherits from B inherits from A), then when you instantiate an object of C, A's constructor is called first, then B's, and then C. When calling a super classes constructor in an initializer list, the point is to pass certain parameters because an initializer list is really the only way to do it. When you call the default constructor in an initializer list, it's very redundant.

So in CircleComponent, RectangleComponent, SpriteComponent, and TextComponent, that should be fixed ;).

And if you notice it anywhere else, you can fix it :p

Tags for Entities

Especially useful for lua scripts where it's necessary to know what type of entity that you're dealing with.

I plan to simply implement tags as something that every entity has. By default the tag will be "". The tag should have get and set properties, as well as the ability to pass the tag into the entity constructor.

This will allow tags to define classes of entities (such as "enemy", "friendly", etc) or individual entities (such as "p1score" or "p2score").

Rectangle Component

In the same way that you made the sprite, text, and circle components, make a rectangle component.

Revamp Collision System

The revamp will happen in 4 steps:

  1. Abstract the collision detection loop into a method to make the fix of issue #49 easier, and also the 4th step easier.

  2. fix #49 by checking for collisions when an entity is validated. If it's colliding with something on creation, kill it.

  3. Use a list over a set for moved entities. And when new entities are added, use push_front. The collision resolution should happen in the opposite order that entities were removed.

  4. Implement "bins". Customization of the number and size of partitions should be easy. Each bin should contain a set of IDs (which will be the IDs of the entities that exist in that bin). When an Entity moves, check to see which bin it belongs in, and move it to that bin (if it passed through it's previous bin). If the entity cannot fit in a single bin, it is okay to put it in multiple bins! Have a check that takes a collider component and determines which bin(s) the entity belongs in. So now when an entity moved message flashes, find the bin(s) that it belongs to and insert it into that/those bin(s) and remove it from any bins that it no longer belongs to. Lastly, when checking for collisions, check only against entities from bins that the entity belongs to.

Check arguments and return values for functions bound to lua

Make sure the number of items on the stack is equivalent to the number of parameters. If there's a discrepancy, or any other problem occurs, push an error string onto the stack and remember, the return value of the function bound to lua is the number of return values (ie the number of items on the stack after the function returns).

TextComponent

Write a TextComponent that inherits from the IRenderComponent interface. Again, general accessors.

Particle System

As of now, the Particle System will contain of three main classes:

The Particle, ParticleComponent, and ParticleSystem.

The ParticleComponent and ParticleSystem will work in tandem in a similar fashion to the other Components / Systems you've made thus far. The ParticleComponent will define data that the ParticleSystem will use to instantiate, and show, components.

The ParticleSystem will be much more complicated than other systems, however. At first it may seem that you could treat every particle as an entity and let the systems that are already in place update and render the particles. You could do that, but each Particle Emitter (basically every time you use a ParticleComponent) will typically emit thousands of particles. This will unnecessarily clog up the entity system since particles are short lived. This would put a great deal of unnecessary stress and computation where it does not need to be.

Instead, the ParticleSystem will be responsible for instantiating, updating, rendering, and destroying every particle.

So let's break this down a bit. The ParticleComponent will need:

  1. Position - This will essentially be the "center" of the particle emitter
  2. Radius - This determines how far from the center particles can be created
  3. Max Velocity - This limits both the magnitude and direction of travel
  4. Min Velocity - Same as above.
  5. Life - How long each particle lives
  6. Max Particles - How many particles the system can produce.
  7. An array of particles
  8. A vertex array

Using this information, the ParticleSystem will Instantiate new particles.

Particles should have the following data:

  1. Position - Where it is
  2. Velocity - How fast, and in what direction it is moving
  3. Age - How old is it?
  4. Graphical Representation*
  5. Animation*
  • We want to create an extensible system. So at first we'll create a system that only renders particles as points and animates between colors. However, we should keep in mind that later we may want to use a different graphical representation. We need to design it in such a way that it won't later be a hassle to implement particles with a different graphical representation. With vertex arrays, this is simple.

For now we will only worry about using sf::Point, but later we will extend the implementation to use textured quads to create better effects.

From here, you can more or less use the SFML model as a guide. Just keep in mind that you aren't making a class that inherits from drawable/transformable.

the Update method in the particle system should do everything the update method in the SFML version does as well as the rendering.

If you have any questions, let me know.

Create/Add Entity Messages are REQUESTS

Before placing an entity, check for collisions to see if it CAN be placed there. That way a spiral of death collision detection is avoided. If something is already there, don't place it.

"RenderNode" Component

The RenderNode component will allow entities to have multiple rendering type components. The Component will inherit from IRenderComponent, but the important part of this is creating the RenderNode (I call it that for lack of a better name).

class RenderNode : public sf::Drawable, public sf::Transformable

Inheriting from these two classes will allow a simple call to window.draw(node) to render all drawables held in the node. Also, by providing a transform, all drawables can simply store an "offset" transform (basically define a transform local to the node's transform).

Which means the draw call will look like:

draw(sf::RenderTarget& target, sf::RenderStates states)
{
//This applies the main transform
states.transform _= getTransform();
for(i = 0; i < numDrawables; i++)
{
//In each successive draw call, the drawable will add it's own transform on (if applicable)
target.draw(_drawables[i], states);
}
}

For Lua loading, a recursive table should work.

However, before implementation, consider how useful this will actually be. Is there any real benefit?

Consider all the types of Drawables you might have:

*Sprite
*Shape
*Text
*Particles

So let's say you have a complex entity that has a Sprite, with it's name in text rendered above it, a health bar rendered nearby, and particles rendered all around.

The point of this RenderNode is to make things easier when priority rendering is implemented (have to make sure entities are rendered in the correct order or you get weird effects). The health bar and name should definitely be rendered over any sprites (it would be strange if a character could "walk over" your name or health bar). So adding them into the same priority queue with other sprites is pointless. It's much more efficient to group like things together. The particles probably should be rendered above everything else as well.

While having one central rendering point may seem nice, it may not be in the long run.

It might then be better to have (for this specific example):

RenderSystem (for the representation of the entity)
ParticleSystem(for any effects from the entity)
HealthSystem(renders health of the entity)
NameSystem(renders name of the entity)

where each System adds it's drawables to a rendering queue, and then renders them. Less drawables to sort through each time = faster rendering.

The Particles, Health, and Name are all rendering data about the entity. While the RenderSystem should render things that represent the entity itself.

Thus, in typing this whole spiel out, I have decided against implementing this feature. However, I will at some point implement a better rendering routine that will rearrange the order.

Add binding to delay

Sometimes it may be necessary to delay (sleep/wait) for a certain amount of time.

Refactor Render Component to make it an interface

Now we're going to have multiple rendering sources (various shapes like circles and rectangles, sprites, and text) we want to have a render component interface (IRenderComponent).

All rendering components will inherit from IRenderComponent once it is complete.

IRenderComponent should have a constructor exactly like the one in the current circle RenderComponent. Aside from that, it should have a pure virtual "GetDrawable" method. this way a single render system can be used to render any rendering components.

Once the IRenderComponent is complete, modify the current circle RenderComponent to inherit from IRenderComponent.

Note: You'll have to slightly modify RenderSystem to work with this. All components inheriting from IRenderComponent will have type "Render", so the ValidateEntity method should be fine. However, the Update method will need to call GetComponent with the template parameter of IRenderComponent, and regular parameter of "Render". Then call the pure virtual GetDrawable method mentioned earlier to get the Drawable.

"Pushing" entities double standard

When an entity with a lower ID number (0 compared to 1) moves into an entity with a higher ID, the latter entity is "pushed". However, reverse the situation and the entity will not budge.

RenderComponent Accessors

RenderComponent.h: Instead of only having a GetCircle method, write methods to get and set the color and radius.

IResourceCache should use stored directory.

IResourceCache has a stored directory string that it does not use. Put it in use so that you can call GetTexture("spaceship.png") and it will internally use "resources/spaceship.png".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.