Sign in to follow this  

Is this a good example of an Entity Component System?

This topic is 1094 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Would this be a good example of an Entity Component System?

I am trying to understand how one works, so I made a simple python script to demonstrate what I suppose an
ECS would look like v.s Object Oriented Programming.

# COMPONENT ENTITY SYSTEM

class Human:
    def __init__(self):
        self.height = 2
        self.position = (0,0)
        self.velocity = (0,0)
        self.sprite = '' #get_some_car_image()
        self.moveable = False
        self.rendered = False 

class Renderer:
    def render(self,obj,screen):
        print 'rendering %s to %s' % (obj,screen)
        obj.rendered = True

class Mover:
    def Move(self,obj):
        print 'Moving %s' % (obj)
        obj.moveable = True 
        
man = Human()

renderer = Renderer()
renderer.render(man,'monitor 1')

mover = Mover()
mover.Move(man)

print man.moveable
print man.rendered

Share this post


Link to post
Share on other sites

The entity (Human) should have the components (Renderer and/or Mover), in your example the components do something with the Human and just set some flags in it, and you're able to call "render(someobject)" with any entity, even if the entity is note supposed to be rendered.

 

You should be able to get the "Renderer" component from 2 different Humans and those renderers shuldn't be the same object, components can have a state, so you want each entity to have different instances of a component class.

 

When you want to render all objects with "renderer" component you iterate over the entities, get the Renderer component (it it has any) and call the rendering method with the entity's state needed (if you're rendering you probably want the position of the entity, and the Renderer component should already have the sprite).

 

Also, the Human shouldn't have the state of the components, if you rendered an entity and want to keep a "rendered" flag, put that flag in the component. If an entity must be renderable, put the Sprite in the Render component.

 

EDIT: In this article there's also a "System" that has the methods related to each component (instead of having the methods in the components). This way when the system is supposed to draw, it gets the state of the entity (position) and the state of the Render component (a sprite), and makes the Draw call. Maybe that's the best approach, I've never implemented one of this patterns, I just used them.

Edited by DiegoSLTS

Share this post


Link to post
Share on other sites
In this article there's also a "System"

No wonder why its called Entity Component System EDIT: Ninja'd by sean tongue.png

 

The "pure" ECS approach has 3 parts:

 

  • Entities, which are an ID (integer, long, UUID, whatever you prefer).
  • Components, which are data, and only data (no behavior, no methods, no logic).
  • Systems, which are the logic and manipulate components and entities.

For setting up these, you need a way to track what components each entity has (many ways to do this) and a way for the systems to specify what kind of entities they can process, that means, a way to specify what components a system needs in an entity for processing it (again, many ways to do this), for example, a PhysicsSystem won't process an entity if it doesn't has a "RigidBody" component.

 

That's the general idea, you put components in an entity, and let the systems resolve what entities they process, run all the systems in the game loop.

 

Ideally the systems aren't very coupled, ie, only few of them need to be run in a specific order, and ideally, when a system processes an entity, it doesn't has side effects that go beyond the components of said entity. This allows for running decoupled systems in parallel and for running the entity processing itself of each system in parallel too.

 

I said "ideally" because coming up with such decoupling can be a challenge in itself (just like designing class hierarchies).

 

This is the most "pure" approach I'd say. Of course you can go off tangent by having Entities being more than pure unique IDs, components having some logic, and using inheritance here and there when it merits it. As with everything, nothing is set in stone and no one says doing ONLY components and ONLY systems and ONLY entities will fix all of your problems.

 

EDIT: On the "data oriented" part. The idea is that components are stored contiguously in memory, so that when a system iterates over entities, it can fetch contiguous components from an array and make the best use of CPU cache. How you do this part depends on your game.

 

For example, if you put every kind of component in their own array, and use the Entity ID to index into said arrays, your data essentially becomes a struct of arrays.

 

If a system that processes most of the entities in the game uses 5 or more different types of components at the same time, it might be more worthwhile placing those 5 components into an array of structures instead, so the 5 components are near each other in memory and can be prefetched by the CPU more efficiently.

 

This part depends a lot on how your game is set up (remember we're making a game after all), you might want some components grouped in memory rather than isolated by type, and some others might be better isolated by type rather than grouped.

 

That is something you'd only know when you have all the components and systems set up, and can profile everything. You can't make these kind of decisions as you go (or maybe you can if you really, really know what you're doing). Ideally, the layout in memory should be abstracted in such a way that you can do these sort of changes (grouping some components, isolating others) without having to refactor everything. As always, YMMV.

Edited by TheChubu

Share this post


Link to post
Share on other sites
http://python-utilities.readthedocs.org/en/latest/ebs.html

From the original site

 

Imagine a car game class in traditional OOP, which might look like

class Car:
def __init__(self):
self.color = "red"
self.position = 0, 0
self.velocity = 0, 0
self.sprite = get_some_car_image()
...
def drive(self, timedelta):
self.position[0] = self.velocity[0] * timedelta
self.position[1] = self.velocity[1] * timedelta
...
def stop(self):
self.velocity = 0, 0
...
def render(self, screen):
screen.display(self.sprite)

mycar = new Car()
mycar.color = "green"
mycar.velocity = 10, 0

The car features information stored in attributes (colorposition, ...) and behaviour (application logic, drive()stop() ...).

A component-based approach aims to split and reduce the car to a set of information and external systems providing the application logic.

class Car:
def __init__(self):
self.color = "red"
self.position = 0, 0
self.velocity = 0, 0
self.sprite = get_some_car_image()

class CarMovement:
def drive(self, car, timedelta):
car.position[0] = car.velocity[0] * timedelta
car.position[1] = car.velocity[1] * timedelta
...
def stop(self):
car.velocity = 0, 0

class CarRenderer:
def render(self, car, screen):
screen.display(car.sprite)
Edited by Tutorial Doctor

Share this post


Link to post
Share on other sites
http://python-utilities.readthedocs.org/en/latest/ebs.html

From the original site

 

Imagine a car game class in traditional OOP, which might look like

class Car:
def __init__(self):
self.color = "red"
self.position = 0, 0
self.velocity = 0, 0
self.sprite = get_some_car_image()
...
def drive(self, timedelta):
self.position[0] = self.velocity[0] * timedelta
self.position[1] = self.velocity[1] * timedelta
...
def stop(self):
self.velocity = 0, 0
...
def render(self, screen):
screen.display(self.sprite)

mycar = new Car()
mycar.color = "green"
mycar.velocity = 10, 0

The car features information stored in attributes (colorposition, ...) and behaviour (application logic, drive()stop() ...).

A component-based approach aims to split and reduce the car to a set of information and external systems providing the application logic.

class Car:
def __init__(self):
self.color = "red"
self.position = 0, 0
self.velocity = 0, 0
self.sprite = get_some_car_image()

class CarMovement:
def drive(self, car, timedelta):
car.position[0] = car.velocity[0] * timedelta
car.position[1] = car.velocity[1] * timedelta
...
def stop(self):
car.velocity = 0, 0

class CarRenderer:
def render(self, car, screen):
screen.display(car.sprite)

 

I don't know why they put that example, that's not ECS and it's confusing. Keep reading and you'll find the definition of Entity, Component and System that you'll find everywhere else:

"Component provides information (data bag)

Entity In-application instance that consists of component items

System Application logic for working with Entity items and their component data"

 

That code doesn't follow the definitions:

- The entity (Car) has data and doesn't "have" the components, the Car doesn't even know they exists

- The components (CarMovement, CarRenderer) have no data and define the behaviour

- The system doesn't exists.

Edited by DiegoSLTS

Share this post


Link to post
Share on other sites

Thanks Diego. I am still digging in trying to make sense of it, and I am glad that I checked first, before I went ahead with this approach. I actually do have a method I want to use, but I figure it has already been discovered before, so that is how I came across ECS. A new term I have learned from here, and elsewhere is "Data Driven Design."

 

Question, how would you turn this example into an actual ECS program?

Edited by Tutorial Doctor

Share this post


Link to post
Share on other sites

This topic is 1094 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this