I was bored this morning so I made an ecs (or rather the base for what could become an ecs)
I tried doing this using a very different approach from when I did one in school. Would very much like to hear opinions.
Spoiler:
Is it a decent system? why?
What would you change?
please consider the fact that I quickly threw this together so it doesn't really do anything yet, the components are placeholders and there's some details I'll change later.
I have these components:
Code: Select all
enum ComponentTypes
{
TYPE_TRANSFORM,
TYPE_SPRITE,
TYPE_VELOCITY
};
Code: Select all
struct ComponentTransform
{
float x;
float y;
float angle;
};
Code: Select all
#include "Sprite.h"
struct ComponentSprite
{
int width;
int height;
Sprite sprite;
};
Code: Select all
struct ComponentVelocity
{
float x;
float y;
};
Code: Select all
#pragma once
#include "ComponentTypes.h"
#include "ComponentTransform.h"
#include "ComponentSprite.h"
#include "ComponentVelocity.h"
#include <map>
typedef unsigned int Entity;
class World
{
public:
World();
Entity CreateEntity();
void AddComponent(Entity entity, ComponentTypes type, void* data);
void RemoveComponent(Entity entity, ComponentTypes type);
void Update();
void MovementSystem();
void RenderSystem();
private:
std::map<Entity, ComponentTransform> _transform_components;
std::map<Entity, ComponentSprite> _sprite_components;
std::map<Entity, ComponentVelocity> _velocity_components;
Entity _entities;
};
Code: Select all
#include "World.h"
World::World()
{
_entities = 0;
}
unsigned int World::CreateEntity()
{
return _entities++;
}
void World::AddComponent(Entity entity, ComponentTypes type, void * data)
{
switch (type)
{
case TYPE_TRANSFORM:
{
ComponentTransform* transform = static_cast<ComponentTransform*>(data);
_transform_components[entity] = *transform;
break;
}
case TYPE_SPRITE:
{
ComponentSprite* sprite = static_cast<ComponentSprite*>(data);
_sprite_components[entity] = *sprite;
break;
}
case TYPE_VELOCITY:
{
ComponentVelocity velocity = static_cast<ComponentVelocity*>(data);
_velocity_components[entity] = *velocity;
break;
}
default:
//invalid
break;
}
}
void World::RemoveComponent(Entity entity, ComponentTypes type)
{
switch (type)
{
case TYPE_SPRITE:
_sprite_components.erase(entity);
break;
case TYPE_TRANSFORM:
_transform_components.erase(entity);
break;
case TYPE_VELOCITY:
_velocity_components.erase(entity);
break;
default:
break;
}
}
void World::Update()
{
MovementSystem();
RenderSystem();
}
void World::MovementSystem()
{
std::map<Entity, ComponentVelocity>::iterator it = _velocity_components.begin();
for (; it != _velocity_components.end(); ++it)
{
ComponentVelocity& velocity = it->second;
ComponentTransform& transform = _transform_components[it->first];
transform.x += velocity.x;
transform.y += velocity.y;
}
}
void World::RenderSystem()
{
std::map<Entity, ComponentSprite>::iterator it = _sprite_components.begin();
for (; it != _sprite_components.end(); ++it)
{
ComponentSprite& sprite = it->second;
sprite.sprite.Render();
}
}
Creating an entity in game.cpp would look something like this:
Code: Select all
unsigned int Player = world.CreateEntity();
ComponentTransform transform;
transform.x = 100.0f;
transform.y = 100.0f;
ComponentVelocity velocity;
velocity.x = 100.0f;
velocity.y = 100.0f;
world.AddComponent(Player, TYPE_TRANSFORM, &transform);
world.AddComponent(Player, TYPE_VELOCITY, &velocity);