I’m having trouble with Objective C.
I’m trying to call a block after I’ve moved a sprite
The short version of what i’m trying to achieve is that i want to move all of the enemies in an array, and when each one finishes moving i want to check whether it has collided.
The simplified code below shows what i’m trying to do.
My Actor class is defined like this
// -----------------------------
// Actor.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "ScreenObject.h"
typedef void (^actorMoveComplete)(void);
@interface Actor : ScreenObject
{
// actorMoveComplete onMoveComplete;
}
@property (nonatomic) BOOL isMoving;
@property (readwrite, copy) actorMoveComplete onMoveComplete;
@property (nonatomic, retain) CCSprite* sprite;
-(void) moveTo:(CGPoint)targetPosition Speed:(float) speed withCallback:(actorMoveComplete)moveComplete;
@end
// -----------------------------
// Actor.m
#import "Actor.h"
@implementation Actor
@synthesize onMoveComplete;
@synthesize sprite;
-(void) moveTo:(CGPoint)targetPosition Speed:(float) speed withCallback:(actorMoveComplete)moveComplete;
{
onMoveComplete = moveComplete;
id actionMove = [CCMoveTo actionWithDuration:speed position:targetPosition];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)];
[super.sprite runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
-(void) spriteMoveFinished:(id) sender
{
isMoving = NO;
if (onMoveComplete != nil)
onMoveComplete();
}
@end
As you can see i’m trying to store the block in an onMoveComplete parameter (i’ve also tried it in a private variable), and then call it once the sprite move has completed.
In my calling class i’m iterating through a bunch of actors (enemies) and i want to call this anonymous code block for each actor once the move has completed:
{
[self checkForCollision:enemy];
}
My calling class looks like this.
//------------------------------
//
// GameLayer.h
#import "cocos2d.h"
#import "Actor.h"
@interface GameLayer : CCLayerColor
{
}
@property (nonatomic, copy) NSMutableArray *enemies;
- (void) updateEnemies;
- (void) checkForCollision:(Actor*)actor;
- (BOOL) isMapGridClear:(CGPoint)mapGrid excludeActor:(Actor*)actor;
@end
//------------------------------
// GameLayer.m
#import "GameLayer.h"
@implementation GameLayer
@synthesize enemies;
- (void) updateEnemies
{
for (Actor *enemy in enemies)
{
//
CGPoint newPosition = [self getNewPosition:enemy]; /* method to figure out new position */
[enemy moveDelta:ccp(dX, dY) Speed:enemySpeed withCallback:^{
[self checkForCollision:enemy];
}];
}
}
- (void) checkForCollision:(Actor*)actor
{
if (![self isMapGridClear:actor.gridPosition excludeActor:actor])
{
actor.isCrashed=YES;
[actor loadSprite:self spriteImage:@"crashed.png"];
}
}
- (BOOL) isMapGridClear:(CGPoint)mapGrid excludeActor:(Actor*)actor
{
/* Actual method figures out if there was a collision */
return YES;
}
@end
Unfortunately when I call the onMoveComplete block, i keep getting an EXC_BAD_ACCESS error
Interestingly, if I try to call the block inside the moveTo method, it works (but of course i want this to trigger AFTER the movement has completed).
Can anyone help me with what i’m doing wrong. Am I even using the correct mechanism?
(Apologies for the poorly formatted, incomplete code segments)
You correctly declared your property as copy, but you are setting your instance variable directly to the address of the block without using the generated accessors. That means the block won’t get copied and gets destroyed before it is called.
Assign your block using
self.onMoveCompleted = moveCompletedand you will be fine.