views:

220

answers:

6

Hi guyz,

I'm starting a game project, my first, it'll be like a civilization clone, with a big focus in war. I always worked with C# but for business apps (mostly web apps) so I have a doubt about what would be a good design to build the map positioning system.

I would like to each unit know where it's positioned, and to the map to know all units at each point, a two-way relationship, but I can't see what would be the best way to model this! I'd like some ideas and pseudo-code, if you could!

Thankz.

+2  A: 

Make your map a two-dimensional array. At each position, put an array of all objects at that position. In addition, add position attributes to each object.

Yes, this will duplicate the information! So on each move you'll have to change the object and update the map.

However, fast reading and fast finding of the objects is very important for that kind of game. In addition, this solution avoids any search routine (e.g. go through the map and look for a particular object), which is generally a good idea: Replace all search routines over large datasets with indexes. The map should be seen as some kind of index over the object's position attributes.

vog
But should I say to some unit to move and let it update the map?
Alaor
Yes, of course! This way, the updating code is cleanly at one place.
vog
It's a turn based game, speed really isn't a factor. Unless he has 10000's of game objects, which he won't - splitting the units into an array-per-player is more than enough.
Sneakyness
It's also worth mentioning that the updating code should be clean and in one place regardless of what method you choose.
Sneakyness
+2  A: 

The map should have all knowledge of all object on it. Furthermore, only each object on the map should know its location. This way, the map can ask all objects where they are and place them in their correct locations. You should never have to store the positioning information twice.

AlbertoPL
"You should never have to store the positioning information twice" ... this is an extreme point of view which I do not recommend. I neither simplifies the code nor makes it faster.
vog
It HIGHLY simplifies the code. Having to keep track of something twice is simply absurd, especially if you forget to update it in two places. An observer type pattern here, where the map observes its objects, is far preferred over duplication of data variables.
AlbertoPL
I think that to draw the scene the map must know which units are in some area, it'll make easy to drwae the screen, and to move the units they must know where they are and where they are going from, so I think I need to store it twice, I know it's error prone but it will make dev a lot easier, I need a pattern or ex code of a ellegant way to do this.
Alaor
"Having to keep track of something twice is simply absurd" ... this is again too extreme. Having to perform search operations is additional work as well. And it's usually more work than simply updating an index. Updating the index is _not_ prone to errors when you do that directly within the "changePosition()" or "move()" method of the object. In other words: Updating an index should be done at _one_ place, that's all.
vog
See PaulG's answer. He's doing exactly what I recommend. Storing the same information in two different places is a pretty bad violation of DRY, and completely unnecessary with an observer-subscriber pattern.
AlbertoPL
DRY means: do not repeat yourself in code. And yes, the index updating code should be in _one_ place. DRY doesn't say anything about the data. In fact, storing data more than once is the key of any fast data access method. Every database does that.
vog
That top answer has nothing to do with storing information twice. It doesn't store any information in two places.
AlbertoPL
+1  A: 

Here's one approach that should avoid duplication

Have a class which holds all objects on the map, and within it collections of different types of object

public class MapObjects
{
   private Collection<GamePiece> gamePieces;
}

Each item in the collections will hold its (current) map co-ordinates

public class GamePiece
{
   private MapCoordinate mapCoordinate;
   // Other items relevant to a GamePiece.. Health, ItemType, etc
}

To find where a particular selected item is on the map should be easy, you have a reference to the GamePiece which holds its coordinates. To find what items are in a particular coordinate you need a helper method, probably within the MapObjects class:

public class MapObjects
{
   public Collection<GamePiece> GamePiecesAtLocation(MapCoordinate mapCoordinate)
   {
      // Iterate through gamePieces collection and build a result 
      // collection of items at specified coordinates.
   }
}

Good luck, sounds like an interesting project with plenty of challenges.

PaulG
Is that really better than simply updating the map after each GamePiece.move()? The MapObjects variant seems to be slower and to need more code.
vog
Thankz man, that was helpfull. I thought about this approach but I got a question: yes, it's nice if we have a big map and some pieces, but what if changed the proportion, a map with a lot of units, changing the responsibility of storing the positioning information should save some time? But now I think I did miss the point, no way of having that much units to a map, even in busy games would be better to the units know where they are.
Alaor
A: 

I would make the map hexagonal instead of a grid, so you don't have the odd Civilization phenomenon where you can cover more ground diagonally. Beyond that, I would just have each unit store its own position, and when you need to know which units are in a particular hex just iterate through the whole collection. It's hard to imagine having so many units involved that this approach would be a performance problem.

MusiGenesis
A hexagonal grid is usually also just a two-dimensional array. :-) ... with some coordinates left unused.
vog
MusiGensis! fancy seeing you here. I would suggest having an array of units for each player. See my answer below about the unexpected complexities of writing things like this.
Sneakyness
@Sneaky: where else would I be on a beautiful Sunday afternoon? Out enjoying the world?
MusiGenesis
A: 

NSPoint is extremely useful when it comes to things like this. Each gameobject should have it's own location. You could store these gameobjects in arrays, one for each player, one for the whole game, it's up to you.

I will warn you that this is a huge project, not only codewise, but content wise, and requires lots of back and forth work while balancing the game. You should really try a few smaller games before you go after this one. Nothing is stopping you from diving in, but you are going to hit a lot of walls and write some serious spaghetticode if your first game is something this large. I would suggest starting with something like checkers, to get the turn based side of things down.

This is all coming from the guy who is currently writing a roguelike as his first game project. In my defense it is relatively straightforward, but there are a lot of things I was not expecting, and something as simple as calculating the sight / fog of war taking obstructions into account uses complex algorithms. I don't regret picking a roguelike as my first game, but after seeing how complex even the most basic concepts can be to implement, something like a turn based strategy game is simply something I'll leave to the pros for now.

If you're currently having trouble thinking of a way to not only create the units, but represent the map and store the locations, what are you going to do when it comes time to code in research? cities? production? resource gathering? A random map generator? Trajectory calculation? Hit probability? Armor? Mobility? Line of sight? Random events? AI?

I'm not trying to crush your dreams by any means, it's just that the genre you picked is more complex than it seems. Your brain will overload and burst at the seams. (I could continue rhyming on topic, but I will refrain to remind you that you should really try something like checkers first.)

Sneakyness
Checkers? Maybe he could start with tic-tac-toe. :)
MusiGenesis
Honestly is not a bad idea. Don't just try to make the game, though. Add your own twist, change things around.
Sneakyness
Hi there! Thankz for the reply, and I agree 100% with you. I know it's gonna be huge and hard, but it's not a goal to be commercial yet, it's part of a final project in my grad and I have a team with me that will work with other stuff, like graphs, audio, etc. The gameplay is alread planned, things like cities, production formulas and etc, how it work in general, all this was thought before starting coding. Like the coding will be my responsibility, I started modelings entities like cities, nations, units and I made a positioning system, I just wanted to know if I'm in the right way.
Alaor
The plan actually is to use most of the knowledge we got in the course, AI, OO, etc...
Alaor
I personally don't even touch anything gameobject related until I have the basics in place. If you've never made _any_ games before, you really are better off writing something extremely small, like Tic Tac Toe, or Checkers, just to make all the simple mistakes there and gain an understanding of what you're going to have to do for this project. Especially if it's a final project for school. Walk before you run.
Sneakyness
Well, I did two little games when reading books about XNA, but there are guided projects, when I said it's my first game is because it's the first on my own, from scratch, I did some games by following book examples, so I think I have some base to starting walking with my own legs.
Alaor
A: 

Good design = simple design.

Make the map a list of objects.

Object
    int X { get; set; }
    int Y { get; set; }

Map
    List<Object> objects
    Add(Object)
    Remove(Object)
    GetAt(X, Y)
    GetInBox(X,Y,Width,Height)
    GetInRadius(X,Y,Radius)

That should be all you need. If the Get(..) queries get too slow, add caching or divide the map into sectors and keep a list of objects for each sector and update it when they move. This helps dramatically if you have many static objects or objects that don't move too quickly from sector to sector. My guess is that in a turn-based game, you won't need to optimize at all.

TomA
NSPoint, NSRect, and NSRange replace half of what you wrote. No need to reinvent the wheel. :)
Sneakyness
I think it is good to explain how a wheel works first, then look for an existing implementation. Also, NSPoint may not be available in every language and/or platform.
TomA