This member has provided no bio about themself...

Report RSS Making Avorion's Game Model an Entity-Component Model

Posted by on

Disclaimer: Warning, this will get pretty technical. If you're not familiar with the terminology and computer sciency stuff, you might have trouble understanding.

I have spent a lot of time lately to change the internal model of the game from the Inheritance Model to an Entity-Component Model.

For those of you that don't know what the Inheritance Model is:
In the Inheritance Model basically all object types inherit some behaviour of other, more basic types.So for example in Avorion's model, you have a Ship type and a Craft type. Ship inherits from Craft - this means a Ship can do everything a Craft can. And a Craft inherits from BlockObject (an abstract object that is composed out of blocks, which is, in Avorion, everything except for loot and wormholes). This system can go very deep and usually you have some very basic object at the bottom. In Avorion this would be a basic object Entity, which has nothing but an index and a position. Now every other object would inherit from Entity, like BlockObject, which would then have other objects inheriting from it. So basically you get a hierarchy, which is wonderful, because you only have to code things once and then have them inherit from other objects. But it has one major drawback - it's not very flexible when it comes to adding new properties.

I first ran into problems with the Inheritance Model when I wanted to create ownable asteroids. Factions would be able to own asteroids or even fields, and players should be able to claim asteroids once they found them. The class Asteroid inherited from BlockObject - but the 'owner' property was located in Craft, which also inherited from BlockObject! At the time I hadn't thought about ownable asteroids, and now I had the choice between 3 alternatives:

  1. I could implement a second property 'owner', just for the Asteroid class.
    This would be bad style - you don't want to implement the exact same logic twice. Like never. Ever ever. Seriously.
  2. Let Asteroid inherit from Craft, which would make every Asteroid a Craft.
    That could make sense in some ways (maybe?), but I decided against it, as it would make asteroids pretty overloaded. Crafts have a lot of other stuff that asteroids simply don't need, like a cargo bay, crew, and some more stuff like engines or controls. Usually this wouldn't be too bad (it would never be used, so the user wouldn't see it, right?), but if you've played Avorion, then you know that there can be thousands of asteroids in just one sector. Having thousands of objects with unnecessary properties floating around, taking up memory, would just be stupid. Plus, it wouldn't keep things simple. You should always keep things as simple as possible.
  3. Move the property owner from Craft to BlockObject.
    This would make every BlockObject ownable. While this could also make sense in some situations, I also decided against it. Basically this would mean that over time the BlockObject class would get loaded with properties, whenever I needed a new feature that might fit into some classes but not into others. Which might then be used in some inheriting classes and not in some others. This would be wasting memory again, and the BlockObject class would grow to some super-sized bloat of functionality that would be impossible get right.

Now this is a lot of problems for one quite simple feature. So I decided to heavy-heartedly drop the feature. But this kind of problem kept reappearing.

Fast forward to four months ago, I remembered that a friend of mine had asked me about the Entity-Component Model, and if I used it in my game. At the time I had never heard of it, but then I decided to look it up.
The Entity-Component model takes another approach of creating an architecture for games. Instead of having inheritance, where everything inherits from something else, you have one basic entity model, which only has an index. Then there are component objects, like Position, Velocity and the like. These components are then dynamically added to Entity objects to create game objects. The big advantage is that game objects can be made up of any components the developer would want. At first this seemed a little weird to me, as I had never thought of this before.

But then it hit me - this would be the solution to all those problems I had before! With the new model I could make the 'owner' property a component and then add it to all the game objects I wanted - I could even create some asteroids with an owner and some without! Or wreckages with an owner (where I had the same problem), or wormholes or ...

So what I've been doing over the last couple of months where nothing new came up was this. I restructured the game model of Avorion from an Inheritance Model to an Entity-Component Model. Now I can create new game objects very easily, which means new features will be much faster to implement.

This new model has even more advantages for Avorion:

  1. Networking
    Now, that everything is made up of components, networking has been simplified. I can update single components of an entity, whereas before, I could only update an entire entity. When I wanted to update the position of say, a ship, I had to add all the properties of the entity to the update message, which created unnecessary networking overhead. (I know, this could have been solved smarter, but this would have involved writing A LOT of more code.)
  2. Saving into database
    Components can be saved into the database more easily than entire entity objects. One table per component - I have yet to find a cleaner solution than this.
  3. Separating server and client logic
    I can have components that run only on the server (like for loot or networking) and components that run only on the client (particle effects, sounds, textures, meshes). The solution I had before was pretty ugly and I don't think I want to talk about it a lot (it involved linking specific functions on the client and some on the server, yay c++!).
  4. Performance
    And this one is a big one. I can now store all components of the same type in an array, so they're located next to each other in memory. When I update the scene, I first iterate over all position components, then all velocity components, and so on, which maximizes the use of the cache and instruction cache. This boosted up performance by over 1000% for some components!

On the other hand, what struck me pretty hard then, was that I realized that composition isn't a new approach at all and had been around for quite some years. So I felt a little dumb. I might have acquired some skill in coding over the last 10 years, but I realized that I'm still learning. And I learned a lot in these past four months.
So if I haven't bored you to death by now, if you have questions about the Entity-Component Model (maybe because you want to implement one yourself), feel free to PM me.

Oh, and uh, there's gonna be a new feature: Ownable asteroids.

Koonschi on Twitter
Avorion on Facebook
Avorion on IndieDB
Avorion Website

Post comment Comments
Guest
Guest - - 693,147 comments

Nice! Great to hear that you are making a lot of progress! :D Ownable asteroids? I think you should add a feature where the player could place a block, that would automatically make the nearby asteroids his (10-20 asteroids). The player could mine those asteroids, or upgrade that block into a station which would:
1: Make more and more asteroids his
2: Would automatically mine those asteroids
If the player got the resources, no matter where he was it would be a very easy way to get infinite resources by placing a few of these, so the solution would be that the station would mine asteroids quite slowly and resources could only be collected when the player is docked.
I hope the idea was helpful, I will post this at the forum too, just to make sure :)

Keep up the great work! :D

Reply Good karma Bad karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: