Advanced Spritesheeting - using a spritesheet in multiple classes - cocos2d-iphone

So after taking a little break after being very frustrated for months on end with this issue, I am now back and attempting to solve my issue once and for all.
I’m not going to post code, because the code I have is messy and patchy and is from countless points of view.
My issue is this:
I have a sprite, and his information is stored in a class called player.m. I have a game level, and it is stored in GameLevelLayer.m
I have player.m store velocity, direction, and all the information about the character, and then I have the GameLevelLayer.m implement, move, use bounds to check collisions, etc.
I now want to make the character move using a spritesheet (I know how to do spritesheeting, I just don’t know how to do it while working with two different classes)
My question is, do I create the batchnodes and spritesheet information (CCBatchnodes, caches, etc) and all of the actions and everything in player.m, and then run them in GameLevelLayer.m? Or do I create all that in GameLevelLayer.m
I really need some help here because I’ve been stuck on this for months
EDIT:
Here is where I am, thanks to a suggestion from a community member.
This is my entire player.m (Long story short, I define everything about the player 'you might just want to pay attention to the init, because that seems to be the problem. The other stuff is my physics engine')
#import "Player.h"
#import "SimpleAudioEngine.h"
#import "GameLevelLayer.h"
#implementation Player
#synthesize velocity = _velocity;
#synthesize desiredPosition = _desiredPosition;
#synthesize onGround = _onGround;
#synthesize forwardMarch = _forwardMarch, mightAsWellJump = _mightAsWellJump, isGoingLeft = _isGoingLeft;
#synthesize WalkAction = _WalkAction;
#synthesize isMoving = _isMoving;
-(id)initWithTexture:(CCTexture2D *)texture{
if (self = [super init]) {
self.velocity = ccp(0.0, 0.0);
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"BankerSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"BankerSpriteSheet_default.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"banker%d.png", i]]];
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
self = [super initWithSpriteFrameName:#"banker1.png"];
self.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
//[_Banker runAction:_WalkAction];
[spriteSheet addChild:self];
[[CCAnimationCache sharedAnimationCache] addAnimation:walkAnim name:#"walkAnim"];
}
}
return self;
}
-(void)update:(ccTime)dt {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
CGPoint jumpForce = ccp(0.0, 310.0);
float jumpCutoff = 150.0;
if (self.mightAsWellJump && self.onGround) {
self.velocity = ccpAdd(self.velocity, jumpForce);
if (![defaults boolForKey:#"All Muted"]) {
if (![defaults boolForKey:#"SFX Muted"]) {
[[SimpleAudioEngine sharedEngine] playEffect:#"jump.wav"];
}
}
} else if (!self.mightAsWellJump && self.velocity.y > jumpCutoff) {
self.velocity = ccp(self.velocity.x, jumpCutoff);
}
CGPoint gravity = ccp(0.0, -450.0);
CGPoint gravityStep = ccpMult(gravity, dt);
CGPoint forwardMove = ccp(800.0, 0.0);
CGPoint forwardStep = ccpMult(forwardMove, dt);
self.velocity = ccp(self.velocity.x * 0.90, self.velocity.y); //2
if (self.forwardMarch) {
self.velocity = ccpAdd(self.velocity, forwardStep);
if (!self.isMoving) {
//[self runAction: _WalkAction];
//self.isMoving = YES;
}
} //3
CGPoint minMovement = ccp(0.0, -450.0);
CGPoint maxMovement = ccp(120.0, 250.0);
self.velocity = ccpClamp(self.velocity, minMovement, maxMovement);
self.velocity = ccpAdd(self.velocity, gravityStep);
CGPoint stepVelocity = ccpMult(self.velocity, dt);
if (!self.isGoingLeft) {
self.desiredPosition = ccpAdd(self.position, stepVelocity);
}else{
self.desiredPosition = ccp(self.position.x-stepVelocity.x, self.position.y+stepVelocity.y);
}
}
-(CGRect)collisionBoundingBox {
CGRect collisionBox = CGRectInset(self.boundingBox, 3, 0);
//CGRect collisionBox = self.boundingBox;
//collisionBox = CGRectOffset(collisionBox, 0, -2);
CGPoint diff = ccpSub(self.desiredPosition, self.position);
CGRect returnBoundingBox = CGRectOffset(collisionBox, diff.x, diff.y);
return returnBoundingBox;
}
#end
So now the issue is, how do i get the player to appear in the game like a normal sprite, and then how do I run the animations when the player begins to move forward

Your game architecture is very good! Keep player properties on player and use GameLayer only to send player actions is the best approach.
If your Player Class extends from CCSprite, put everithing related to player in your Player Class: Run animations on it, load the cache on player constructor (use the CCSprite initWithTexture:rect:rotated: or a custom autorelease constructor, like a +(id)player ).
Then, in your GameLevelLayer you will need a CCSpriteBatchNode to add your player to it. You can use this batch node to add other objects that use same spritesheet.
EDIT:
Reviewing your code, your initWithTexture is wrong. The correct is to call [super initWithTexture:]:
-(id)initWithTexture:(CCTexture2D *)texture{
if (self = [super initWithTexture:texture]) {
Then, in your GameLevelLayer, create your player and add it to a CCSpriteBatchNode:
// *** In GameLevelLayer.m ***
// Create player
Player *player = [Player spriteWithFile:#"player.png"];
// Create batch node
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithTexture:player.texture];
// Add batch node as child
[self addChild:batchNode];
// Add player as batch node's child
[batchNode addChild:player];
// Set player position
player.position = ccp(100,100);
Your GameLevelLayer needs to do only this to create your Player. And when it detects user input, call methods like "jump", "moveRight", "moveLeft" in your player. Also detect collisions and send actions to player like "die", "getSpecialItem".
// *** In GameLevelLayer.m ***
[player jump];
[player die];
So, your player needs to handle these methods and performs its own logic to do the actions:
// *** In Player.m ***
- (void)moveRight
{
self.position = ccpAdd(self.position, ccp(10,0));
}

Related

How to build Physics Body using Different sprites in spritebuilder

I just started using SpriteBuilder with cocos2d - v3.
It looks promising and a good tool to have.
But my issue is that I want to create a man like character with all body parts as different sprites and put them into a Physics body using joints. I am struggling to find any example of it using spritebuilder or chipmunk.
Will greatly appreciate any help here. Thx in advance.
EDIT : Here's code for body. I used peevedpenquin example from link
Here is my code for character body. I just added a block as body part to penguin's tail.
#import "PenguinWithBlock.h"
#implementation PenguinWithBlock{
CCNode *_pBlock;
CCNode *_penguinB;
CCPhysicsJoint *_penguinJoint;
CCPhysicsNode *_penguinNode;
}
- (void)didLoadFromCCB {
_penguinNode.debugDraw = TRUE;
[_pBlock.physicsBody setCollisionGroup:_penguinB];
[_penguinB.physicsBody setCollisionGroup:_penguinB];
// create a joint to connect the catapult arm with the catapult
_penguinJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_penguinB.physicsBody bodyB:_pBlock.physicsBody anchorA:_penguinB.anchorPointInPoints];
}
This is Gameplay.m file
#implementation Gameplay {
CCPhysicsNode *_physicsNode;
CCNode *_catapultArm;
CCNode *_catapult;
CCNode *_levelNode;
CCNode *_contentNode;
CCPhysicsJoint *_catapultJoint;
CCNode *_pullbackNode;
CCPhysicsJoint *_pullbackJoint;
CCNode *_mouseJointNode;
CCPhysicsJoint *_mouseJoint;
PenguinWithBlock *_currentPenguin;
CCPhysicsJoint *_penguinCatapultJoint;
CCAction *_followPenguin;
}
// is called when CCB file has completed loading
- (void)didLoadFromCCB {
// tell this scene to accept touches
self.userInteractionEnabled = TRUE;
_physicsNode.collisionDelegate = self;
CCScene *level = [CCBReader loadAsScene:#"Levels/Level1"];
[_levelNode addChild:level];
// visualize physics bodies & joints
//_physicsNode.debugDraw = TRUE;
// catapultArm and catapult shall not collide
[_catapultArm.physicsBody setCollisionGroup:_catapult];
[_catapult.physicsBody setCollisionGroup:_catapult];
// create a joint to connect the catapult arm with the catapult
_catapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_catapultArm.physicsBody bodyB:_catapult.physicsBody anchorA:_catapultArm.anchorPointInPoints];
// nothing shall collide with our invisible nodes
_pullbackNode.physicsBody.collisionMask = #[];
// create a spring joint for bringing arm in upright position and snapping back when player shoots
_pullbackJoint = [CCPhysicsJoint connectedSpringJointWithBodyA:_pullbackNode.physicsBody bodyB:_catapultArm.physicsBody anchorA:ccp(0, 0) anchorB:ccp(34, 138) restLength:60.f stiffness:500.f damping:40.f];
_mouseJointNode.physicsBody.collisionMask = #[];
}
- (void)update:(CCTime)delta
{
if (_currentPenguin.launched) {
// if speed is below minimum speed, assume this attempt is over
if (ccpLength(_currentPenguin.physicsBody.velocity) < MIN_SPEED){
[self nextAttempt];
return;
}
int xMin = _currentPenguin.boundingBox.origin.x;
if (xMin < self.boundingBox.origin.x) {
[self nextAttempt];
return;
}
int xMax = xMin + _currentPenguin.boundingBox.size.width;
if (xMax > (self.boundingBox.origin.x + self.boundingBox.size.width)) {
[self nextAttempt];
return;
}
}
}
- (void)nextAttempt {
_currentPenguin = nil;
[_contentNode stopAction:_followPenguin];
CCActionMoveTo *actionMoveTo = [CCActionMoveTo actionWithDuration:1.f position:ccp(0, 0)];
[_contentNode runAction:actionMoveTo];
}
// called on every touch in this scene
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInNode:_contentNode];
// start catapult dragging when a touch inside of the catapult arm occurs
if (CGRectContainsPoint([_catapultArm boundingBox], touchLocation))
{
// move the mouseJointNode to the touch position
_mouseJointNode.position = touchLocation;
// setup a spring joint between the mouseJointNode and the catapultArm
_mouseJoint = [CCPhysicsJoint connectedSpringJointWithBodyA:_mouseJointNode.physicsBody bodyB:_catapultArm.physicsBody anchorA:ccp(0, 0) anchorB:ccp(34, 138) restLength:0.f stiffness:3000.f damping:150.f];
// create a penguin from the ccb-file
_currentPenguin = (PenguinWithBlock*)[CCBReader load:#"PenguinWithBlock"];
// initially position it on the scoop. 34,138 is the position in the node space of the _catapultArm
CGPoint penguinPosition = [_catapultArm convertToWorldSpace:ccp(34, 138)];
// transform the world position to the node space to which the penguin will be added (_physicsNode)
_currentPenguin.position = [_physicsNode convertToNodeSpace:penguinPosition];
// add it to the physics world
[_physicsNode addChild:_currentPenguin];
// we don't want the penguin to rotate in the scoop
_currentPenguin.physicsBody.allowsRotation = FALSE;
// create a joint to keep the penguin fixed to the scoop until the catapult is released
_penguinCatapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_currentPenguin.physicsBody bodyB:_catapultArm.physicsBody anchorA:_currentPenguin.anchorPointInPoints];
}
}
- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
// whenever touches move, update the position of the mouseJointNode to the touch position
CGPoint touchLocation = [touch locationInNode:_contentNode];
_mouseJointNode.position = touchLocation;
}
- (void)launchPenguin {
// loads the Penguin.ccb we have set up in Spritebuilder
CCNode* penguin = [CCBReader load:#"PenguinWithBlock"];
// position the penguin at the bowl of the catapult
penguin.position = ccpAdd(_catapultArm.position, ccp(16, 50));
// add the penguin to the physicsNode of this scene (because it has physics enabled)
[_physicsNode addChild:penguin];
// manually create & apply a force to launch the penguin
CGPoint launchDirection = ccp(1, 0);
CGPoint force = ccpMult(launchDirection, 8000);
[penguin.physicsBody applyForce:force];
// ensure followed object is in visible are when starting
self.position = ccp(0, 0);
CCActionFollow *follow = [CCActionFollow actionWithTarget:penguin worldBoundary:self.boundingBox];
[_contentNode runAction:follow];
}
-(void) touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
// when touches end, meaning the user releases their finger, release the catapult
[self releaseCatapult];
}
-(void) touchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
// when touches are cancelled, meaning the user drags their finger off the screen or onto something else, release the catapult
[self releaseCatapult];
}
- (void)releaseCatapult {
if (_mouseJoint != nil)
{
// releases the joint and lets the catapult snap back
[_mouseJoint invalidate];
_mouseJoint = nil;
// releases the joint and lets the penguin fly
[_penguinCatapultJoint invalidate];
_penguinCatapultJoint = nil;
// after snapping rotation is fine
_currentPenguin.physicsBody.allowsRotation = TRUE;
_currentPenguin.launched = TRUE;
// follow the flying penguin
_followPenguin = [CCActionFollow actionWithTarget:_currentPenguin worldBoundary:self.boundingBox];
[_contentNode runAction:_followPenguin];
}
}
-(void)ccPhysicsCollisionPostSolve:(CCPhysicsCollisionPair *)pair seal:(CCNode *)nodeA wildcard:(CCNode *)nodeB
{
float energy = [pair totalKineticEnergy];
// if energy is large enough, remove the seal
if (energy > 5000.f)
{
[self sealRemoved:nodeA];
}
}
- (void)sealRemoved:(CCNode *)seal {
// load particle effect
CCParticleSystem *explosion = (CCParticleSystem *)[CCBReader load:#"SealExplosion"];
// make the particle effect clean itself up, once it is completed
explosion.autoRemoveOnFinish = TRUE;
// place the particle effect on the seals position
explosion.position = seal.position;
// add the particle effect to the same node the seal is on
[seal.parent addChild:explosion];
// finally, remove the destroyed seal
[seal removeFromParent];
}
- (void)retry {
// reload this level
[[CCDirector sharedDirector] replaceScene: [CCBReader loadAsScene:#"Gameplay"]];
}
PenguinWithBlock settings in SpriteBuilder:
You can use a "blank" CCNode with all others parts of the body being children of it, maybe even have children of another body parts. The tree of nodes will heavily depend on the body design.
Give a look at this tutorial, as it teaches the basics to do so. Also, SpriteBuilder still doesn't have the feature to create the joints inside it, but you can easily do this programmatically as the tutorial does.
EDIT: This can help you

Cocos2D SpriteBuilder simple car with wheels

I'm currently trying out a few things. I already did this tutorial: https://www.makegameswith.us/tutorials/getting-started-with-spritebuilder/
However I'm a little stuck now.
I created a CCNode in SpriteBuilder and added 3 images. carbody.png and 2 wheel.png.
I made all objects physicsObjects.
In code I tried to connect them with joints and move them. However the carBody moves but the wheels keep staying on their place.
#import "Car.h"
#implementation Skater{
CCNode *_wheel1;
CCNode *_wheel2;
CCNode *_carBody;
CCPhysicsJoint *_bodyWheelJoint1;
CCPhysicsJoint *_bodyWheelJoint2;
}
- (id)init {
self = [super init];
if (self) {
[_wheel1.physicsBody setCollisionGroup: _carBody];
[_wheel2.physicsBody setCollisionGroup: _carBody;
[_carBody.physicsBody setCollisionGroup: _carBody];
_bodyWheelJoint1 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel1.physicsBody bodyB: _carBody.physicsBody anchorA:_wheel1.anchorPointInPoints];
_bodyWheelJoint2 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel2.physicsBody bodyB: _carBody.physicsBody anchorA:_wheel2.anchorPointInPoints];
}
return self;
}
And in Gameplay.m I only did this:
-(void)didLoadFromCCB{
[_car runAction:
[CCActionMoveTo actionWithDuration:10 position:CGPointMake(2000,_car.position.y)]];
}
The carBody moves, the wheels don't...
What am I missing?
Edit:
I made a few changes now but my wheels still keep staying on their place...
#import "Car.h"
#implementation Car{
CCNode *_wheel1;
CCNode *_wheel2;
CCNode *_carBody;
CCPhysicsJoint *_bodyWheelJoint1;
CCPhysicsJoint *_bodyWheelJoint2;
}
- (id)init {
self = [super init];
if (self) {
CCLOG(#"Car created");
[_wheel1.physicsBody setCollisionGroup:_carBody];
[_wheel2.physicsBody setCollisionGroup:_carBody];
[_carBody.physicsBody setCollisionGroup:_carBody];
_bodyWheelJoint1 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel1.physicsBody bodyB:_carBody.physicsBody anchorA:_wheel1.anchorPointInPoints];
_bodyWheelJoint2 = [CCPhysicsJoint connectedPivotJointWithBodyA:_wheel2.physicsBody bodyB:_carBody.physicsBody anchorA:_wheel2.anchorPointInPoints];
}
return self;
}
-(void)moveCar:(int)distance{
CCLOG(#"Car should move");
CGPoint launchDirection = ccp(1, 0);
CGPoint force = ccpMult(launchDirection, distance);
[self.physicsBody applyForce:force];
}
#end
You're simply missing the point that move (and other) actions bypass physics. Once a node has a physics body, the use of CCAction* classes that change position and rotation is a no-no, and most others (ie scale) will not be applied to the physics body either but can still be used safely.
To move a physics object, apply an impulse or force to the physics body.

Move a whole animation sprite sheet

I have some sprite-sheet that i have to animate forever , and i would like to add it as a CCLayer
to my scene .
Later on , i have to move this whole animation sprite on the screen.
So, for example, i have some animation of a dog walking, from sprite sheet, this one is running forever. than i want to be able to move this dog on screen while animating.
What is the best way to do this ? (or the right way)
This is how i animate the frames :
CCSprite *boom;
boom = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#_00000.png",file]];
boom.position=touch;
[self addChild:boom];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 0; i < 5; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:
#"%#_0000%i.png",file,i]];
[animFrames addObject:frame];
}
CCAnimation* boxAnimation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.075f];
CCAnimate * boxAction = [CCAnimate actionWithAnimation:boxAnimation];
CCAction *call=[CCCallBlock actionWithBlock:^{[self removeFromParentAndCleanup:YES];}];
CCAction * sequence=[CCSequence actions:boxAction,[CCHide action],call,nil];
[boom runAction:sequence];
return self;
How would you move this whole thing ?
There are a few ways to do this. If you are not preocupied with collision detection, then one way would be to :
CGPoint egressPosition = ccp(0,0); // figure this out in your app
float moveDuration = 1.5f ; // whatever time you compute for desired speed and distance
id move = [CCMoveTo actionWithDuration:moveDuration position:egressPosition];
id spawn = [CCSpawn actions:sequence,move,nil];
[boom runAction:spawn];
otherwise, using your code as is
[self schedule:#selector(moveBox:)]; // optional, you could do this in update method
[boom runAction:sequence];
-(void) moveBoom:(CCTime) dt {
CGPoint newPosition;
delta = ccp(dt*speedX,dt*speedY); // crude , just to get the idea
newPosition = ccpAdd(boom.position,delta);
// here you can figure out collisions at newPosition before the collision
// and do whatever seems appropriate
boom.position = newPosition;
}

EXC BAD ACCESS With Cocos2d pushscene that works for blank scene

So I am trying to do a levelup screen with pushscene/popscene. The pushscene works when it's a blank scene, but not when it's my scene that I want. My scene/layer loads completely with all images and text displaying their exact correct content. After all of the images load there is a EXC BAD ACCESS that doesn't seem to be linked to any particular message being sent. Any help or further diagnostic tests would be appreciated.
I have a version where I commented out the sprites and labels and it still crashes. Is there something big that I'm missing?
EDIT: I've added the [self = [super init]] and [super onEnter] methods and still same problem. It's something else. Any ideas?
EDITEDIT: I think this has something to do with the optionsArray I'm using, not sure what objects need to be retained. The array is a CCArray and contains NSDictionaries of differing capacities
#import "LevelupLayer.h"
#import "GameManager.h"
#implementation LevelupLayer
#synthesize optionsArray,spritesArray;
#synthesize confirmLabel;
#synthesize counter;
+(id) scene {
CCScene *scene = [CCScene node];
CCLayer* layer = [LevelupLayer node];
[scene addChild:layer];
return scene;
}
-(void)onEnter
{
counter = 1; // for debugging
//Detemine what levelups are possible
GameManager* gm = [GameManager sharedManager]; //GameManager is a helper that oversees communication between layers and plists
optionsArray = [gm possibleLevelups]; //Access plist and formats data into expected format
[optionsArray retain];
int numPossibilities = [optionsArray count];
//Build Levelup layer based on possible options
CGSize size = [[CCDirector sharedDirector] winSize];
//float positionIncrement = (size.width / numPossibilities) - ((size.width/numPossibilities) * 0.5);
float positionIncrement = (size.width / numPossibilities);
float stripWidth = size.width / numPossibilities;
for (int i = 0; i < numPossibilities; i++) {
int slot = i+1;
NSDictionary* optionDict = [optionsArray objectAtIndex:i];
NSString* name = [optionDict objectForKey:#"name"];
NSString* title = [optionDict objectForKey:#"title"];
NSString* description = [optionDict objectForKey:#"description"];
// Add the sprite
CCSprite* optionSpite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#.png",name]];
[self addChild:optionSpite];
[spritesArray addObject: optionSpite];
optionSpite.position = CGPointMake(slot * positionIncrement, size.height*0.60);
[optionSpite setAnchorPoint:CGPointMake(0.5f, 0.5f)];
// Add the description
CCLabelBMFont *optionDescription = [CCLabelBMFont labelWithString:description fntFile:#"bodyFont.fnt" width:stripWidth alignment:kCCTextAlignmentCenter];
[self addChild:optionDescription];
optionDescription.position = CGPointMake(slot * positionIncrement, size.height*0.30);
[optionDescription setAnchorPoint:CGPointMake(0.5f, 0.5f)];
// Add the title
CCLabelBMFont *optionTitle = [CCLabelBMFont labelWithString:title fntFile:#"titleFont.fnt" width:stripWidth alignment:kCCTextAlignmentCenter];
[self addChild:optionTitle];
optionTitle.position = CGPointMake(slot * positionIncrement, size.height*0.90);
[optionTitle setAnchorPoint:CGPointMake(0.5f, 0.5f)];
}
[self scheduleUpdate]; //Update only prints counter to see how many frames it lasts
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void) update:(ccTime)delta
{
CCLOG(#"counter: %d",counter);
counter++;
}
-(void) onExit
{
[optionsArray release];
}
#end
`
i don't see any [super onEnter]; or [super init] or anything like that ...that's your problem
First add [super onEnter] on the first line in onEnter.
Second add an init method like this:
-(id)init{
if (self=[super init]){}
}
Third add [super onExit] at the end of your onExit method
I figured it out, it wasn't anything to do with the code I posted, so sorry about that. It was just a stupid release call to a non-retained array. Retained the array previously and it worked fine. Sorry about crying wolf

Animations are not working properly(Cocos2d)

My problem is that animation are not working properly during movements of sprite.
Below is the code which i'm using
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
[selSprite resumeSchedulerAndActions];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self selectSpriteForTouch:touchLocation];
return TRUE;
}
- (void)selectSpriteForTouch:(CGPoint)touchLocation
{
CCSprite * newSprite = nil;
for (CCSprite *sprite in movableSprite) {
if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
newSprite = sprite;
break;
}
}
if (newSprite != selSprite) {
[selSprite stopAllActions];
selSprite = newSprite;
_MoveableSpritetouch = TRUE;
}
if(_MoveableSpritetouch==TRUE)
{
movement=0;
CGRect selRect=CGRectMake((SpriteX)-20.0,(SpriteY)-20.0,40.0,40.0);
if(CGRectContainsPoint(selRect, touchLocation))
{
[selSprite stopAllActions];
}
if((selSprite==MarshallCar)&& (!(CGRectContainsPoint(selRect, touchLocation))))
{
movement=1;
[self reorderChild:selSprite z:5];
NSMutableArray *MarshallCarWalkAnimFrames = [NSMutableArray array];
for(int i = MarshallCarTouchStartFrameIndex; i <= MarshallCarTouchEndFrameIndex; ++i) {
[MarshallCarWalkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"mcar_move_%d.png", i]]];
}
MarshallCarWalkAnim = [CCAnimation animationWithFrames:MarshallCarWalkAnimFrames delay:MarshallCarTouchFrameDelay];
walkMarshallCar = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:MarshallCarWalkAnim restoreOriginalFrame:NO]];
[selSprite runAction:walkMarshallCar];
}
}
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
if(gameState == TRUE){
CGPoint point = [touch locationInView:[touch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
if (moveDifference.x>0)
{
selSprite.flipX = YES;
}
else {
selSprite.flipX = NO;
}
[selSprite setPosition:point];
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
movement=0;
if(selSprite==MarshallCar)
{
[selSprite setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"mcar_idle.png"]];
}
[selSprite pauseSchedulerAndActions];
}
The animation frames for movement are not playing every time during movements sometimes it plays or sometimes not. It plays properly when you touch and move your sprite for the first time but if touch another sprite and then again move the previous sprite the animations for movement won't play.
Is anyone having any idea why this is happening?
Please tell me the proper code for removing this bug.
Thanks!!!
I believe your problem is the if/else if construct:
if (_MoveableSpritetouch==TRUE)
{
CGRect selRect = CGRectMake(SpriteX - 20, SpriteY - 20, 40, 40);
if(CGRectContainsPoint(selRect, touchLocation))
{
[selSprite stopAllActions];
}
else if(...)
{
...
[selSprite runAction:walkMarshallCar];
}
}
If you don't see it right away: if the touch location is inside the selRect, you call stopAllActions on the selected (new) sprite and do nothing else. Only if the touch location is not within that rectangle you'll run the animation action.
I think the "in rectangle" check is superfluous since you've already called stopAllActions anyway a few lines above.
Allow me a few general remarks about your code:
The method "selectSpriteForTouch" tells me that you're selecting a new sprite. The function does that. But it does not advertise playing an animation. You might want to refactor this out to a seperate "playAnimationOnSelectedSprite" method.
You wrote 20.0 and 40.0 several times. This means you're actually passing a double (8 bytes floating point data type) to a CGPoint which takes floats (4 bytes floating point). Strictly speaking use either 20.0f with the suffixed "f" to denote it as a floating point data type, or use integers since you don't use the floating point part.
Why you put (SpriteX) in brackets is not clear to me, if you want to enhance readability you'll achieve more by adding spaces after commas and operands.
In Objective-C, use YES and NO macros instead of TRUE and FALSE.
The bool variable _MoveableSpritetouch seems superfluous, unless needed someplace else. In any case you should move the following if(_MoveableSpritetouch==TRUE) block to where you set the _MoveableSpritetouch variable to TRUE because it just makes your code harder to read by setting a variable, leaving the code block you were in ( if(selSprite != newSprite) ) just to jump into another block of code ( if(_MoveableSpritetouch==TRUE) ) that you already know you're going to run anyway.
if((selSprite==MarshallCar)&& (!(CGRectContainsPoint(selRect, touchLocation))))
{
movement=1;
[self reorderChild:selSprite z:5];
NSMutableArray *MarshallCarWalkAnimFrames = [NSMutableArray array];
for(int i = MarshallCarTouchStartFrameIndex; i <= MarshallCarTouchEndFrameIndex; ++i) {
[MarshallCarWalkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"mcar_move_%d.png", i]]];
}
MarshallCarWalkAnim = [CCAnimation animationWithFrames:MarshallCarWalkAnimFrames delay:MarshallCarTouchFrameDelay];
walkMarshallCar = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:MarshallCarWalkAnim restoreOriginalFrame:NO]];
[selSprite runAction:walkMarshallCar];
}
I have added [selSprite stopAllActions];
and it started working correctly because in the touch ended method i was pausing the actions
but not resuming them so when i touch the sprite for the second time it was not playing animation because the action was paused.