Object Management?

Started by
26 comments, last by AgentPaper 12 years, 10 months ago
Hey everyone. I've been messing around with C# and XNA to try and make a fairly simple game just to start, but a problem I've run into, which I've run into before and had trouble with, is managing objects that are created and destroyed on the fly, and specifically how you would tell the engine to draw all of those objects. For example, right now I'm just trying to make a simple spaceship that shoots bullets when you hit the spacebar. I've got the ship moving around just fine, but I can't figure out how to make the newly created Bullet objects draw and stop drawing themselves correctly. I'm sure there must be some standard way that this is done, but I've been unable to find anything, probably mostly because I have no idea what to call such a system in the first place!

I've tried making an array that stores all the objects that need to be rendered, but I can't seem to make it work, and I don't think my solution is ideal anyways. If someone could share some example code of how this type of thing is managed in an existing game, that would be extremely helpful.
Advertisement
You need to define an abstract "GameObject" class that has Update() and Draw() virtual functions that have to be overloaded. You can also define position/orientation/scale stuff inside a game object class. Every object in your game (players, bullets, etc) needs to derive from the GameObject.

The object manager should deal with GameObject's. It should also have an Update() and Draw() function that loops through every GameObject the object manager manages and individually updates and draws them. Be sure update comes before draw though.

I generally store my game objects in lists, but usually thats just because I'm too lazy to write fixed array resizing code. Its more efficient to write one that works with fixed arrays (for static stuff that doesn't change often) and linked lists (for the dynamic stuff like those bullets, because things can be added to and removed from linked lists without re-sorting or re-sizing an array internally). If you don't know the differences between linked lists and array storage, I recomend you look into them!

Further more.. I usually keep "lists of lists" to keep separate types of objects together. This way you can update certain GameObject's that need to loop through specific other types of GameObject without having to search through -everything- for the correct type. This way you can pull lists of players or enemies separately. For that you define a generic function "public GetTypeList<T>()" so you can get a list of a certain type back. If you dont know about generics you should read up on those too. This comes in handy for things like bullets especially. If you're calling update on individual bullets that need to check enemies for collision, you dont have to search through every type of object blindly. You can do something like this in the update function of the bullet:

List<Enemy> enemies = ObjectManager.GetTypeList<Enemy>(); // Grab the list of enemies.

foreach(Enemy e in enemies)

{

if(bulletCollidesWithEnemy)
{


Enemy.Kill() // Kill the enemy, he's been shot!
this.Kill() // Kill the bullet because it's hit an enemy.
}


}



You have to implement a function in the ObjectManager that removes GameObjects though. Something like ObjectManager.Remove(GameObject obj). It really depends on the type of game and the data structures you use to determine the best way to remove objects. If you call list.remove(), it will search the list sequentially until it finds the object to remove. This could get really inefficient the larger your game is, so it might be better to add a removal bool value to your GameObjects and add another loop to search for and delete those later. You have to be VERY careful about things that get removed as other objects could still be referring to the object you are "removing". If you remove something from the object manager and another GameObject has a reference to the object that you are removing, the object wont be removed. C#'s garbage collector wont get rid of it because it still has a reference, and since its not managed by the object manager anymore it could cause problems. If you remove an object you have to do checks to make sure all of its references are gone, OR add checks inside the functions that use those references "if(object.isDead())".

I would give you a copy of my ObjectManager and GameObject classes if the power supply on my programming computer didn't recently die. :P

But yeah.. Back to your original post. I dont think your game objects had separate Update() and Draw() functions. Your objects need to be able to kill themselves or kill others inside update functions. Please ask more questions; I've just uber-ranted.
Small tip. Rather than continually creating and destroying something like a bullet, create your objects at level load. Have a pool of bullets large enough to ensure that no one can hit space enough to fill the screen with all of them. When space is hit the bullet is set to the fire location and given velocity, when the bullet hits something or moves off screen reset it (null position and not set to render). If the game is simple enough you can do this with enemies as well. It gets out of constant resource creation and deletion, simplifying your task to set, event, reset.


if (bullet.location.y < screenHieght && bullet.location.x < screenWidth)
{
if (bulletCollision())
{
reset(bullet);
reset(whatsBeenHit);
update(scoreEct);
}
bulletUpdate(bullet);
}
else { reset(bullet); }



Its pseudo code but I did something similar in Unity with C#.
At the moment, I've actually already got my objects seperated into a good number of classes. I've got RenderedObject, which is anything that's visible, and only has a position, rotation, and sprite. I also have MobileObject, which inherits from RenderedObject, which also has a velocity and acceleration. And so on down the line for DestructibleObject (has HP), ShipObject (has weapons and such), and then finally my actual SimpleFighter, which has the actual stats for the specific ship. I also have a SimpleBullet that inherits from ProjectileObject, which itself inherits from MobileObject. So I think my main problem was just that I don't know the syntax for making a list of objects, or a list of lists for that matter.

Small tip. Rather than continually creating and destroying something like a bullet, create your objects at level load. Have a pool of bullets large enough to ensure that no one can hit space enough to fill the screen with all of them. When space is hit the bullet is set to the fire location and given velocity, when the bullet hits something or moves off screen reset it (null position and not set to render). If the game is simple enough you can do this with enemies as well. It gets out of constant resource creation and deletion, simplifying your task to set, event, reset.


if (bullet.location.y < screenHieght && bullet.location.x < screenWidth)
{
if (bulletCollision())
{
reset(bullet);
reset(whatsBeenHit);
update(scoreEct);
}
bulletUpdate(bullet);
}
else { reset(bullet); }



Its pseudo code but I did something similar in Unity with C#.


I don't think that would really work for what I'm doing. There's going to be a whole lot of bullets of many different types flying around at any given time, after all. And does it really save that much processing power or anything? Doesn't seem like it would all that much. I guess I could simply not destroy bullets after they're created, and if a bullet of that type is fired again, it'll re-use the old bullet before making a new one. That's really an optimization thing though, so I don't think I'll worry about that quite yet.
Object management is an broad issue though. The trend of the last years in larger projects (and I explicitly stress the term "larger" here) is to avoid deep class hierarchies as described by the OP, because they tend to either cause an explosion of types or else migrating nearly all stuff into base classes, thus violating the "single responsibility" design principle (from this point of view also having draw() and update() in the same class is questionable). Similarly, scene management is gone away from the omnipotent scene graph to a variety of sub-systems, each one responsible for a single or at most a couple of closely related tasks. This had led to the development of the nowadays famous entity-component systems.

It is usual to split updating and drawing of game object. But looking at more complicated examples, one can see that even updating can often not be handled in a single step. Animation and physics and especially the reaction of game objects on other (updated) game objects needs to be considered here. And also drawing is not that easy as soon as batching, transparency, avoiding of state switches and similar stuff come into play (what is another point of not having game objects draw themselves). Not to mention that e.g. collision detection isn't something that can be done locally by a game object itself.

IMHO the principle of object management should consider to use more aggregation than inheritance, to out-source tasks to dedicated sub-systems, to limit a scene graph to just a logical scene description, and to link the belonging single aggregates of game objects into the sub-systems dealing with the appropriate functionality. Although this need not be strictly followed in small projects, IMHO it would be a great practice just to start with, preparing the ground to more complex projects coming in the future.

Coming to more concrete statements: Projectiles may be implemented as game objects with separated behavioral representation and graphical representation. This way would probably allow to fetch a shared graphical representation from resource management, and to use unified behavior aggregates fetched from a pool. The graphical representation needs to be linked into the rendering sub-system, the bounding volume needs to be linked into the collision sub-system, the movement needs to be linked into the animation sub-system. There need to be several collision handlers. E.g. one handler that destructs projectiles that leave the bounding volume of the screen, another that handles collision with enemy ships, ...

Just my 2 EUR-Cents

At the moment, I've actually already got my objects seperated into a good number of classes. I've got RenderedObject, which is anything that's visible, and only has a position, rotation, and sprite. I also have MobileObject, which inherits from RenderedObject, which also has a velocity and acceleration. And so on down the line for DestructibleObject (has HP), ShipObject (has weapons and such), and then finally my actual SimpleFighter, which has the actual stats for the specific ship. I also have a SimpleBullet that inherits from ProjectileObject, which itself inherits from MobileObject. So I think my main problem was just that I don't know the syntax for making a list of objects, or a list of lists for that matter.
[/quote]
This sounds quite overengineered for your self-described "simple game", where a ship shoots bullets (a lot of the solutions suggested are similarly complex, IMO). KISS and YAGNI are important principles to keep in mind. Maybe you're writing this game as a simple way to test a more complex "engine" that you are developing, in which case this class cluster might make a little more sense.


You need to define an abstract "GameObject" class that has Update() and Draw() virtual functions that have to be overloaded. You can also define position/orientation/scale stuff inside a game object class. Every object in your game (players, bullets, etc) needs to derive from the GameObject.
Emphasis added
[/quote]
It is perfectly possible to do this without such a class or design. I would recommend it as one starting point for simple games, but you certainly don't need to do these things. For some games, having a bunch of lists of concrete classes makes more sense and is actually simpler.


The object manager ....
[/quote]
Beware of "manager" classes. These are often poorly defined. The class that holds my game objects is usually called a "World" or similar. Functionality outside the scope of the world is moved to other classes.


Small tip. Rather than continually creating and destroying something like a bullet, create your objects at level load. Have a pool of bullets large enough to ensure that no one can hit space enough to fill the screen with all of them.
[/quote]
Object pooling is an optimisation, I wouldn't recommend it (yet) until you know you need it. It can add complexity to the object, because it makes it harder to enforce invariants. In particular, a Reset() function for complex objects can be an easy place for bugs to slip in.

That said, for languages with garbage collection it has a certain justification because it reduces the amount of collection pauses. This isn't the only solution - using a "structure of arrays" approach for frequently allocated and deallocated objects can combine this optimisation with better cache performance. It is something to consider anyway.


I generally store my game objects in lists, but usually thats just because I'm too lazy to write fixed array resizing code. Its more efficient to write one that works with fixed arrays (for static stuff that doesn't change often) and linked lists (for the dynamic stuff like those bullets, because things can be added to and removed from linked lists without re-sorting or re-sizing an array internally). If you don't know the differences between linked lists and array storage, I recomend you look into them!
[/quote]
C# has an extensive library of data structures. You do not need to write a fixed array class, that is what List<> is. A linked list is a... LinkedList<>.
The App Hubs well explained Shooter tutorial covers all of the concepts you have a problem with.You could download the source code and take a look.It covers bullets, explosions, lists of active bullets etcIt's quite good.
Let me give you a simple answer.

Have a list (STL, for example: http://www.cplusplus.com/reference/stl/list/) and, when you're ship produces a bullet, add the bullet object to the list. In your main update function, loop through the list, updating the location of the bullet, then draw it. When the bullet should be destroyed (either because it hit something, or it is off the screen), remove it form the list, and delete it.

Worry about optimizing later (if needed, which, I bet you won't need for a simple game). Be careful about removing an object from a list while your traversing it.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

First thing you must keep in mind is that XNA is NOT a game engine, this is a common misconception, while XNA is designed to be used in game development specifically, it is merely a wrapper of DirectX and most operative system interactions to get you a more comfortable starting point than you would have on a bare c++ project, its just yet another abstraction layer.

Second, while it is true that you should not concentrate on optimization during the initial stages of a project, specially a small one, simply adding and removing projectiles from a list when shot and when hit is not just a matter of optimization, its bad design, objects that get created and destroyed very often MUST be pooled, usually because of the mere cost of instanciation, initialization and destruction of the objects, but in an environment like XNA which uses a garbage collector its all that much worse, such a high frequency - short lifespan object creation will quickly trash even the simplest of games.

Given the rate of fire and the range of a given type of projectile it is possible to calculate the max number of projectiles that can exist at any given time coming from the same source, this source is most likely to live much longer than its projectiles, therefore it must pre-instanciate and initialize all projectiles and then just re-use the same ones over and over again.

As for managing the actors themselves (ships, asteroids, enemies), you should usually create some kind of manager in charge of the decisions of adding or removing actors to the world, L4D called this the Director, other games implement this in the World, or Level object, but it is important to have some centralized management of these types of object.

Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


This topic is closed to new replies.

Advertisement