Jump to content

  • Log In with Google      Sign In   
  • Create Account

Krankles

Member Since 25 Jul 2012
Offline Last Active May 03 2014 08:13 PM

Posts I've Made

In Topic: Need Help Implementing Entity Component Systems

03 February 2014 - 01:53 PM

Thanks for the descriptive answers guys! I think I got it now.


In Topic: Need Help Implementing Entity Component Systems

03 February 2014 - 06:33 AM

That's not really how you should be doing it.  Really, it all needs to be generic and you don't actually call the system's functions.  Rather, you have a ECS World, and you create Systems, and you designate what type of component(s) that system should deal with, and you create Entities, and assign Components to them.

 

Then, in your update function, you simply call EcsWorld->Update(), and it will iterate through all your entities and components through all the systems that operate on certain components.

 

Here's an example from my Escape System (and here's a brief explanation of the ECS)

 

Define an Input Component and give it to a entity:

// in a header file
class TInput : public Esc::TComponent
{
public:
    TInput() : Esc::TComponent("Input") {}
 
};
...
// in a .cpp file
Esc::TEntityPtr Entity1 = pWorld->CreateEntity();
TInput* inputComp(new TInput());
pWorld->AddComponent(Entity1, inputComp);
//Assume there's also a Physical Component, that defines the entity is a physical object
pWorld->AddComponent(Entity1, physicalComp);
 

()

 

Now create a system that acts upon an entity that has both a Physical Object component and an Input component (see the Initialize() function):

// in a header file
class TInputSystem : public Esc::TSystem
{
public:
    TInputSystem(sf::RenderWindow *pApp);
    ~TInputSystem();
 
    void Update(Esc::TEntityPtr entity, uint32_t tickDelta);
    void Initialize();
 
private:
    sf::RenderWindow *mpApp;
 
    uint32_t mCenterY;
    uint32_t mCenterX;
 
};
...
 
// in a .cpp file
InputSystem = new TInputSystem(app);
pWorld->AddSystem(InputSystem);
 
...
 
TInputSystem::TInputSystem(sf::RenderWindow *pApp) :
  Esc::TSystem(), mpApp(pApp)
{
    ...
}
TInputSystem::~TInputSystem()
{
 
}
 
void TInputSystem::Update(Esc::TEntityPtr entity, uint32_t tickDelta)
{
    TPhysicalObject *physicalObject =
      static_cast<TPhysicalObject*>(entity->GetComponent("PhysicalObject"));
    // Do something with entitiy based on the input
...
 
}
 
void TInputSystem::Initialize()
{
    // Set which components we want to deal with
    Esc::TSystem::HandleComponent("PhysicalObject", true);
    Esc::TSystem::HandleComponent("Input", true);
}
 

Now, in your game loop, you'd simply call pWorld->Update(), and it would go through all the systems (in this case the InputSystem), and it would call InputSystem-> with all the entities that have both a PhysicalObject and an Input Component (probably only 1 entity).

 

You probably need a better understanding of C++ before you can get a real good grasp on all this.

 

Good luck.

 

I see! This makes a lot of sense, thanks. And yeah, I should probably learn more of C++ before I start doing this. However, I have a quick question. What if you wanted separate functionality for a specific entity that operates within the same system? Should you just create a new system entirely? Or possibly check if it's a specific entity and run that code inside the system? For example, I have a JumpSystem and the player could double jump but the enemy can't, should you create a new DoubleJumpSystem? Or should you just check within the JumpSystem for the player entity? Or another example to possibly clear the question up, what if I have an AnimationSystem and the 2 different entities animate differently, should it just check for a specific entity or create a new system?

 

Thank you.


In Topic: Need Help Implementing Entity Component Systems

02 February 2014 - 07:11 PM

Sorry for the triple post! But, ignore what I said earlier, I was being stupid. I think I got a good system going. I need to know if this is how a decent ECS should work though, or even if this is a good basis. I took out the Render component and replaced it with Velocity and Position instead, as I find it much easier to start out with.

#include "Entity.h"
#include "PositionComponent.h"
#include "VelocityComponent.h"
#include "MovementSystem.h"
 
int main(int argc, char const* argv[])
{
    MovementSystem movementSystem;
 
    Entity player;
    player.AddComponent(new PositionComponent(2, 2));
    player.AddComponent(new VelocityComponent(5, 5));
 
    for (int i = 0; i < 10; i++) {
        movementSystem.ProcessEntity(&player);
    }
 
    return 0;
}

That's basically how everything works, I create a movement system, entity, add components to the entity and then use the system to process my entity. I don't know whether or not this is how ECS works or not, but it seems right to me.

 

MovementSystem.h

#ifndef MOVEMENT_SYSTEM_H
#define MOVEMENT_SYSTEM_H
 
#include "EntitySystem.h"
#include <vector>
 
class VelocityComponent;
class PositionComponent;
 
class MovementSystem : public EntitySystem
{
    public:
        MovementSystem();
        ~MovementSystem();
 
        void ProcessEntity(Entity* entity);
 
    private:
        VelocityComponent* velocityComponent;
        PositionComponent* positionComponent;
};
 
#endif

MovementSystem.cpp

#include <iostream>
#include "Entity.h"
#include "MovementSystem.h"
#include "PositionComponent.h"
#include "VelocityComponent.h"
 
MovementSystem::MovementSystem()
{
 
}
 
MovementSystem::~MovementSystem()
{
 
}
 
void MovementSystem::ProcessEntity(Entity* entity)
{
    positionComponent = dynamic_cast<PositionComponent *>(entity->GetComponent("position"));
    velocityComponent = dynamic_cast<VelocityComponent *>(entity->GetComponent("velocity"));
 
    positionComponent->SetX(positionComponent->GetX() + velocityComponent->GetVelocityX());
    positionComponent->SetY(positionComponent->GetY() + velocityComponent->GetVelocityY());
    std::cout << "Player X: " <<  positionComponent->GetX() << std::endl;
}

That's how my movement system works, but I was wondering if there's anything I could improve my system on?


In Topic: Need Help Implementing Entity Component Systems

02 February 2014 - 08:05 AM

So I've been researching even more, and I am confused a bit now. Should the System know how to do a function? Or should the Component know how to do a function? For example, JumpComponent and JumpSystem, should the System know how to Jump? Or should the Component know how to jump? I'm confused because I've read that the component should just contain the data, etc, and the system should handle the components. However, in some people's implementations, I've seen them having the component having the data and knowing how to do something, and the system should just have a list of components, and make them interact with each other.

 

Also, I've been thinking, for my RenderComponent and RenderSystem -- to make it work -- should I have the Render function inside my RenderComponent, and then have the RenderSystem loop through all of the RenderComponents and call the respective Render function?

 

Not only that, but I was also thinking that for my problem earlier, I could possibly fix the problem by using my newly created RenderSystem by passing in the component pointer to the RenderSystem component list and then be able to access the member named "image".

 

Lastly, I was wondering, why do people in their Entity class don't include the component header? I see them just doing "Class Component;" and that's it. (Sorry for the noob questions, I didn't fully learn C++, I learned the basics, learned some SDL and went on creating basic games. I also can't test this ideas right now because I'm busy with other things currently.)

 

Thanks.


In Topic: Need Help Implementing Entity Component Systems

31 January 2014 - 08:05 PM

Also, a big hierarchy of classes (valuing inheritance over composition) is not traditional OOP; it's a complete abuse of OOP!
OO teaches that you should prefer composition over inheritance. I'd suggest simply practicing writing OO code using composition first, to get used to how composition based code is structured, before trying to create your own library that's designed to make composition easier somehow.

 

My bad, I guess I got too used to it!

 

Anyways, thanks guys, I started my own attempt at ECS, but I'm having troubles connecting things together. This is what I have so far.

 

Entity.h

#ifndef ENTITY_H
#define ENTITY_H
 
#include <vector>
#include <string>
#include "Component.h"
 
class Entity {
    public:
        Entity();
        ~Entity();
 
        void AddComponent(Component *component);
        Component* GetComponent(std::string name);
        void Update();
 
    private:
        std::vector<Component*> components;
};
 
#endif
 
Entity.cpp
#include "Entity.h"
 
Entity::Entity()
{
 
}
 
Entity::~Entity()
{
 
}
 
void Entity::AddComponent(Component *component)
{
    components.push_back(component);
}
 
Component* Entity::GetComponent(std::string name)
{
    for (unsigned int i = 0; i < components.size(); i++) {
        if (name.compare(components[i]->name) == 0)
            return components[i];
    }
}
 
void Entity::Update()
{
    for (unsigned int i = 0; i < components.size(); i++) {
        components[i]->Update();
    }
}
 
BaseSystem.h
#ifndef BASE_SYSTEM_H
#define BASE_SYSTEM_H
 
class BaseSystem
{
    public:
        BaseSystem();
        virtual ~BaseSystem();
};
 
#endif
 
Component.h
#ifndef COMPONENT_H
#define COMPONENT_H
 
#include <string>
 
class Component
{
    public:
        Component();
        virtual ~Component();
 
        std::string name;
        virtual void Update();
};
 
#endif
 
RenderSystem.h
#ifndef RENDER_SYSTEM_H
#define RENDER_SYSTEM_H
 
#include <SDL2/SDL.h>
 
class RenderSystem : public BaseSystem {
    public:
        void Render(SDL_Renderer* renderer, SDL_Texture* image);
};
 
#endif
 
RenderSystem.cpp
#include "RenderSystem.h"
 
void RenderSystem::Render(SDL_Renderer* renderer, SDL_Texture* image)
{
    SDL_RenderCopy(renderer, image, NULL, NULL);
}
 
RenderComponent.h
#ifndef RENDER_COMPONENT_H
#define RENDER_COMPONENT_H

#include "Component.h"
#include <SDL2/SDL.h>

class RenderComponent : public Component {
    public:
        RenderComponent();
        ~RenderComponent();
        SDL_Texture* image;
};

#endif
 
RenderComponent.cpp
#include "RenderComponent.h"

RenderComponent::RenderComponent(){
    name = "render";
}

 

So that's all I have right now, but I don't know if I'm even doing this right or not. Right now, I don't want to complicate anything, and just want a simple entity (background, player, what-have-you) to draw. Once I have that down, I believe I can implement the rest.

 

I need some help being guided in the right direction, I know my code might look like utter crap right now, but I'm just learning, so please bear with me. When I try creating an entity in my test program, I tried doing this:

Entity background;
background.AddComponent(new RenderComponent());
SDL_Surface *tmp_image = NULL;
tmp_image = IMG_Load("gfx/background.png");
background.GetComponent("render")->image = SDL_CreateTextureFromSurface(renderer, tmp_image);

But it says that "class Component" has no member named "image". Which is obvious, since it's not declared in the class Component, but in RenderComponent. How do I solve this? Or should I NOT be doing this?

 

Thanks.

 

EDIT: Basically what I'm asking is, is that how you correctly add a component? If so, then when I get my component, I want to be able to manipulate it, but it doesn't let me due to the class Component having no member named image. The list of components is an array of Components, which means I can't access the image variable. Also, how are systems supposed to work. I've been googling around and it's somewhat confusing. I feel like I'm doing this completely wrong.


PARTNERS