RTS game - Unit managment

Started by
11 comments, last by web_scripter 18 years, 9 months ago
Hello, i'm new to rts game development, but i'm trying to make a 3d space rts game. It's a cross between HomeWorld and Age Of Empires. I am using directx 9 and C# t make this game and I was wondering what is the best way to go with unit/building managment? How should i manage my units so that it will be quick and wont use lots of system resources, when i try to create, move, attack with lots of units? Thanks
Advertisement
Managers are great. use a map to store the data with the key(filename). If a requested item isn't in the map you load it, if it is, you return it. This consept applies to everything not just DX.
This article might also interest you...
Should i use an array to store all my units, then have another with the index of the units selected. Then when i move them i just have to go to each of them and tell them to go to a certain place. Then at each update of the game i update each unit's position. Or is there a better way of doing this?


Also what is the formula for movement. I mean right now i'm just using this code to move my unit. but it goes on a diagonal route then goes verticaly or horizontaly to the chosen position, instead of going strait to it.
bool t = false;if(m_x != m_destX){	if(m_x > m_destX)		m_x--;	else		m_x++;}else   t = true;if(m_y != m_destY){	if(m_y > m_destY)		m_y--;	else		m_y++;}else{	if(t)	{		Check();		return false;	}}Check();return false;
Quote:Original post by web_scripter
Should i use an array to store all my units, then have another with the index of the units selected. Then when i move them i just have to go to each of them and tell them to go to a certain place. Then at each update of the game i update each unit's position. Or is there a better way of doing this?


Thats one way, but consider if a unit dies or exceeds its life then likely you'll want to remove the unit from the array which likely means you either have to shuffle all the units and indexes around to close the gap in the array made by removing the unit or just leave the gap and find it later on when you want to add another unit. Both are not best options in my oppion.
You could use a linked list which gives better performance (especially when dealing with lots of units) at the expense of using a little more memory, this would be easy to code.
If your proficient with your language of choice (probably c++) you could use a technique known as pooling (google for it) which if done well can have good performance and minimal memory overhead.

Quote:Original post by web_scripter
Also what is the formula for movement. I mean right now i'm just using this code to move my unit. but it goes on a diagonal route then goes verticaly or horizontaly to the chosen position, instead of going strait to it.
*** Source Snippet Removed ***


Yes thats the expected behaviour of that code. You should be made aware of vectors. I don't know what graphics API you're using (or are you using a gfx lib that came with your compiler?) but most support translations along vectors.
The simple way to do this is to construct a vector from the unit position to the destination, normalize the vector, scale it by some amount and store it within the unit then just move the unit along that vector each frame until the destination is reached.

As a side note: If your not using a modern graphics API such as DirectX or OpenGL then I recommend you do. If your a beginner then opengl is easier to learn and supported on multiple platforms but if your on Windows then your PC may support DirectX better (so you could potentially create better graphics)
Pretty much the same way as you would do in any other game.

Use some sort of container and store your objects polymorphically (i.e. as subclasses of a common base class). Your manager can then call the methods en-masse as necessary.

Obviously if you haven't used such techniques before I'd recommend using them on a simpler game first (Not necessarily Pong, but something a bit more involved - with a larger number of things happening).

IMHO, your biggest problem will be giving the player enough control of the camera to get a decent picture of what's going on, without totally confusing them. This will be extremely difficult, as in space there aren't really any good reference points.

Also, most RTSs rely on ingenious use of the terrain to be fun - and in space, there isn't any - which is going to mean that you have to find new ways of handling the gameplay.

I'm not suggesting it can't be done, but just that it can't be done easily.

Mark
Thanks for the tips and suggestions.

The game is going to very similar to homeworld but instead of being only missions and just a fleet of ships. I want to add space stations and other things to make it more empire based.

Isn't a linked list the same as an arraylist in C#.
How would it help me to manage my units?

What type of pooling do i need, Object pooling or Thread pooling or are they the same thing?
Is pooling just a thing where i only need to create a unit once?
Will i have to create each unit and add it to the pool or will i only need to create one of each unit type?
Do you have some examples or tutorials on pooling, preferably in C#.

I'm also using C#, and the ObjectPooling attribute seems slow. Is there a better way of pooling in C#.

[Edited by - web_scripter on July 23, 2005 8:51:37 PM]
You are confused. You do not need to use Object Pooling or Thread Pooling, these are features of the CLR that you (probably) won't need.

What you do need, is to store everything in *some* sort of structure.

ArrayList is certainly one option. It stores things in an array internally, which is resized as necessary. This is normally fine, but if you're frequently adding / removing elements at arbitrary positions, it might be inefficient.

Anyway for the time being, yes, use ArrayList.

I think from your previous posts, that you are probably not ready to tackle a 3d space-based RTS yet (Apologies if you feel differently; ignore me if you like). Moreover, there are unresolved gameplay issues that you haven't addressed.

You need to understand Polymorphism (to do your object-management), and a certain amount of 3d geometry (then you'll see why you can't just increment the x coordinate to make something fly towards a point).

Mark
sorry but not every one can have a diploma in computer programming at 15. I'm only trying to get some things figured out so i can go to the next thing and then the next. Soon i will probably not know what to do and i will ask another question, or quit altogether and return to it when i do have a diploma.

What are some of the unresolved game issues that i need to address? I would apreciate the help. everyone has to start somewhere. and i choose to start here, since i've already started a tile based game, which is decent but not ready to be played. This is how i learned to program. I just wanted to make something and i asked around for what i needed to do. Now i am a pretty good programmer too, not proffesional but pretty good. I would think that my first year at university for computer science will be pretty strait forward.

Yah I appreciate any help that you can offer, since this is how i learn. What other issues do i need to address?

web_scripter, your approach is great if you have the potential to pull it off (Its how I learnt :)). The problem comes when you try to relate to other coders, for example im only guessing what pooling means ;)
(and I've got a BSc Honours in Computing *rolls eyes*)

So im guessing it means keeping a 'default' version of each of your unit types in memory, so when the player creates a new unit, you can get the stats for that unit from memory, instead of read a file on your harddrive with the stats in it.

So..
Say you have 3 different ships that you store on file (hard disk), you can use a default pool to store the stats to stop loading the files all the time.
This would need a container of sorts (array, linked list etc) to store each type of ship, plus a way of adding/finding types (don't really need remove..)
The ArrayList may have everything you need, but if it doesn't - you can build an class around the ArrayList that could also deal with loading the data/parsing it from the file.
If you didn't use a pool, you'd need to read and parse the file every time a new unit was created (else you wouldn't know its speed etc).
You could also hard code the ship stats into the code itself - but when you start getting lots of ships/units etc it becomes a right bitch to edit / maintain and tweak (for balance issues or whatever).
IMO you want the container for the default pool to allow 'random access' - that is, if you know the index (key, placement, whatever) of the data you want in the container, you can get it straight away.
For example, if you know that your ship's type is #2 in a normal array (Ship shipDefaults = new Ship[3]), you can just do
Ship newship = shipDefaults[2];
(or the equivilent in your chosen language)
when a player builds a new ship.

[Added:]It should be noted that you only need to load 1 instance of each type of ship as well - so if for some example it tried to load a "cruiser" ship type twice, it realises that it has already loaded that ship - a 'map' (rather then an array) is good for that..

Random Access is good, because I can't really think of a reason in the middle of a battle that you'd want to iterate through every object in the array.

Of course, I could be way off with the pooling idea.. but meh..

The default pool is completely seperate from the list of units that each player has under their control. This is because each ship will have a different location on the battlefield, amount of shields / hull left, conditional modifiers etc. Each individual ship would have a shipType which would point to the defaultShip array.
Now you could keep all the data for each ship type in the individual ship object (so each ship would nativelly how many maxHPs, maxShields, maxSpeed it can have (as well as its currentHPs, currentShields, currentVelocity etc). This would increase the amount of memory required per ships.
Or when you need to check the ships type, you can just refrence it from the default pool. For example, you increase the speed at which a unit is moving, then do:
if(currentVelocity > shipDefaults[shipType].maxSpeed)
currentVelocity = shipDefaults[shipType].maxSpeed;

[ADDED:] This isn't just for unit variables, but can be used to control their resources (like models, animations etc). The default pool has the model and animation for the ship type, the individual ships have current animation data (which one they are playing, how many frames they are into it or whatever).

As for actually storing these ships into memory, a linked-list would be good if you cycle (iterate) through the ships to update them. But would suck if you tried to do a "I killed your ship#32" scenario since you can't randomly access them (you would have to cycle through the first 31 ships to get to that one). So how to store them would really depend on how you code the rest of the game.

When it comes to actually selecting and giving orders, keeping an array (or list whatever) of which units you have selected is a good approach when you're using a container with random access for the individual units - you can just have an ID of which ones you have selected.
If you have a linked list container (or non-random access) you can use pointers instead of IDs to locations in the container.
Depending on how much you know about pointers and references (I've noticed alot of beginners miss these out?) you can use pointers with random-access anyway.



As for your movement problems... well I cant help there because my math skills suck (and I have someone else to do the maths bit - I just convert it into code).




Thats how I do things anyway, others might have different opinions.

Im ramberling..
Roger that, lets run like hell!
Pooling is a technique that allows for fast and efficient aquisition and release of memory.
Initially a pool of memory is allocated once, when you want to create an object (as you would usually do with the 'new' keyword) rather than allocating more memory you simply get a pointer to a location within the pool. When you delete and object rather than actually de-allocating memory it is simply released back to the pool.
When the pool is full a new pool is created. The idea is to reduce the number of memory calls.

The technique that Interesting Dave is describing is the 'prototype pattern' a design pattern that you may also want to consider.
Dave also made the point that you can design a system where-by an array is a better container becuase it offers random-access where-as a linked-list doesn't but a linked-list is more suited to continuous resizing from things spawning and dying (but an array isnt).

Another thing you may want to consider is the ever-popular scene-graph which can help with relating object together (eg gun->hand->arm->body->person->room->building->planet)

There's nothing wrong with being 15 (I'm 16 myself [smile]) but don't be under the impression that everyone else here has qualifications.

Realistically: what chance do you think you have of making a completed game comparable to a comercial (team built) product? On the other hand I think that it would be a valuable learning experience to prepare you for later life/tasks.
I think you should be viewing this as more of a learning exercise so when you run into a bump rather than give up - try and solve it, remember how you did it and think about how you can generalise the problem/solution for a wider set of typical programming problems.

Last but not least there are a set of common solutions to common programming problems that every programmer should at least be aware of. These are called design patterns. They can be applied to a large set of problems and often when you find yourself pondering on the best design for something there is already a general well-known solution that already exists.

Hope that helps [smile].

This topic is closed to new replies.

Advertisement