Entity Systems are the future of MMOG development – Part 2

Part 2 – What is an Entity System?

(Part 1 is here)

Sadly, there’s some disagreement about what exactly an Entity System (ES) is. For some people, it’s the same as a Component System (CS) and even Component-Oriented Programming (COP). For others, it means something substantially different. To keep things clear, I’m only going to talk about Entity Systems, which IMHO are a particular subset of COP. Personally, I think Component System is probably a more accurate name given the term COP, but then COP is improperly named and is so confusing that I find if you call these things Component Systems they miss the point entirely. The best would be Aspect Systems, but then AOP has already taken ownership of the Aspect word.

An entity system is simply a part of your program that uses a particular way of breaking up the logic and variables of your program into source code.

For the most part, it does this using the Component Oriented Programming paradigm instead of the OOP paradigm – but there’s subtleties that we’ll go into later.

We refer to an entity “system” instead of entity “programming” because ES’s are usually found embedded in a larger, OOP, program. They are used to solve a subset of problems that OOP is poor at dealing with.

So, it is generally a replacement for Object Oriented Programming. The two are mutually exclusive: you have to choose one or the other (although any complex program may have multiple levels of abstraction, and you could mix and match OOP and COP/ES at different layers, any given layer is going to be one or the other (or, of course, any other alternative way of structuring your program).

Common misconception #1 – Entity Systems are part of OOP
Common misconception #2 – Entity == Class, Component == Object

Where OOP has Classes and Objects, an ES has Entities and Components – but it is very important to note that an Entity is NOT equivalent to a class, and a Component is NOT equivalent to an Object, although superficially they seem to share some characteristics. If you think of Entities/Component’s in OOP terms, you will never understand the ES, and you will screw up any attempt to program with it.

The whole point of ES’s using a different programming *paradigm* is that this means there CAN NEVER BE a direct equivalent between Classes and anything, or between Objects and anything – if there were, it would actually be the same paradigm, and just be a variant of OOP. It’s not. It’s fundamentally different and incompatible.

What’s an Entity?

An Entity System is so named because Entities are the fundamental conceptual building block of your system, with each entity representing a different concrete in-game object. For every discernible “thing” in your game-world, you have one Entity. Entities have no data and no methods.

In terms of number of instances at runtime, they are like Objects from OOP (if you have 100 identical tanks, you have 100 Entities, not 1).

However, in terms of behaviour, they are like classes (Entities indirectly define all the behaviour of the in-game object – we’ll see how in a second).

So, entities on their own are pretty much entirely useless – they are coarse-grained, and they serve to do little more than to tag every coarse gameobject as a separate item. This is where Components come in.

What’s a Component?

Every in-game item has multiple facets, or aspects, that explain what it is and how it interacts with the world. A bicycle, for instance, is:

  • Made of metal
  • Can be used by a human
  • A means of transportation
  • Something that can be bought and sold
  • A popular birthday present
  • Man-made

At this point, please note: OOP does not have this concept of multiple aspects; it hard-codes all the aspects into one glob, and declares that the set of behaviours and values of data to be the single-aspected Class of an Object. C++’s Multiple inheritance and Java’s Interfaces can get you a small part of the way towards the aspects of an ES, but they quickly collapse under the strain in fundamental ways that cannot be fixed within OOP.

The way that an Entity for an item represents the different aspects of the item is to have one Component for each aspect. The Component does one really important thing:

  • Labels the Entity as possessing this particular aspect

It may do several other things, depending upon your implementation and the design of your ES. However, with an ES, this is the most important, because this is the basis of all method execution and processing.

What’s a System? (or subsystem)

An ES goes further than OOP in how it splits up the universe of code and data. In OOP, you make everything into Objects. With an ES, you have two different things that you split code and data into: the first is “Entity + Components”, and the second is “Systems”.

This is the source of a lot of the value of an ES. OOP is very good at implementing the part of any program that has lots of data floating around and lots of methods floating around which need to be executed only on a small, instanced, subset of the data in the program. OOP is very poor at implementing the “global” parts of a program, which have to operate “on everything”, or have to be invoked “from everywhere”. An Es solves this by explicitly dealing with all the global stuff using Systems, which are outside the realm of Entity/Component.

Each System runs continuously (as though each System had it’s own private thread) and performs global actions on every Entity that possesses a Component of the same aspect as that System.

There is a one to one relationship between Systems and AVAILABLE aspects (i.e. types of Component). A System essentially provides the method-implementation for Components of a given aspect, but it does it back-to-front compared to OOP. OOP style would be for each Component to have zero or more methods, that some external thing has to invoke at some point. ES style is for each Component to have no methods but instead for the continuously running system to run it’s own internal methods against different Components one at a time.

Typical Systems in a game would be: Rendering System, Animation System, Input System, etc.

The Rendering system wakes up every 16 milliseconds, renders every Entity that has the Renderable Component, and then goes back to sleep.

The Animation system constantly looks out for anything that would trigger a new animation, or cause an existing animation to change (e.g. player changes direction mid-step), and updates the data of each affected Entity (of course, only those that actually have the Animatable Component, i.e. are animations).

The Input system polls the gamepad, mouse, etc, and changes the state of whichever Entities with the Inputable Component are currently marked as being controlled by the player.

In tradtional OOP, if you have 100 units on a battlefield, and each is represented by an object, then you theoretically have 100 copies of each method that can be invoked on a unit. In practice, most OOP languages use runtime and compiler optimizations to share those methods behind the scenes and avoid wasting memory – although scripting languages for instance often don’t do any sharing, allowing all the methods to be independently changed on each and every instance.

By contrast, in an ES, if you have 100 units on a battlefield, each represented by an Entity, then you have zero copies of each method that can be invoked on a unit – because Entities do not contain methods. Nor do Components contain methods. Instead, you have an external system for each aspect, and that external system contains all the methods that can be invoked on any Entity that possess the Component that marks it as being compatible with this system.

That’s not an Entity System!

Well … at least, that’s what *most* people I’ve worked with consider to be an Entity System. But even within a single project, I’ve found multiple different ideas of what an ES is, some of which are compatible, others of which are incompatible. Here are some of the other ideas I’ve come across that people thought were ES’s.

Alternative definitions of entity systems:

1. An ES provides a different model of class-inheritance to OOP, especially w.r.t inheritance of fields. For any given entity-class you declare which aspects that class possesses, and the actual class is looked-up at runtime by piecing together all the different aspects.

2. The same as 1., but taken literally for methods as well as fields, i.e. this provides an interesting way to mix-n-match inheritance of functions/methods. So long as methods are attached to the fields upon which they operate, and/or a “pre-requisite” system is implemented such that “having aspect X automatically causes you to also have aspect Y”, then this works quite smoothly. NB: this is implementing “modular objects”: the “aspects” are complete objects from the standard theory of OOP.

3. A variant on 1. or 2. where the aspect data is pre-compiled into a large number of OOP classes at compile time, so that at runtime you are just running “normal” classes, without any lookup cost of the dynamic “I’ve got an entity E which claims to have aspect X; just hold on a sec while I build a function table to find out what the heck to do now someone just tried to invoke function Z…”

4. A way of compiling standard OOP classes into runtime-data (note: disassociating them from their OOP-ness) specifically so that you can treat them as streamed data instead of chunked binary + data. The main value of this is to play nicely with hardware that has tiny tiny amounts of memory available in the code cache and/or very very slow access to fetch extra code, but has vast bandwidth to stream SEQUENTIAL data through the CPU. PlayStation consoles especially like this approach, as opposed to the typical PC approaches. Note that in this case, the idea is that the game-programmers and game-designers are UNAWARE that there’s an entity system – it’s a runtime/compile time performance optimization, not a design-feature.

5. A system design that revolves around excessive use of the Observer pattern, but does so using standard OOP techniques. I mention this because it’s a common (ab)use of the concepts of ES’s, but lacks much of the advantages. For what it’s worth … that’s the situation I was in when I first discovered ES’s. So, personally, I really don’t count these as ES’s. These are not an ES, but an: “OMG, I need an ES!”, but many people persist in thinking (and claiming) they’re a true ES.

NB: IMHO this is one of those “you really shouldn’t do this” classes of Entity System usage. Why? Because you end up just creating MASSIVE OOP classes with tonnes of independent implemented Observer methods tacked onto them. That’s fine as a general approach, it buys you something whilst remaining ENTIRELY OOP, but it also loses most of what ES’s have to offer, especially in the realm of flexibility and compound inheritance.

Who cares about ES’s and why? (where did they invent these from?)

1. Coders who are used to writing a graphics/rendering engine and trying to keep it isolated / separate from the rest of the computer game. They learnt that they can write the entire graphics engine using only PARTIAL information (a couple of aspects – no more than 2 or 3) of every OOP object that exists in the game-universe. They need to use: Renderable (do I have to paint it to the screen every frame? [it will have all the methods necessary to do that painting generically]), Updateable (does it potentially change in response to one or more game-loop-ticks? [animations are a great example of this – their internal state changes independently of how many times they’re rendered]),

2. Multi-threaded coders who are looking at the concept of aspects per se (i.e. Renderable as opposed to Updateable) to allow for coarse-grained multi-threading: you are allowed one thread per aspect, and this is guaranteed safe simply because the aspects are – by definition! – independent from one another. Since a typical ES will have a dozen or more aspects, you’ve just bought yourself reasonably effective performance scaling of up to 12 separate CPU cores, for free.

Also … going to the next level of difficulty and performance improvement, they’re looking for the largest possible individual (literally: things that “cannot be divided”) things that can be made the atomic level of multi-threading. The default position is that only manually-hard-coded atomic operations count, and OOP objects certainly are full of all sorts of multi-threading individual pieces so are far too coarse, but maybe components within entities are small enough to be the unit of atomicity.

3. Game designers who want to enable “everything to become anything”.

Do Cameras shoot people?

Do Bullets accept input from the player?

No?

Well … have you played Unreal Tournament? If you have but didn’t answer yes to the earlier questions then you need to find someone to show you a Redeemer being used in Alternate Fire mode (hint: you get to manually “fly by wire” the rocket from a first-person view inside the warhead itself).

ES’s allow everything and anything to be used as anything and everything, interchangeably, with no re-coding. That’s the beauty for designers – all the artifical constraints on design that were previously enforced by coders having to, you know, place SOME constraints just to write their own damn code and have it be reasonably performant and bug-free are suddenly lifted.

It’s true – you really CAN have strongly-typed safe code and yet have total freedom to pass any object to any method; at least, you can with Entity Systems.

4. Coders who go a bit overboard with the Observer pattern.

If you’re unsure about this one, and have used Observers a lot, ask yourself this: have you ever had that problem with Observers where you found that “just one base class isn’t enough”? i.e. one base class that implemented a handful of different Observers worked great, but as your system / game / application expanded you found you needed more variety in that base class, you needed multiple different versions, and you needed *every possible combination* of those different versions, because base-classes cannot/will not “stack” nicely on top of each other.

Thought for the day

Programming *well* with Entity Systems is very close to programming with a Relational Database. It would not be unreasonable to call ES’s a form of “Relation Oriented Programming”.

This needs a followup post, but you might want to think about that :) both in terms of how the above statement could be true (hint: think about what most of the code you write for each System is going to look like, and what exactly it is doing), and also in terms of what the knock-on effects of this are if it is true.

Bear in mind that no-one’s yet managed to do OOP fast with Relations; the excessively high conversion cost between RDBMS and OOP – both at coding-time and at runtime – is still one of the biggest single development problems with writing an MMO.

Did this post help you?

Support me on Patreon, writing about Entity Systems and sharing tech demos and code examples

NEXT: Part 3

75 thoughts on “Entity Systems are the future of MMOG development – Part 2

  1. Pingback: T=Machine » Entity Systems are the future of MMOG development - Part 1

  2. Fiordean Dacian

    Thanks, now that’s cool. We were waiting for this 2nd post; I’ll have to print that out and think about it, as you challenge us with that “Thought for the day”. Be right back with an opinion here, hope so…

  3. Juha Lindfors

    “The best would be Aspect Systems, but then AOP has already taken ownership of the Aspect word.”

    So what does the ES bring that cannot be accomplished with an AOP framework?

  4. adam Post author

    Juha – that’s what I hope to explain in the next post :). I tend to think of AOP and ES as being different implementations of the same core ideas, although I’ve not yet properly checked how accurate that is.

    Just to be clear – “cannot be accomplished” is not literally what you mean? – everything can be accomplished using any of these programming paradigms, it’s just that some things are much easier with one that with another.

  5. Juha Lindfors

    “Juha – that’s what I hope to explain in the next post :)”

    Ok, looking forward to it.

    “Just to be clear – “cannot be accomplished” is not literally what you mean?”

    Well, no. It’s like you said — just curious to see what ES would bring to the table that would take significant time investment to develop with an AOP framework.

    So far it sounds like the components behave similarly to AOP advice or introductions. That makes sense to me since I do agree that the static inheritance hierarchy imposed by some programming languages (C++, Java, C# family) is too restrictive for this type of implementation.

    The systems part to me sounds like a variation of a flyweight pattern, so this is a separate concern (memory consumption vs. adding dynamic behavior) on the description. Mixing of the two concerns is probably what makes the explanation of an ES sound more muddled than is necessary.

    Anyway, even though I don’t quite agree with everything you’ve described so far, it’s a good discussion to point out the design requirements that need to be addressed in order to steer away from the obvious mistakes from the beginning of the design/implementation (like relying on static inheritance tree, considering the number of objects and amount of object state in the system).

  6. adam Post author

    Yep, there’s a lot of the flyweight pattern in there. It’s what you then do on top of that that I find particularly interesting – treating everything as data, to the extent of e.g. using a QL (such as SQL) to select which of the possible flyweight instances to load and send as input to methods you want to execute.

  7. Raine

    I find this a very interesting approach and I’m looking forward to read the next articles. Keep them coming! :)

  8. Daniel

    Hi adam,

    Thanks for taking the time to write these articles, they’re a really interesting read. I am however a little confused about a couple of things. I’m sure it’s down to me just not grasping the concept correctly. I understand how the component based method of constructing your entities can make for a much more maintainable, dynamic and data driven system as opposed as opposed to the inheritance based approach. The issue I’m having is understanding exactly how and where you’d create specific implementations of a particular aspect. Say for example you wanted to construct a ‘Tank’ entity to use your example. My tank would obviously have a Movable aspect or something similar. If I was using the inheritance based approach, I would inherit from a generic ‘Movable’ base class and implement the movement behaviour specific to my tank object by overriding base class methods relating to movement. I’m finding it hard to grasp exactly where this specific behaviour would be defined in an ES, especially after these two statements:-

    ‘…Entities do not contain methods. Nor do Components contain methods.’
    ‘Entities have no data and no methods.’

    ‘Systems’ are obviously for generic management of all entities that have a particular aspect, so where would this specific functionality belong?

    I’m sure my mis-understanding is down to me just grasping something incorrectly or not being able to free my mind of traditional OOP thinking, but it would be great if you could enlighten me!

  9. Matthieu

    Few people care about this stuff, but I find it very interesting. Especially since I’ve worked with:
    1- an engine where I ran into the “Many Base Classes” issue, with no systems
    2- an engine that went less inheritance-crazy but where the Entity has a Sync point where data is exchanged, with some systems
    3- an engine where the Entity has Components that have functions, which no systems.

    I’ve been making an engine with an entity design similar to what you describe. I found your post while wondering how many systems I should have apart from Rendering, Animation and Physics, which I already have… especially at the “game layer”…I would like to hear what you have to say about this!!

    Perhaps take the example of how you would design:
    – Teleporter
    – GravityVolume
    – HurtVolume

    How many aspects would you create to support them, and how many systems would be made to handle their functionality :]

  10. Arni Arent

    “Each System runs continuously (as though each System had it’s own private thread) and performs global actions on every Entity that possesses a Component of the same aspect as that System.”

    Are you suggesting that the Systems are run parallel?
    This leads to the question of thread synchronization.

    How do you solve dependencies between components? When one type of component (or System) needs to perform a action or retrieve some data from another component (via another System I assume)?
    E.g. Movement depends on Health, because if health is < 25% then the entity needs to move more slowly.

    So, if you could answer these questions about:
    – Parallel execution of Systems and their components (and data integrity)
    – Dependencies between components, especially in a multithreaded system.

    Thank you!

  11. Jmp97

    Thanks for the article! Very good read.
    I would echo the request of Arni. Those would be interesting questions to cover.

  12. Haversack

    Very interesting read. In terms of versatility (if I actually understand this stuff) you couldn’t beat Entity systems.

    Ive been thinking of this in terms of the stored data server side (recent experiences with SQL to blame) since it seems that an “Entity” would be like the database and the “Component” would be like the table. The records within the table would be the stored data you would associate with components such as life or in the case of a position component with x,y, and z. This could also be done with the table as the Entity and the records the Components I think (would actually have to try it).

    That being said the Systems would be the “Observers” and which as stated above should be kept to a minimum. Im guessing you would have Systems to report changes to the entities’ components. Observers arent really needed because you would never have to tell something to update since the data in the component would be updated already. Thusly when any System using the component calls data or updates its own runtime it would do whatever is triggered by that system, ie. life or position changes. In other words the data just is. It doesn’t need a “changePos” method the position would have already been changed.

    I dont see a way around not having at least one observer. In my mind it would need at least one Observer to control client:server interaction and at least update the data in the correct component. The server reports the entities with components to the client which then the client uses the data to perhaps render everything you would have in one zone(PCs, NPCs, Terrain, whatnot). the component would just report which meshes and textures you needed to render as references which would be stored on the client.

    If all of this is correct it would be obscenely easy to update pretty much anything you wanted by just changing the entry in your “Database” or component to the desired material. In the case of updating graphics, since its all stored client side, you would have to push out a patch or expansion to do so.

    I can see where there would be lots of room for optimization, finding the right amount of data to pass between client and server would be troubling.

    After reading this article ive been working on applying this system to one of my projects.

  13. herzmeister der welten

    I don’t think this is a non OOP style of doing things. It’s merely another “resolution” of looking on stuff.

    Rather than mapping classes directly to game entities with hard-implementing all of their behavior, we now introduce one more abstract layer inbetween to allow for more dynamic mapping of behaviors.

    From an OOP perspective, that’s just as fine to describe the problem that way. Rather than concrete bicycle, skater etc objects we now have entity, component or behavior objects, but they’re still objects.

  14. adam Post author

    You’re no longer using OOP to model/represent the system, hence you can no longer say that you are implementing th system in OOP.

    Rather, you are implementing a different language/paradigm within OOP, and that secondary paradigm is doing allthe work of modelling/implementing the actual program.

    The value of this approach is that it allows us to effectively do some stuf like : *cleanly* writing a particular kind of functional program inside a traditional OOP program

  15. Arni Arent

    I have a few questions:

    1. Do all component types need to have a System?

    2. Do Systems contain a collection of their components?
    E.g. renderingSystem.addRenderingComponent(..) ?

    3. I have a entity, such as a tank, that has translation information such as (x,y,z,rotatation). Do I need a Component and a System for this data? E.g. TranslationComponent/System.

    4. And clearly, this tank needs to move, so I guess I need a MovementComponent and some sorts of MovementSystem. Does the MovementSystem (when it performs actions on the MovementComponent) have to look up the TranslationComponent of the same entity in order to update it’s translation?

  16. adam Post author

    @Arni

    1. Do all component types need to have a System?

    Generally, you only add a new component type because you’ve added a new system that needs to store/attach data to the entities.

    So … I guess you could have components with no system, but it’s going to be unusual / unlikely. Where are you going to put the code that creates and manages that data? :)

    2. Do Systems contain a collection of their components?
    E.g. renderingSystem.addRenderingComponent(..) ?

    This is merely an implementation detail – you can do it that way if you want.

    Normally, I have a centralized manager object that kept track of which components were attached to which entities.

    3. I have a entity, such as a tank, that has translation information such as (x,y,z,rotatation). Do I need a Component and a System for this data? E.g. TranslationComponent/System.

    Yes, you MUST have a component for ANY data you’re using.

    But … NO, you do not have what you think you have. :)

    There is no such thing as “a tank, that has translation information”. Unless a system CREATED that information, it doesn’t exist – you’re jumping ahead of yourself, just because you “expect” a tank to have translation information. Don’t do that.

    See next point…

    4. And clearly, this tank needs to move, so I guess I need a MovementComponent and some sorts of MovementSystem. Does the MovementSystem (when it performs actions on the MovementComponent) have to look up the TranslationComponent of the same entity in order to update it’s translation?

    Ah, so *now* you have some REAL information – it’s “the info created/edited/stored by the Movement System”.

    Does that make sense? (sorry, very breif responses)

  17. Arni Arent

    Thank you for your replies adam.

    I’m still a bit confused.

    Here’s how I’m thinking this:
    Since we’re discussing about a “tank” we can dissect what aspects this entity has. It can move, it can shoot, it can look for targets at a given interval, it has a limited health, it can be damaged by other bullets.
    Now, the reason why I dissect the “tank” in this fashion is so that I can reuse some of these components in other entities, such as “jeep” or “soldier”.

    How would you go about dissecting all different aspects for a typical game unit and defining systems and components for it?

  18. adam Post author

    @Arni

    You’re trying to be too clever, and add stuff to your program that you GUESS you will need later, even though you have no proof yet. You’re so sure of this GUESS that you’re claiming you “know” it; but, technically, it’s still just a guess.

    Don’t guess. Only write the stuff you need.

    You are stuck in OOP thinking: “I must have 100% knowledge of my app before I start writing it. If I don’t, and change my mind later, it will cost me thousands of wasted hours.”

    The truth is: there’s NO NEED to plan your whole app in advance – that’s an annoying side-effect of certain OOP styles. ES’s encourage you to explore your app as you go (which is how 99% of all computer games are written anyway – this is why OOP sucks so badly for game development).

    For example:

    GOOD: “It can move, it can shoot, it can look for”

    These are things “it can do” – i.e. they require source code, i.e. they require being implemented as Systems.

    Attempting to do that will FORCE you to create a Component for each system, and place appropriate data in that component.

    BAD: “it has a limited health, it can be damaged by other bullets”

    These are not things “it can do”. Hence, they don’t matter. Forget about them.

    You will get to a point when you want to add the ability to “fire a bullet”, and then “bullet damages anything it hits” – at that point, you’ll invent a “Damage System”. You don’t actually know what variables / data you will need to use to represent health UNTIL you get to writing that System.

    So … don’t try to jump ahead of yourself and write a Component for a System that you haven’t planned yet :). Concentrate on “what can X do, actively?”. Eventually, you’ll cover everything in the game this way.

  19. Pingback: T=Machine » Entity Systems are the future of MMOG development – Part 1

  20. Ed

    Hey nice blogs here, first time I’ve been to this place so bare with me. I’m a very noob hobby programmer (in delphi) and I wanted to ask a question about Entities and systems;

    Ie in OOP you have procedures and functions, you write the ‘tools’ you need to do certain things with these (I tend to only go into a function if I use that ‘tool’ more than once, a text parsing function for example)

    In my very limited view, these entities and systems seem like creating an iterating record of data, which also has its own functions based inside timer control (or other threaded system) Hence the timer control runs by itself, does everything it needs to do and while this is happening the rest of the game/project continues with other things. These systems then are maybe just a lot of threaded micro-programs?

    Would this be a fairly close analogy?

  21. Jonathan Hartley

    Hey Adam, thanks very much for this series. I’m clearly late to the party, just working my way through.

    I’m not a game developer, but I am a developer, and I recognise this sort of pattern from other areas (eg. GIS projects use it to model different types of equipment that participate in electrical disribution networks, or water pipes, etc.)

    I don’t want to be contradictory, but Interestingly I wouldn’t agree that it isn’t OOP. To me it seems just to be an acknowledgement that one relatively simple class model (eg. class Transformer, class Cable, etc) doesn’t cut it, so you’ve moved to a more sophisticated one, with a single extra layer of indirection in it. This sort of indirection is very much part and parcel of what OOP is for. I can see this is a matter of terminology though – I’m not saying you’re wrong, just that there’s more than one way to look at it.

    Also, it’s interesting to me to note that almost all of the code you show in your excellent concrete example of an ES, over at:

    http://t-machine.org/index.php/2010/05/09/entity-system-1-javaandroid/

    is used to wrangle around the fact the type system doesn’t let you do what you want. In a dynamic language, almost every single line of that code evaporates away. Entity.getAs() turns into ordinary attribute access (entity.Position) because these ‘aspects’ can be added to and removed from entities on the fly. I recognise that you can’t code AAA games in dynamic languages due to performance constraints, but from a software engineering perspective it’s interesting to me to note that this pattern has arisen to perform a little dynamic typing in a type-safe way, at the cost of some verbosity.

    Thanks heaps for the fun and educational posts.

  22. adam Post author

    @Jonathan

    OOP … Yes, you can merge both paradigms (that’s what I’m doing on a regular basis, after all ;)). But every way I look at it, this seems to be fundamentally antagonistic to OOP. To write “good ES code”, you are required to do things that are pathologically bad for an OOP setup. You are *required* to break one of the most basic tenets of OOP: Object == code+data. You are *required* to break encapsulation. Etc.

    Typeless code … I can see how that might seem the case from a particular perspective, but it’s only very narrowly accurate. Typeless would reduce the amount of keystrokes I have to put on the keyboard – but by *VERY LITTLE* (because the IDE will always auto-complete strongly-typed options). At the same time, it would make the code a lot more fragile.

    I think you’re missing some of the points of what I’m doing here. I *absolutely* do not want typeless code; I would rather claw my eyeballs out. Arguably … what I really want is to add *even more* strong typing; I want to strongly-type the “data” relationships in my code, and then throw away all other constraints on “data”. I want to take a codebase, and “convert” the data from “fields inside Objects, that are managed by OOP, and are tied to their CODE” … to “fluid SQL, obeying absolute mathematical relationships, and nothing else”.

    Typeless programming (and approximations thereof) has consistently been one of the biggest single causes of bugs and lost time in my entire programming life, across all languages (accompanied by memory (mis)-management, and 3rd-party systems that disobey their own stated protocols).

    Note that I am *explicitly* retaining type-safety in my ES’s … if you dispense with type-safety on a large project, with no spec (no game is ever built to a spec), then IME it’s not so much “shooting yourself in the foot” as it is “putting your face in front of a bazooka” :).

  23. Jonathan Hartley

    Hey Adam,

    Thanks for the reply, that’s great to hear your thoughts.

    OO doesn’t necessarily mean ‘one class per real-world type of entity’ though – that’s just one fairly common type of OO model. Just because you don’t do that, that doesn’t make it not OO. You’re just using a different set of classes to more usefully & accurately model the scenario.

    Like, earlier today I was writing code for a sort of spreadsheet. And I didn’t end up with classes called ‘Sheet’ or ‘Row’ – although I considered that model at the outset. But I found it wanting, so instead I ended up with slightly more abstract classes that I called ‘Range’ and ‘Element’ and ‘Transposer’, etc. None of these directly correspond to a visible part of a spreadsheet exactly. Instead they form a more flexible model, which I chose because it provides the abilities I’m going to need. This is still OO though. I just chose a different set of classes.

    Am I misunderstanding you? Do we just have different definitions of what it means to be ‘OO’? Or is it something else?

    Sorry to be banging on about this – I can see you’ve heard it before. :Thanks for indulging me. :-)

    I very much appreciate you aren’t looking to make ‘typeless’ code – just the opposite. That’s not what I meant, but I’ll leave the rest for the moment, so I don’t pile too much of my junk on you. :-)

    Very best regards, much respect.

  24. adam Post author

    @Jonathan

    Hmm. I’m not focussing on how fine-grained your OOP mapping is … I’m focussing on the nature of “what” an OOP object is.

    IMHO, the definition of OOP object is mutually exclusive with the definition of Entity; i.e no matter what level of abstraction you use, you can never represent an Entity correctly as a theoretical OOP object.

    There’s a side-effect: you can never write “good OOP code” that operates directly on entities; you have to write “bad OOP code” (bad … as in: deliberately breaks some of the core best-practices of OOP code)

    (which is not the same as representing it within an OOP language; it’s easy to write non-OOP code in most OOP languages, of course)

  25. Jonathan Hartley

    Hey Adam,

    Thanks again for taking the time.

    I guess it sounds like we have different definitions of what ‘good OO’ is, and my definition is a superset of yours – so when we both look at X, it falls within my definition, but outside your definition.

    If you’re interested in this, would you like to be more specific about where core best-practice OO is broken by the ES? I don’t see it. (if you’re not interested, I understand if you don’t want to get drawn into it at any point.)

    Based on your earlier comments to me and others, I’m guessing it includes things like the fact that the Entity class doesn’t declare any internal state.

    (I might have guessed badly here. Obviously let me know if this is not a good example of what you’re talking about, and suggest some better ones.)

    This seems normal OO to me. There are many OO designs that feature classes with no state, explicitly declared or otherwise. A Proxy object, that delegates all its attributes or operations to some other entity, for example. Or a testing Stub, that exists purely to provide callable methods of the right signature. Or some Sentinel class, which exists purely to support testing equality by identity, instead of by value. All of these and many more are very common, and a normal part of OO.

    I could make more guesses, but I’ll stop in case I’m barking completely up the wrong tree.

    Best regards,

    Jonathan

  26. appel

    I’m sorry, I’ve gone through all your posts but I still can’t grasp how you make something actually exist on the screen as a in-game active moving shooting dynamic object and all that.

    A component represents an aspect of an entity, and contains certain data necessary for a system to “work” on that aspect of the entity.

    Let’s take the bicycle as an example. It can be bought/sold. I assume we’ll name the component for this aspect something like SellableComponent, containing data such as price.

    But, this doesn’t seem to warrant me to go into my engine code and add a new system to deal with this new aspect!?

    “Typical Systems in a game would be: Rendering System, Animation System, Input System, etc.”

    There’s no BuyingSellingSystem?

    I assume that all non-standard systems like that are implemented as some sort of a sub-system within a ScriptingSystem? If that’s not the case, I can’t see how a team of content developers can create a large game world when they need to go into the game code to add a new system to deal with all possible aspects.

  27. adam

    Why would you assume that?

    Here you have the opportunity to.write the simplest code possible – a wholly self-contained chunk of independent code – and you’re turning away from it?

    You wont be “going into your engine code”, you’ll be writing new code that exists independently. In most cases you’ll want a single entry point into this new code eg. A gameloop callback once per frame, but that’s all. Very simple, very loosely coupled.

  28. appel

    Thanks for the reply adam.

    Perhapse my worries are more focused on implementation.

    What I work with is something similar to Game Object Component System as described in Game Gems 6. Or something similar to what Unity uses.

    I’d like to be able to dynamically create content in the world. That is, have a world running, create a new entity comprising of new components, and then load it into a running world. I can’t do that if components are just data without code. In Unity you can create a new component as a script, which has data and code, and it can interact with other entiites/components within the world, and it can be looked up also by other entities/components. Then of course you have systems providing you with the ability to e.g. load and run scripts, render graphics, audio, input etc.

    Maybe my question is… once I’ve created a new component as a data or table, how do you recommend I proceed with creating a system to deal with that component? Could it be dynamically loaded on-demand?

  29. Adam

    A true ES is exceptionally good at runtime loading, but it is NOT trying to solve the general problem of runtime changes to compiled code.

    If you want to swap around existing behaviours between game-items (e.g. change an Orc to an Orc Chieftain … or see what happens if you make all bullets “homing” instead of straight) … the ES shines. But it assumes you either have all the behaviours pre-written/pre-compiled, or that you have some OTHER mechanism for hot-swapping compiled code.

    What you’re describing sounds more like you just want a scripting system – and any-old scripting system would do. You just want runtime-loaded code – i.e. interpreted code would be fine.

    If you want to do that *with* your ES, then you’ll want to implement all your Systems within your scripting language of choice, rather than in a compiled language (C++/Java/etc). Off the top of my head, that might work quite well – the nature of the data you’re sending to systems (batched, very little indirection) tends to be good for avoiding the performance problems of scripting languages.

    PS: I don’t remember the GPG6 system well – but my vague memory is that it was a fairly weak substitute for what I’d call a “real” Entity System. I don’t remember it well enough to say if it did a good job of solving other problems, but it certainly didn’t show you how to make a good ES.

    (I stopped writing for GPG series after the fifth one, and stopped buying them too, so I’m afraid I don’t have a copy of GPG6 to check now)

  30. Adam

    “In Unity you can create a new component as a script, which has data and code, and it can interact with other entiites/components within the world, and it can be looked up also by other entities/components.”

    That’s not an Entity System. It just happens to share some of the same vocabulary…

    “That is, have a world running, create a new entity comprising of new components, and then load it into a running world. I can’t do that if components are just data without code.”

    Of course you can do that if components are just data – in fact, this makes it MUCH easier to do *safely*.

    If you look into hot-swapping code in an OOP language, you’ll see that one of the biggest challenges is versioning of the Class files. If you hot-swap a class, and it’s changed, what do you do to all the existing objects that were instantiated from the “old” version of the class?

    (this is a nasty problem)

    With an ES, you can hot-swap your code as much as you want, just so long as you don’t change the data-fields within a component.

    When you *do* change the data-fields, it’s generally easy to write a conversion method that will “convert” the old set of fields to the new set. This is purely a data-operation and *there are no side-effects* (you don’t have to worry about “code that is currently running” for instance – which you *do* have to worry about when hotswapping full Class/objects).

  31. Jonathan Hartley

    Hey Adam,

    Fair enough, we shall have to agree to disagree. All part of life’s rich tapestry.

    Incidentally, there’s one or two other things I’m going to stick my oar in about too, just to be contraversial. I suspect these issues will be similarly intractable to discussion right now, so don’t worry about exploring them unless you’re really interested.

    It’s a shame that you’ve had such bad experiences with dynamic languages – there are lots of situations where they can really shine. Certainly, your characterisation of them as difficult to build large, comples systems with rapidly changing requirements seems, in my experience, to be wrong. Choosing an appropriate language depending on what you’re trying to achieve can make huge differences (by which I mean improvements in productivity of factors of five, that sort of order of magnitude), so if you have any patience left for them, I’d encourage you to give dynamic languages another go sometime. There is a lot more to them than just ‘static languages without the benefits of type safety’. They represent a full half of the world that computer science has to offer us. Mastering them makes anyone a better programmer. I was a static language zealot myself for about ten years before I started also using dynamic languages, and now I look back on that time and curse the time I wasted. :-)

    Reducing the number of keystrokes in an editor is a good thing, but in my judgement, when writing large, complex systems, it’s better to reduce the amount of code produced instead. This also reduces the number of keystrokes required, but additionally and more importantly, it also reduces the amount of work needed to read and understand the code afterwards. I feel that in the long run, this latter saving turns out to be more important than reducing number of keystrokes.

    I can appreciate these sorts of things are contraversial though, and we programmers should expect to disagree with each other over them from time to time. My best regards to you, with much respect for your views from another perspective.

    Jonathan

  32. adam Post author

    Dynamic languages – which ones are you thinking of? I’ve built stuff big and small in a wide variety. I regularly use compiled langs (C++, Java), interpreted langs (PHP), scripting langs (anything except Python), functional langs, shell-scripting / batch languages, etc.

    [I hate Python’s whitespace: this the antithesis of one of the few rules that every single language and most file formats follow; it’s just personal preference, but I hate writing Python so much that I haven’t touched it in about 6 years]

    “fewer lines of code is good” is true as a gross generalization, but in most systems, and in many apps, “fewer lines of code” means “more HIDDEN code and HIDDEN side-effects”. I’ve learnt over the decades that it’s very easy to have “too high-level / abstract” code, and it gets even worse than the “too verbose” code you were replacing.

    e.g. classic example: it’s much much faster to get a CMS working from scratch written in PHP than it is in J2EE. But once it’s written in J2EE, it works, it is *FAST*, and it carries on working, no matter what you add on the sides. The PHP one will be riddled with horrible bugs and often can’t be updated without breaking in a dozen places.

    Generally speaking, I advocate writing something first in a crappy language *IFF* you need a result quickly – and then schedule-in to re-write it in a serious language as soon as possible if you keep the project running.

    NB: not “when the project is bigger / better”, but merely “if you carry on using it”; otherwise you often never reach the point of porting until it’s too late / too large / too unwieldy.

  33. adam Post author

    “Certainly, your characterisation of them as difficult to build large, comples systems with rapidly changing requirements seems, in my experience, to be wrong.”

    Look at your bug reports over the lifetime of the system.

    Categorise them by cause.

    If the language is C, you can bet that mem-management or buffer-overflows account for one of the top 3 slots.

    If the language is non-compiled, then you can bet that performance and/or typos does.

    NB: many “typos” *will still run*, just incorrectly, because vars have valid names, but the types are incorrect – and so you try to do arithmetic with a string.

  34. Jonathan Hartley

    Hey Adam. Thanks once again for the replies. Always interesting to hear them.

    Ha! That’s funny – we seem to be diametrically opposed on everything! I’ve used a bunch of languages, but the largest and most recent share is of Python (& IronPython.) :-)

    I understand differences due to invisible whitespace is generally a terrible thing, so I empathise with that. There is a really simple fix that everyone uses in practice though, and once that’s in place, it’s never an issue. Plus, then, there is a fairly good argument to be made for why deriving block structure from indenting is a really good idea. But if you really don’t like it, then fair enough.

    Sorry, I’ve taken your blog comments way way off topic. But I find this sort of thing fascinating. How people percieve and choose languages. Your spectrum of languages from ‘crappy’ to ‘serious’ intruiges me. It sounds like we both agree that PHP is at the fairly ‘crappy’ end of the scale, albeit well suited for hacking together quick websites. But then your other implications about what’s crappy and what’s ‘serious’ remind me of Paul Graham’s ‘languages spectrum’ essay about ‘Blub’. No offense intended. :-)

    We do a lot of analysis of our bugs at my current shop, which is IronPython, we’re really big on that. The five ‘whys’, etc. And one thing I can catagorically state without any doubt is we do not get many bugs due to performance, nor due to lack of static type checking.

    Case in point. We had bought some big grid UI control component from some third party. A compiled C# thing. And recently we decided to replace it with one we wrote ourselves in Python. And it’s much faster. Ten or a hundred times faster. It blazes. And that’s not because Python is a fast language, obviously, its a very slow language – probably 100 times slower than compiled C. But there’s a funny thing about performance, which is this:

    When algorithms are small and simple (eg. in benchmarks, or with small inner loops churning over arrays or well-defined data structures) – then all implementations will choose the best algorithm. In these cases, the speed difference between languages totally dominates. In these sorts of situations, Python being 100 times slower than C really shows.

    But when the algorithms become non-obvious, then a funny thing happens. The performance difference between languages becomes much less pronounced. This is curious. Why should it be? I suspect it’s because the language performance only gives you a constant factor of speed up of slow down. (e.g. x100 from C to Python). However, changing algorithms can change your program from O(n) to O(log n) or whatever. For large n, these sorts of changes start to vastly outweigh the mere constant factor contributed by your languages choice.

    Sometimes, the flexibility of dynamic languages allows you to choose a different algorithm. Often this simply results in a simpler design or more readable code. Occasionally, though, those algorithm changes yield speed improvements. Not just constant factors, but Big-O notation speed improvements. Over a large, complex system, those improvements are composable, so they start to accumulate.

    So the somewhat peverse outcome is that the larger and more complex a system is, the better dynamic language solutions tend to perform compared to static systems languages.

    This is all in my humble experience, so I understand if you agree to disagree. :-)

    Respect.

  35. Mark

    There’s a strong argument that if you write unit/integration tests, the type problem in dynamic languages is significantly lessened, as your tests will fail. Then again, there’s the counter argument that the compiler verifies this aspect for you when working in statically typed languages.

  36. Jonathan Hartley

    Hey Mark.

    Yeah, I guess that’s where I’m coming from. I think it’s reasonable to suggest that every project should be using unit tests (and system tests too) regardless of whether they are using static or dynamic languages. The advantages are tremendous, and go far beyond people’s initial expectation of ‘verifying correct behaviour’.

    Once you’ve got unit tests in place, the benefits of static type checking become fairly negligable. Paraphrasing Jay Fields: Your static type check verifies that ‘1 + 1’ will always return an integer. This is useful – but type mismatches are only one sort of possible error. To catch the other possible errors, you also need unit tests, to verify that ‘1+1’ actually returns the correct result: ‘2’. Since 2 is an integer, the static type check is now redundant.

    Often overlooked, the costs of static type checking are huge. Mangling the design and bloating the codebase of projects. With all due respect, the ES this post is about is a great example of that. Like a lot of design patterns, In a dynamic language the whole need for this pattern goes away – you get all of its features for free, with no extra coding, just from ordinary attribute access.

    I’m not saying that static languages don’t have a role – of course they are brilliant and often are more appropriate than dynamic languages. But for historical reasons dynamic languages have often been under-represented, and are a better choice in more circumstances than people often realise.

    I’ll stop hijacking the comments now. Sorry! :-)

  37. Adam

    Surely … if that’s true … then …

    Static type-checking is (among other things) a special form of Unit Test that:
    – takes a LOT less time to type
    – is MUCH cheaper to maintain
    – is more EXPLICIT about intent

    ?

    I see the logic of your statements about unit testing, and I swear by UT, but … in practice, even with all the help in the world, I find UT takes a lot longer to type than the almost zero time it takes for typing.

    Also … I’m confused by your implication that types make for less clarity – how on earth does that happen? If you’re doing OOP, your types ENORMOUSLY improve clarity, intent, and application design – I’m struggling to see how it could happen any other way.

    (assuming your team is using types correctly)

  38. Jonathan Hartley

    Hey Adam.

    Yes, I absolutely agree that static typing is a special form if unit testing.

    >> “less time to type”:
    Absolutely, all other things being equal, adding (and maintaining) static type annotations is a lot faster than creating (and maintaining) unittests. But on the other hand, if you’re creating unit tests anyway, regardless of language type, then this becomes less significant.

    >> “cheaper to maintain”:
    This bit seems debateable. The typing and updating of those types (or tests) in the code are not the only costs that contribute to ‘cheapness to maintain.’ That depends on a lot of things. I think dynamic languages can score some points back here in the big picture, due to having smaller codebase size, and more flexibility in possible designs, which sometimes allows you to choose designs which more closely match the problem domain, and are less closely tied to the semantics of the programming language.

    The ES is a good example of this: The last thing I want to do here is be critical of the ES in your posts, because I think it’s an elegant and highly versatile solution to the problem, and also is implemented perfectly within the language you are using. It’s a great example of the idea to ‘prefer composition over inheritance.’ But in addition, it also illustrates this point about maintainability. It has lots of ‘Java’ in it, specifically added to subvert the type system, but the core of the idea is that you’re adding attributes of appropriate types to an Entity object at runtime. This is obviously just “ent.position = Position(x, y)” in a dynamic language. It’s easier to understand and maintain this single line of code than the entire ES that it replaces. This is what I meant about dynamic solutions sometimes improving clarity. Huge chunks of code often simply evaporate when moving to a dynamic solution, so that what is left is just the core of your idea, without any intrusive ritual from the language.

    That was why I made my initial very first comment about the ES being interesting from a computer science point of view of comparing different language paradigms.

    >”more explicit about intent”
    Obviously you are very right, that at a low level, the intent of a particular data member or method is often made clearer to human readers by explicitly labelling types. But at another level, tests are more explicit still. They actively prove that ‘this code can be called like this, and it has the following effect’. Such tests enumerate all the situations the authors of the code expected it to be used, and what its failure modes are. This seems far more explicit to me than simply balancing type declarations, especially since they are explicitly testing behaviour (which is the important thing) as opposed to conformance to the arbitrary constraint of matching types (which does not perfectly correllate to actually working.)

    I wrote a lot more, but I already write too much. Delete, delete, keep this last bit:

    Finally, remember that dynamic solutions are highly OO as well. Just because something is dynamically typed, that doesn’t mean it is not also strongly typed. So all the benefits of clarity from defining and using OOP is still present in most dynamic languages.

  39. adam Post author

    Ah, now here’s a very interesting point / misunderstanding:

    “The ES is a good example of this: … it also illustrates this point about maintainability. It has lots of ‘Java’ in it, specifically added to subvert the type system, but the core of the idea is that you’re adding attributes of appropriate types to an Entity object at runtime. This is obviously just “ent.position = Position(x, y)” in a dynamic language. It’s easier to understand and maintain this single line of code than the entire ES that it replaces. This is what I meant about dynamic solutions sometimes improving clarity. Huge chunks of code often simply evaporate when moving to a dynamic solution, so that what is left is just the core of your idea, without any intrusive ritual from the language.”

    Yes, it looks like that … but, no – that’s not what it’s doing.

    It is *intentional* that there is this “middle layer” through which everything is routed. In the real-world, it is *critically* important that you can store and pass-by-value (or pass-by-reference-to-value) the minimum amount of data needed.

    For instance, an ES in this style makes it very easy to implement high-performance data loading/unloading. This helps *enormously* when writing multiplayer code (where 99% of the data isn’t available 99% of the time), and also when writing heavily multicore code or gaming-console code (where you want to keep as much as possible inside caches).

    On the other hand, at a very high-level, I think this middle layer does two things (NB: I’m not sure these are the most important things, or the only things, but they’re the most obvious to me right now, off the cuff):

    – EXPOSES the data relationships (it records which code added which field to which entity and in which context)
    – COMPRESSES the data down to an efficient representation (only the data that is actually needed is actually present – an entity with 10,000 fields may be passed to you in-memory with only 5 of those fields, as the static component-typing has guaranteed that you don’t need or care about the other 9,950 fields)

    …I’ve personally written code that does the EXPOSES part in several dynamic languages. It works awesomely. It just needs a 10Ghz x 20 core CPU to run at anything approximating a decent speed :(.

    (I’ve seen languages that I believe can do that a lot faster, but none that were in use on mainstream production systems, so I never got to benchmark them. Most languages IME were either “not dynamic enough” or “too dynamic (slow)”. I haven’t tried for a few years, so I’m happy to believe the situation has changed. Then again … I’ve seen the strategy behind these languages, and very rarely does anyone care about making ultra-dynamic code run at high performance).

  40. Jonathan Hartley

    Hey Adam,

    Thanks once again.

    You’re absolutely right, I hadn’t understood those aspects of the ES. I might have to go chew on that for a while, see how it affects my understanding. Sounds like the ES isn’t quite such a good example of what I’m thinking after all. Perhaps I should try implementing an ES in a dynamic language, just so we can have a real idea of whether the code simplifies at all, and we can both have a laugh at its performance. :-)

    I also agree that dynamic language implementers have rarely had performance as a priority. It’s relatively obvious that the kind of performance optimisations that have been developed for static languages, in the compilers, the runtimes and on hardware, don’t work at all for dynamic languages, so people kind of gave up on dynamic performance, for decades.

    I think that is starting to change a little in the last couple of years – primarily driven by the performance of competing Javascript engines in the browser. People have realised there are a whole different set of dynamic language performance optimisations, which are very different from those used for static languages. There are reasons to be optimistic about the future of such developments, but it’s very early days yet. By which I mean that I hope that some real-world results will be ready for production in the next couple of years. For example the PyPy project have re-implemented the Python interpreter in Python. They started out about ten times slower than regular Python (which is written in C) but of late are from 2 to 10 times faster, and say they have plenty they have not yet done. Hopefully those changes will be rolled back into the regular CPython. But generally, there is decades of catching up to be done.

  41. Jonathan Hartley

    Oh, and the idea of me implementing an ES isn’t such a crazy leftfield idea as it might seem – I was reading your pages in the first place to find out how other people had solved the sort of problems I was finding in a hobbyist Sunday afternoon project of my own. So it might actually happen. :-)

  42. Jonathan Hartley

    Hey Adam,

    So I did implement my own quick-and-dirty version of an ES. I took some shortcuts that you might not approve of.

    In particular, I’m storing all my important data as attributes on the Component instances themselves. I can see that this falls short of your described ES design, but my idea was that this is a simple first pass, and converting this into storing this data in arrays, maybe managed by the Systems, will be relatively easy to bolt on later.

    For the moment, this is a good enough start for my hobbyist project. I don’t yet need to record metadata about how aspects get created (I think this is what you are describing by the ‘ESPOSES’ idea above?) nor do I yet need to compress my data. I’m planning to deal with very low-poly models for an abstract sort of look.

    So here’s what I *did* do:

    I have a minimal GameItem class that just allocates its own unique ID on instantiation. My World class stores a collection of these, in a hashmap, keyed by ID.

    At runtime I attach various subclasses of Component to GameItems. At the moment, possible types of Component are:

    * Position
    * Orientation
    * Shape (manages the verts and faces of an arbitrary 3d poly)
    * Glyph (stores the result of converting a Shape into the arrays OpenGL needs)
    * Mover (updates the gameitem’s position)
    * Camera (makes the gameitem into a camera)

    My main game loop calls .update() on each of the half-dozen or so types of system. Each system iterates through just the Gameitem instances that has attached the type of Component the system is interested in. For example, the Render subsystem iterates through the Gameitems which have a Glyph, and calls glDrawArrays using its data.

    The ‘Mover’ Component currently has only one implementation, called ‘WobblyOrbit’, which is attached to the camera, to make it move around within the scene.

    I’m pretty happy with this for a couple of days work. The code is *much* nicer than previous similar projects have been using a traditional ‘inheritance tree’ style of game item.

    It’s written in Python, and performance is ‘adequate’, by those standards, by which I mean at 60fps on my shoddy old laptop (a 2005 Thinkpad, with ATI Radeon X1400) I can do either:

    * 800 independently moving and rotating entities, of a couple dozen vertices each

    or

    * 1 big entity, with about 10,000 vertices on it.

    Or any linear interpolation trade-off between those extremes.

    I know this is fairly laughable by pro-gamer standards, but it seems adequate for my hobbyist game ideas. And I haven’t even begun to think about optimising for performance yet, eg. I don’t do any entity or geometry culling at all. I’m simply updating and rendering everything, all the time. Presumably this and lots of the things you have already talked about could help performance going forward. Oh, and I’m using client-side opengl arrays, not buffers, so I suspect all my opengl data is being set to the card on every frame. I might be wrong but I haven’t looked very closely at it, so I’m probably doing much here that is quite dumb.

    Your thoughts and ridicule are very welcome. :-)

  43. Jonathan Hartley

    I forgot to emphasise: Many thanks for the posts and the subsequent chat. You’ve really helped me get my head around this somewhat, and even though I’ve only taken it half way, my code is *much* nicer as a result. Great work!

  44. adam Post author

    @Jonathan

    –“I took some shortcuts that you might not approve of. In particular, I’m storing all my important data as attributes on the Component instances themselves. I can see that this falls short of your described ES design”–

    To be honest, so long as you know *why* that’s an evil and wrong thing to do, then … there’s nothing wrong with doing it :).

    The problem is that 95% of the time when someone does what you describe in those lines of code it’s because they think they understand what’s going on, but actually they misunderstood.

    Your comment brings up an interesting point I’d not thought of before: if you really know how to make an ES properly, they’re actually very fast to make in a “quick and dirty” fashion, and “upgrade later”. This is a side effect of the way they de-combine data and code from each other.

    NB: merely putting the code and data in different places DOES NOT achieve this (there are other, more obvious, techniques that do that, but fail on their promise to be upgradeable so easily. Some of them do pretty well, but I’ve used some that died horribly). I guess it’s because the overall system (NB: not the same use of that word as the internal ES systems/sub-systems I usually talk about!) is architected very deeply to treat data and code as separate things, free-floating.

    (I’ve used data-dependent coding methodologies that did this less well; I suspect it’s because they typically threw away the code entirely. ES don’t do that; they keep the code, they just move it somewhere else – somewhere well-defined)

    Code can easily be thrown away, replaced, upgraded, re-implemented, re-designed, re-architected, built again from scratch … and yet the bulk of your game remains unchanged, because it was data-dependent.

  45. Jonathan Hartley

    Yeah, that – makes a lot of sense. The increased modularity you talk about really makes a big difference. Classes are small, and often consist of a single method, which just operates on a single kind of data.

    I’m putting together my project as a demo for a talk at a conference this summer about the pros and cons of OpenGL from Python, and the use of an ES design is ostensibly irrelevant to that, but it’s worked out so well that I’m thinking of including a small section in the presentation about it now! :-)

    Also, for some reason today lots of my friends and follows are linking to stuff about data-oriented design, i.e. working on contiguous arrays of data rather then traditional objects with fragmented memory use. An idea that’s clearly interwoven with your ES ideas and growing all the time. Very cool!

Leave a Reply

Your email address will not be published. Required fields are marked *