views:

186

answers:

3

My question involves a simple game that 2-4 people can play. This is a game that is played on one iphone/ipod touch so no networking is required. When the game is started, the user will select the number of players that will play.

For each player I need to create and instance of the Player class. My question is how do I code so that only the required number of classes are made and they are all named differenly. I thought of the following but I know this won't work.

Assume I have an array named "playerNames" that stores the names of the players in the game.

for (int i = 0; i < [playerNames count]; i++) {

     Player *playeri = [[Player alloc] init];

     //other code

}

I can't just put "i" in there as the counter for the loop and get four instances out named player1, player2 etc. How do I do this?

Thanks in advance for your help.

+2  A: 

You can't create variable instances on the fly - you need a collection to store the resulting players. A C-array or NSMutableArray would work well. You can add this collection to your controller or view to have the players accessible through the game.

Also, you may want to use autorelease to automatically free the players or alternatively free the items in the collection in your dealloc method to avoid memory leaks.

Here's some code using an NSMutableArray that I've assumed you would add to your class interface (and initialized somewhere, typically in viewDidLoad)

-(void) CreatePlayers:(int)playerCount
{
  for( int i = 0; i < [playerNames count]; i++ )
  {
      [playersArray insertObject:[[[Player alloc] init] autorelease] 
                         atIndex:i];
  }
}
LBushkin
A: 

You can't exactly name your variables programmatically like that.

You can however create those objects and add them to an NSMutableArray, and then call them out later.

If you really want to associate a "PlayerN" name with each object, use an NSMutableDictionary. Store the player object as the value, for the key @"PlayerN" (an NSString).

Creating the key could be done like this:

NSString *key = [NSString stringWithFormat:@"Player%d", i];
jbrennan
A: 

The most basic solution for this would be to store the players in either an array or a dictionary (keyed on the player name). Taking the array approach:

// assume we have an NSArray property, players
NSMutableArray *tempPlayers = [NSMutableArray arrayWithCapacity:[playerNames count]];
for (NSString *name in playerNames) {
  Player *player = [[Player alloc] init];
  [tempPlayers addObject:player];
  [player release];
}
self.players = tempPlayers;

You can now access each player from the players property by calling objectAtIndex:.

A word on design - firstly, have you considered adding a name property to your Player class? This seems like a natural place to store this information after you've captured it. For example:

for (NSString *name in playerNames) {
  // you might also have a designated initializer
  // e.g. [[Player alloc] initWithName:name]

  Player *player = [[Player alloc] init];
  player.name = name;
  [tempPlayers addObject:player];
  [player release];
}

Overall this is the simplest thing that works and is all I would do for now. However, in the future...

At some point, you may find yourself introducing some kind of Game class that represents each new game your user creates. This would be a natural place to store your array of players and would allow you to build a more cohesive interface, for instance:

Game *newGame = [[Game alloc] init];
for(NSString *name) in playerNames) {
  [newGame addPlayerNamed:name];
}

Your Game class would encapsulate the array of players and the addPlayerNamed method would encapsulate the process of creating a new Player and storing it in that array, making your controller code much simpler (and intention-revealing) in the process.

Another benefit of this is it gives you a way of being able to access this data throughout your app rather than having it tied up in this particular controller. You could implement some kind of singleton-like access to a "currentGame". Not a true singleton of course, but something like this would work well:

Game *newGame = [[Game alloc init];
.. // configure game as above
[Game setCurrentGame:newGame];

So now, whenever you need access to current game (or player) information:

// in some other controller
Game *currentGame = [Game currentGame];
for(Player *player in currentGame.players) {
  // etc...
}
Luke Redpath