1

So I'm at the point where I'm starting to reduce my spaghetti code down.

So right now, I have 11 different dinosaur images that I've put into an NSMutableArray using a "for" loop. I've also declared CCSprite instance variables in which I was hoping I can set each dinosaur image to so that I can check bounding boxes, set positions, etc. So I pointed each object from the array to an instance variable So far, I have this code:

.h file:

CCSprite *dinosaur1_c;
CCSprite *dinosaur2_c;
CCSprite *dinosaur3_c;
CCSprite *dinosaur4_c;
CCSprite *dinosaur5_c;
CCSprite *dinosaur6_c;
CCSprite *dinosaur7_c;
CCSprite *dinosaur8_c;
CCSprite *dinosaur9_c;
CCSprite *dinosaur10_c;
CCSprite *dinosaur11_c;

.m file

NSMutableArray *dinoSprites = [[NSMutableArray alloc] init];

for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
    id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"dinosaur%d-c.png", i]];
    [dinoSprites addObject:dino];
    [sceneSpriteBatchNode addChild:dino];
}


dinosaur1_c = (CCSprite *)[dinoSprites objectAtIndex:0];
dinosaur2_c = (CCSprite *)[dinoSprites objectAtIndex:1];
dinosaur3_c = (CCSprite *)[dinoSprites objectAtIndex:2];
dinosaur4_c = (CCSprite *)[dinoSprites objectAtIndex:3];
dinosaur5_c = (CCSprite *)[dinoSprites objectAtIndex:4];
dinosaur6_c = (CCSprite *)[dinoSprites objectAtIndex:5];
dinosaur7_c = (CCSprite *)[dinoSprites objectAtIndex:6];
dinosaur8_c = (CCSprite *)[dinoSprites objectAtIndex:7];
dinosaur9_c = (CCSprite *)[dinoSprites objectAtIndex:8];
dinosaur10_c = (CCSprite *)[dinoSprites objectAtIndex:9];
dinosaur11_c = (CCSprite *)[dinoSprites objectAtIndex:10];

This bit of code does work, but I'm sure it can be reduced. How would I be able to set each of these instance variables using the "for" loop?

I'm using these instance variables in other methods to set positions, check collisions/intersects, fade ins, etc.

I put an equivalent-code to better explain what I'm trying to do:

NSMutableArray *dinoSprites = [[NSMutableArray alloc] init];

for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
    id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"dinosaur%d-c.png", i]];
    [dinoSprites addObject:dino];
    [sceneSpriteBatchNode addChild:dino];

    // Set instance variables
    dinosaur%i_c = (CCSprite *)[dinoSprites objectAtIndex:j];
}

Is there a way to achieve what I am asking? After 2.5 hours of searching, I still have come up with nothing. Just finding solutions for animation frames.

Am I missing something small or should I have a different way to point to each image in the array to set their positions, fade ins, check bounding boxes, etc?

Any ideas / inputs are greatly appreciated!! Thanks for taking the time to read this! :D

1
  • use array of CCSprites instead of different variables.. Commented Mar 6, 2012 at 10:53

2 Answers 2

3

Instead of having eleven CCSprite instance variables, you should just have one NSArray.

So in your .h:

@property (strong) NSArray *dinoSprites;

In your .m, do a

@synthesize dinoSprites;

and then replace the code from your question with:

NSMutableArray *newDinoSprites = [[NSMutableArray alloc] init];

for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
    id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"dinosaur%d-c.png", i]];
    [newDinoSprites addObject:dino];
    [sceneSpriteBatchNode addChild:dino];
}

self.dinoSprites = [newDinoSprites copy];

And then, whenever you need to refer to what you used to call, say, dinosaur8_c you would instead just use (CCSprite *)[dinoSprites objectAtIndex:7].

Sign up to request clarification or add additional context in comments.

2 Comments

Wow that was a quick response!! I barely just finished brushing my teeth when you responded. I just tried this out and it worked!! Thank you!! I had no idea that (CCSprite *)[dinoSprites objectAtIndex:0] would still work for setting positions, checking interects, etc. Again, thank you so much!!
You have no idea how much this helps me. Thank you again!
2

Is there a way to achieve what I am asking? After 2.5 hours of searching, I still have come up with nothing. Just finding solutions for animation frames.

You seem to want a variable whose value is another variable, so that you can iterate over a set of ivars. I can think of two ways to do something like what you're asking.

The first way is to use the address of each variable, i.e. a pointer to each variable. Since pointers themselves are scalar values, not objects, you'd need to use a C-style array:

CCSprite *ivars[] = {&dinosaur1_c, &dinosaur2_c, &dinosaur3_c, &dinosaur4_c};
for (int i = 0; i < 4; i++) {
    *(ivars[i]) = [dinoSprites objectAtIndex:i];
}

The second way is to use key value coding. Construct the name of each ivar as a string, and then use that as the key in a call to -setValue:forKey: like this:

NSString *name;
for (int i = 0; i < [dinoSprites count]; i++) {
    name = [NSString stringWithFormat:@"dinosaur%d_c", i];
    [self setValue:[dinoSprites objectAtIndex:i] forKey:name];
}

All that said, I'd strongly encourage you to not take either of the preceding two approaches to your problem. It's very likely that there are much better solutions to your problem that don't involve having a separate ivar for each dinosaur. You've already got the dinosaurs in an array, so there's no need to create a separate ivar for each. As a general rule, if you ever find yourself creating numbered variables like this, you should probably step back and rethink what you're doing -- numbering your variables is a strong signal that you should be using an array instead.

So, in your case, I don't see any reason that you couldn't use the array you already have everywhere in your code. Instead of dinosaur6_c, you can obviously use [dinoSprites objectAtIndex:6]. But you'll really clean up your code if you think of ways to treat all the dinosaurs with the same code, so that you're never hard-coding specific indicies into your array. For example, if you need to set each dinosaur to a different position, there are at least two good ways to go about it. One is to compute the position, if possible, based on the index. You can do this if you're laying out the dinosaurs in a regular way, like on a 3 x n grid:

for (int i = 0; i < [dinoSprites count]; i++) {
    int row = i / DINOS_PER_ROW;
    int column = i % DINOS_PER_ROW;
    CGPoint position = CGPointMake(row * rowHeight, column * columnWidth);
    [[dinoSprites objectAtIndex:i] setPosition:position];
}

If the position of each dinosaur isn't computable from its index in the array, then you're probably currently hard-coding the positions in your code. You can clean that up by at least moving the positions to an array, and perhaps by reading that array in from a data file. That will make your code much shorter, easier to understand, and easier to maintain:

NSArray *positions = [NSArray arrayWithContentsOfURL:someURL]; // read positions from a property list
NSAssert([positions count] >= [dinoSprites count], @"Not enough positions!");
for (int i = 0; i < [dinoSprites count]; i++) {
    CGPoint position = [[positions objectAtIndex:i] pointValue];
    [[dinoSprites objectAtIndex:i] setPosition: position;
}

Of course, I'm just using the position of the sprite here as an example. You can do exactly the same thing with any attribute that you'd want to apply to a dinosaur, and you can even do them all at once. Instead of a positions array that you load from a property list, you could load an array of dictionaries, where each dictionary contains a number of attributes (color, favorite food, speed, hunger level, etc.).

2 Comments

Very good points you have here. These ideas definitely would help me clean up my code. Also, the positions of these dinosaurs are not symmetrical or on a grid. They are placed according to the background that was given to me. I don't want to bug you about details of these methods you've mentioned. Is there a tutorial / link that explains these ideas you are mentioning in more detail? Things like using plists, data files, arrays, etc to store object information and how to link them together? Thanks for your wonderful input. :D
@rizzlerazzle You might start with Apple's Property List Programming Guide. More generally, the idea of factoring out the common part of any operation (like setting the position of a dinosaur) and turning the changeable part into data is a fundamental concept in programming. I don't know that you'll find any tutorials on that, but it's the reason that every programming language supports features like loops, functions, and data structures.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.