views:

46

answers:

4

Hi all - new to Obj C and programming in general - learned a lot from this site and really appreciate everyone's contributions.

My scenario is as follows (programming an iPhone game which explains the funny names)

In my main gameLoop (which is in my view controller) if a certain condition is met I create an enemy - the cherry bomb

if (bounceCounterGlobal % 2 == 0 && bounceCounterGlobal > 1 && cherryBombSwitch == 0){
    [self addCherryBomb];
}

The addCherryBomb method is as follows:

-(void) addCherryBomb{
    CherryBomb *myCherryBomb = [[CherryBomb alloc] init];
    [cherryBombArray insertObject:myCherryBomb atIndex:0];
    [myCherryBomb release];
    [[cherryBombArray objectAtIndex:0] initializeCherryBomb];
     [self.view addSubview:[[cherryBombArray objectAtIndex:0] cherryBombView]];
    cherryBombSwitch = 1;
}

The CherryBomb header file is short:

#import <Foundation/Foundation.h>
#import "SimpleGameViewController.h"

    @interface CherryBomb : NSObject {

        UIImageView *cherryBombView;
        NSTimer *cherryBombDetonateTimer;
        NSTimer *cherryBombMoveTimer;
    }

    @property (nonatomic, retain) UIView *cherryBombView;

    -(void) initializeCherryBomb;
    -(void) detonateCherryBomb;
    -(void) moveCherryBomb;

    @end

What I would like to do is when the cherry bomb detonates (which is determined within the cherryBomb object), I would like the object to remove itself from the cherryBombArray which is an ivar of the view controller.

I tried calling a view controller class method to do this - but I am unable to access ivars of the view controller (because it is a class method). I do not know how to communicate back to the view controller class to tell it to remove the exploded object.

@implementation CherryBomb
...
-(void) detonateCherryBomb{
    NSLog(@"KABOOM!");
    cherryBombDetonateTimer = nil;
    [cherryBombMoveTimer invalidate];
    [cherryBombView removeFromSuperview];
    //I would like to remove this object from the view controller's cherryBombArray
}
@end

Your help is greatly appreciated. Thank you in advance!

+1  A: 

I recommend you to create some "Environment" object that will handle all the gaming logic.

The cherryBomb shouldn't deal with its explosion. The cherryBomb can store many information (size of the explosion, type of explosion, and so on), but the effects of the cherryBomb on the others "things" (characters, bombs, whatever) shouldn't be calculated by the cherryBomb itself.

I'm not very used to game programming, but this aspect of architecture/design is common: each object/class has its responsibilities.

The cherryBomb represents a bomb, no more (and not the "graphic" aspect either).

The Environnement represents a "world" at current instant, and modelizes actions/interactions between the elements of the world.

There is a lot to say about the best way to design a game...

Anyway, to give your question an answer, you can still use "events". The bomb can send a message to your controller telling him: "I've exploded, remove me".

In the bomb:

[[NSNotificationCenter defaultCenter] postNotificationName:@"kaBOOM" 
                                                    object:self];

In the controller:

[NSNotificationCenter defaultCenter] addObserver:self
                                        selector:@selector(methodToCallWhenKaBOOM) 
                                            name:@"kaBOOM" 
                                          object:nil];

And

- (void)methodToCallWhenKaBOOM:(NSNotification *)note
{
    // do stuffs
}

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html

Francois B.
A: 

There are a number of ways to do this, and you may want to think about the exact division of labour here, in terms of controllers and models. Things can get pretty spaghettified if you have too much calling back and forth.

However, without getting into all of that, the basic thing you need to do to allow one object to access another object is to give the first a reference to the second.

In this case, you're actually creating the CherryBomb in the view controller, so it's easy to just pass it a reference at that point. Give your CherryBomb class another ivar like this:

SimpleGameViewController* cherryBombViewController;

Modify CherryBomb so that either the init method or your initializeCherryBomb one (these probably should just be a single method, btw) takes such a pointer and assigns it to the ivar:

- (void) initializeCherryBomb:(SimpleGameViewController*)vc
{
    // ... whatever other stuff you do in here, plus something like:
    cherryBombViewController = vc;
}

When you call this, pass it self as the vc parameter. Then later on, when your bomb detonates it can invoke some method you add on the controller to remove itself:

[cherryBombViewController handleDetonationOfCherryBomb:self];

Note that you absolutely should not access the controller's array directly -- that's an implementation detail your bomb should have no knowledge of. You can get away with being a little sloppy in your control structures in simple cases, but never screw with your encapsulation.

walkytalky
A: 

Read up on the MVC design pattern. If you find ivars which you need to share among views, they should probably go in a higher level Model object (the M of MVC), instead of having some view's peaking into other view's ivars. A pointer to this Model object can then be passed down to all the view objects that need to access it.

hotpaw2
A: 

I think this is a good application of key value observing. You need a property of the cherry bomb which represents its state e.g.

@property (assign) BOOL isExploded;

Any object that is interested in whether the cherry bomb has exploded registers itself for KVO on the isExploded property. For example the view controller might do:

[cherryBomb addObserver: self
             forKeyPath: @"isExploded"
                options: ....
                context: ....];

and in -observeValueForKeyPath:ofObject:change:context: for the view controller remove the cherry bomb from the array.

Your detonate method does the following as well as everything else it is currently doing:

[self setExploded: YES];
JeremyP