2-8
Cleaned up some things. The current way of doing waypoints sucks. Right now, I create a lot of entities and give them names, and then whatever wants to use them needs a list of names. Instead of that I'm going to make it official. Then the editor can modify them as just a list of points. (Minor issues : Waypoints need to be in world space, but everything else is in entity space... )
2-7
After fixing the stuff I wrote yesterday, I drew some crappy sprites and messed around with placing them in the editor. [See editor screen shot.] They actually look pretty good. But this is still just an excuse not to do the parts I know need doing first. I really should concentrate on gameplay first. In that direction, I think I will work on enemy AI. Get them moving around a little, firing.
2-6
So I started in on the graphical portion of the maps. It proved very simple. Of course, without any assets, it's rather pointless. And it felt rather like an excuse to not work on the stuff I know needs done. But, it's there, and it (mostly) works. So.
2-5
A compelling case for a global. The situation : I have an entity handle. To get the entity, I need the world and the handle. But to get the world, I need the entity. A simple solution : Global access to the world.
Dependency injection is a better alternative. But. You know. Lazy.
There is another advantage to Object Handles is that hanging references to a logically destroyed entity won't keep the entity object alive. Of course this comes with a gotcha - I have to check the handle for validity every time I want to use it.
Also a lot of boxing.
2-4
Problem : A list of created entities. All entities in the list are initialized, and if they have an OnSpawn handler, it is called. Problem : The OnSpawn handler can spawn an object, which is placed in the list of created entities. Possible result : Infinite loop creating an infinite number of entities.
Solution : Double-buffer the created entities list. I can do this by hand, or just create a simple collection class to handle it for me. Bonus : I get to learn how to write collections in C#. It only needs three operations : Swap, ClearFront, and Add. (Of course, implement the IEnumerator interface to use foreach on it - it's just a pass through to the front buffer.)
Problem : Referring to entities by ID. IDs cannot be reused. If IDs are never reused, entities must be stored in a dictionary. If IDs are reused, errors can occur when an ID is recycled soon after being released. (Things referring to it need at least one complete update cycle to notice that the ID has been invalidated - and this is hard on scripts anyway.)
Solution : Entity handles. Untie the array index from the entity ID. A handle is an ID and an index. This lets a handle be invalid even if a new entity has been created at that index - their IDs will not match. This solution is not meant to recycle entities, only array indexes. Entity look-up remains fast, while not creating a reference in the object graph.
Addendum : This breaks some functionality of the scripting system, while making other functionality possible. I will proceed with caution.
Implementation : Write a custom container. It indexes on handles.
2-3
HEY. RUSKIS. Stop leaving comments on my blog in Cyrillic : I can't read it, I will only delete it.
The more I use C#, the more I hate garbage collection. It is supposed to make the language easier to work in. I suppose it might, for begginers, but the garbage collector actually makes it more difficult for me to manage memory. As an example : My game entities. I know when they are no longer needed; let me destroy them myself. Also, why do I have to decide at design time if an object goes on the stack or the heap?
Anyway. The solution to Garbage Collector woes is two fold. Both is great, but you have to go all the way with one. Half way with both fails. It's either No Allocations, or, Simple Memory Layout. The second is much easier to achieve than the first.
Top : What it currently looks like.
Bottom : What it will look like if I switch to Entity IDs.
2-2
[EDIT]
Also this.

Maybe a concept every day? Maybe.
[/EDIT]
Last night I wrote (most) of that article series. I made it all the way into part 3, and I wrote the code for the whole thing. (Someone) pointed out that it isn't as much an article, as, 'here is my code, look at it.' (Someone) is right, but I don't care. Here is the first part of that article. I'm looking for feedback. Comments are welcomed.
This is an article about an entity component system. It's specifically for XNA, but this first part is applicable to any language. After this, I'll get into things that are very XNA-specific, and use C#'s reflection, and winforms, and XNA's serialization and content pipeline - and those things won't translate too well to a different environment. But if you are using XNA, well, this is going to be awesome!
This article is a rough draft. There will be mistakes. The code won't be perfect, either. I've pulled this code from a real project, but that project is very complex. I had to simplify this a lot - and a lot of details were removed. Some of those forgotten details could have been important. This is meant to give you the ideas, not the code, so don't copy it and just expect it to work!
In part 1, I'll talk about what a component actually is, and how they are put together to make an entity. I'll go over how they communicate with each other and the various sub systems in the game.
In part 2, I'll use XNA's content pipeline to turn an XML document into a set of entity components. This is as simple as adding a few references to the game project, and writing the XML. I'll also go through the use of reflection to clone entity components, and why they have to be cloned this way.
In part 3, I'll examine a simple scripting system. The scripts themselves are in C#, and are actually entity components. This should demonstrate just how powerful an entity component system can be. It will also cover implementing closures in C#.
In part 4, I'll create an editor for assembling entity templates. This will remove the need to write the XML directly, and will also demonstrate XNA's intermediate serializer, the property grid control, and another use of reflection.
These articles are not a step by step tutorial. There's sample projects at the end, but they are full of stub functions, and they actually do almost nothing at all.
Before I dive in, a few words on the project structure. The solution contains three projects - Engine, Game, and Editor. Most of this stuff goes in the Engine project. I'll explain why in part two, but for now, all the classes I list here go into the Engine project.
Part 1
So what is an entity component? It's a component of an entity. Okay, so that definition is entirely useless. A component represents some unit of logic. Entities bind these components into a single object. Wait, so what is a component then? That's hard to say. A component is useless without the entity. The idea can only be defined as that part of a whole. By itself, it is nothing. Thankfully, the ideas don't need to be clear for the code to be.
I can answer the question 'What is a component' in code.
public class EntityComponent
{
//V- What the hell is that? It's some cruft for XNA's Intermediate Serializer. See part 2.
[Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
public Entity Me { get; internal set; }
public virtual void Initialize(ContentManager Content) { }
public virtual void Destroy() { }
public virtual void Update(float ElapsedSeconds) { }
}
That's rather bare. The component keeps track of what entity it belongs to. The property is public, but only types from the same assembly can modify it.
Components are grouped using an EntityTemplate class.
public class EntityTemplate
{
public List<EntityComponent> Components;
public EntityTemplate()
{
Components = new List<EntityComponent>();
}
}
I use this class so that in Part 2, I can load these, instead of trying to load complete entities which have members that XNA can't serialize. This also allows multiple entities to share a template. Okay - they can't right now. Each entity needs it's own instance of the components. In part 2, I'll go over how I clone an EntityTemplate so that I can create many entities from a single template.
For now, we'll have to create entity templates the hard way.
EntityTemplate Template = new EntityTemplate(); Template.Components.Add(new ExampleComponent());
The entity class needs to provide a way to get a component. Other than that, it does nothing more than pass through to it's components.
public class Entity
{
public Simulation Sim; //This is the 'world' the entity exists in.
public EntityTemplate Template;
//I'll use these delegates in Part 3.
public Action<Entity> OnContact;
public Action OnSpawned;
public bool Alive { get; private set; }
public T GetComponent<T>() where T : class
{
foreach (EntityComponent Component in Template.Components)
if (Component is T) return Component as T;
return null;
}
public void Initialize(Microsoft.Xna.Framework.Content.ContentManager Content)
{
foreach (EntityComponent Component in Template.Components)
{
Component.Me = this;
Component.Initialize(Content);
}
Alive = true;
}
public void Destroy()
{
foreach (EntityComponent Component in Template.Components)
Component.Destroy();
Alive = false;
}
public void Update(float ElapsedSeconds)
{
foreach (EntityComponent Component in Template.Components)
Component.Update(ElapsedSeconds);
}
}
When I create an entity, I have to assign a template to it's Template member, and then I call Initialize.
I'll show you an example of a Component.
public class EntityDrawComponent : EntityComponent
{
public override void Initialize(ContentManager Content)
{
//Use Me.Sim to get the Rendering subsystem, and add something to it, like a scene node, or whatever you want.
}
public override void Destroy()
{
//Remove what we added in Initialize from the Rendering subsystem.
}
}
2-1
I've decided to extend this daily dev blog for another month, but with some additions to the contract. If I want to do something else, I am free to : So long as I still have something to show for it.
Something Unrelated : I spent several hours yesterday getting a property grid to edit a bitfield value with a bunch of check boxes, instead of a raw integer. This was supposed to be collision category and mask info for the physics objects. But then I realized that that is way too low-level for this, so I'm going to replace it with simple collision groups.
I have a sort of game-making tool on my hands here. The editor is nice. Really nice. The component model is even better. The ability to couple simple scripts to events in the editor is surprisingly powerful. I don't know what to call it. I don't necessarily want to call it Jemgine : Even though I have been calling it that so far, Jemgine is the application/gui framework I wrote in C++ over the last few years. This is something new, and much more specific to a certain kind of game. I'd like to name it after the game. Maybe something like 'Crustacean'. So I have to goals. Not just to produce this physicy-adventure game, but to produce a great tool for piecing these sorts of games together.
I plan to upload binaries of everything tonight. No source yet, sorry; it's not ready. (Don't misunderstand : My code is, as always, very well written. I just want it to be a little more feature-complete before I share.)
And that brings me to the other thing I want to do with this month. I want to write exactly one article, of a decent length, each week, detailing some aspect of the technical design of this thing. I plan to start with the entity component model. And then I think I will write about combining that with XNA's intermediate serializer for loading template definitions. This part might also include bits about cloning components off of the templates. Third part, the script driver, and all that. And finally, the fourth article, will be a simple editor for creating these entity templates - which I need to write anyway. I might have to write a whole other set of 'simplified' code to support this article series.
Ah, remember those binaries I promised? Here they are : http://jemgine.omnisu.com/projects/Crustacean2_1.zip
You'll need XNA installed - the redist should do. http://www.microsoft.com/downloads/details.aspx?familyid=53867A2A-E249-4560-8011-98EB3E799EF2&displaylang=en
To use the game, you'll need a wired 360 gamepad.
[Edit] I have been informed that there's some sort of adapter for wireless gamepads. Yeah, that will work too. Sorry about the lack of keyboard support - I'm targeting the 360 first, so anything else is secondary. [/Edit]
You won't be able to actually try out any maps in the game - the game requires the map to go through the XNA content pipeline first. I know, sucks! Sorry about that. But, at least I might get some feedback on the editor itself.
1-31
I hacked an 'affected by gravity' flag into Box2d.XNA so that my bullets could fire slow and not fall to the ground. They are supposed to be energy weapons, or something. I also hacked in a way to pass a parameter to an entity's OnSpawned event, and then I removed it, because I found a better way. I can attach a function to the entity's OnSpawned event that does what I want, instead of passing something to some script on the entity that was just passed. Also, I used Reflection to clone components without having to write a virtual clone function in every component.









