I have total 20 images in NSMutableArray of ccspirit objects, and I want to show them on screen moving moving upward, I add them to as [self addChild:p] as below
-(void) callMethod {
static int x = 50;
if (x>=0) {
Paddle *p = [paddlesFruits objectAtIndex:x];
p.position = CGPointMake(40,0);
[self addChild:p];
[self moveMethod1: p];
[p release];
x--;
}else {
x=50;
}
}
and the method which will move it upside is
-(void) moveMethod1 : (id) sender {
id actionMove2 = [CCMoveTo actionWithDuration:6 position:ccp(40, 520)];
id actionMoveDone2 = [CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[sender runAction:[CCSequence actions:actionMove2, actionMoveDone2, nil]];
}
-(void)spriteMoveFinished:(id)sender {
//NOTHING HERE
}
but after using addChild again and again, it will make it heavier, so what should I do,
I am thinking to addChild and remove after certain time, I will removeChild, but is it possible to to add a ccspirit again after using removeChild for same ccspirit object?
Related
i have this code to show animation of a image
-(void) blink:(ccTime) delta {
animateblink ++; //adds 1 every frame
if (animateblink <= 6 ) { //if we included frames to show for breaking and the current frame is less than the max number of frames to play
if (animateblink < 6) {
[sprite setTexture:[[CCSprite spriteWithFile:[NSString stringWithFormat:#"%#_blinkk00%i.png", baseImageName,animateblink]] texture]];
[self unschedule:_cmd];
[self schedule:#selector(openEyes:) interval:0.1f];
[self schedule:#selector(moveSprite:) interval:0.1f];
}
}
}
i have 6 images of animating like
dragonimage_blinkk001,dragonimage_blinkk002,dragonimage_blinkk003,dragonimage_blinkk004,dragonimage_blinkk005,dragonimage_blinkk006 like that
i put two methods,
1: for animation time
2: for movement of the image
the code is
-(void) openEyes:(ccTime) delta {
[sprite setTexture:[[CCSprite spriteWithFile:[NSString stringWithFormat:#"%#.png", baseImageName]] texture]];
[self unschedule:_cmd];
int blinkInterval = (arc4random() % 6) + 1; // range 3 to 8
[self schedule:#selector(blink:) interval:blinkInterval];
}
-(void)moveSprite:(ccTime)delta
{
movementCounter ++;
if (movementCounter == 1000) {
[self unschedule:_cmd];
}
else
{
spriteimagename.position = ccp(spriteimagename.position.x+10,spriteimagename.position.y);
}
}
but on the first method the animation time is not correct,there is a lot of delay of animation,i just want to show animation of the images randomly and fast,its a dragon flying animation.
my sec on method is not at all working,i didn't get any movement of that image.
i hope you understand my issue.how to solve the above two method issues.
Thanks in advance.
Quick solution is to add frameIndex member in cocos2d CCSpriteFrame class. i don't know is that allowed to change. But it works fine.
#interface CCSpriteFrame : NSObject <NSCopying>
{
int frameIndex;
....
}
//Here in code initialize frames with unique index
CCAnimation* animation;
NSMutableArray *animFrames2 = [NSMutableArray array];
for( int i=1;i<=15;i++)
{
CCSpriteFrame *frame = [cache spriteFrameByName:[NSString stringWithFormat:#"ActerSmash_%d.png",i]];
frame.frameIndex = (int)i;
[animFrames2 addObject:frame];
}
animation = [CCAnimation animationWithFrames:animFrames2];
CCAnimate *action = [CCAnimate actionWithDuration:ACTER_SMASH_SPEED animation:animation restoreOriginalFrame:YES];
action.tag = kTagAnimationSmashAnim ;
mActer.AnimSmash = action;
//Checking frame Index
CCAnimate *anim = mActer.AnimSmash ;
for(CCSpriteFrame *frame in anim.animation.frames)
{
if([mActer isFrameDisplayed:frame] ) )
{
if(frame.frameIndex == 5 )
{
//Do something..
}
}
}
Let me explain it in depth, when ever if(CGRectContainsPoint([hole1 boundingBox], ball1.position)) condition goes true, i do lots of stuffs, like unscheduled, a selector, destroying a ball body calling an animation (please refer Code below)etc. This work properly most of the time. But sometimes when ball is really near to hole(just touching the hole but but not enough to make the above condition true), or is been throws towards the hole really fast speed, then application got terminated. I have checked, by commenting many actions which are been performed in this section, but got nothing helpful, application keep terminating when some efforts are been done to make it terminate.
if(CGRectContainsPoint([hole1 boundingBox], ball1.position))
{
ballBody->SetLinearVelocity(b2Vec2(0.0f,0.0f));
ballBody->SetAngularVelocity(0.0f);
[self unschedule:#selector(tick:)];
self.isTouchEnabled = NO;
[self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
// create the sprite sheet
CCSpriteSheet *spriteSheet;
GolfBallsAppDelegate *appDelegate = (GolfBallsAppDelegate *)[[UIApplication sharedApplication] delegate];
if([appDelegate.ballValue isEqualToString:#"cricketball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"cricket_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"ironball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"iron_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"golfball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"golf_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"soccerball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"soccer_ball_strip.png"];
}
else if([appDelegate.ballValue isEqualToString:#"basketball"])
{
spriteSheet = [CCSpriteSheet spriteSheetWithFile:#"basket_ball_strip.png"];
}
spriteSheet.position = ccp(hole1.position.x,60);
[self addChild:spriteSheet];
float frameWidth = 96;
float frameHeight = 84;
CCSprite *sprite = [CCSprite spriteWithTexture:spriteSheet.texture rect:CGRectMake(0, 0, frameWidth, frameHeight)];
[spriteSheet addChild:sprite];
//if(animation)
{
// create the animation
CCAnimation *spriteAnimation = [CCAnimation animationWithName:#"potting" delay:0.1f];
int frameCount = 0;
for (int x = 0; x < 6; x++)
{
// create an animation frame
CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:spriteSheet.texture rect:CGRectMake(x*frameWidth,0*frameHeight,frameWidth,frameHeight) offset:ccp(0,0)];
[spriteAnimation addFrame:frame];
frameCount++;
// stop looping after we've added 14 frames
if (frameCount == 6)
{
//[self removeChild:spriteSheet cleanup:YES];
break;
}
}
// create the action
CCAnimate *spriteAction = [CCAnimate actionWithAnimation:spriteAnimation];
//CCRepeatForever *repeat = [CCRepeatForever actionWithAction:spriteAction];
// run the action
[sprite runAction:spriteAction];
//[sprite runAction:repeat];
}
[self schedule:#selector(loading) interval:0.5];
[self schedule:#selector(holeFinish) interval:1];
//[self removeChild:spriteSheet cleanup:YES];
}
Any suggestion will be highly appreciated.
EDIT: What i found is, problem with folling lines [self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
(MAY be). but as it not occurs always, (as I mentioned), thus it's being ridiculous.
I think your problem will be that you are trying to delete a body when the b2World is 'locked', (When the world is busy working out collisions).
Try flagging the object as ready for deletion, and deleting it at the start of your next loop:
Replace:
[self removeChild:ball1 cleanup:YES];
world->DestroyBody(ballBody);
with
ball1.isDead = YES;
And at the start of your next game loop:
for (Ball b in balls)
{
if (b.isDead)
world->DestroyBody(b.ballBody);
}
Please, I need help in making this code work. I intend to do an animation with a sprite I added using cocos2d and box2d in xcode. But for some odd reasons I cannot get the sprite to animate repeatedly.
This code builds successfully but animates only once. Can anyone help and tell me what I am not doing right?
The implementation file are as follows:
#import "Mosquito.h"
#import "Box2DHelpers.h"
#implementation Mosquito
#synthesize flyingAnim;
- (void) dealloc{
[flyingAnim release];
[super dealloc];
}
-(void)initAnimations {
flyingAnim = [self loadPlistForAnimationWithName:#"flyingAnim"
andClassName:NSStringFromClass([self class])];
[[CCAnimationCache sharedAnimationCache] addAnimation:flyingAnim
name:#"flyingAnim"];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
// id flyingAction = nil;
//CGPoint newPosition;
[self setCharacterState:newState];
switch (newState) {
case kStateIdle:
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"Mosquito_anim_1.png"]];
break;
case kStateFlying:
action = [CCAnimate actionWithAnimation:flyingAnim
restoreOriginalFrame:NO];
break;
case kStateTakingDamage:
action = [CCBlink actionWithDuration:1.0 blinks:3.0];
break;
default:
//CCLOG(#"Unhandled state %d in Mosquito", newState);
break;
}
if (action != nil) {
[self runAction:action];
}
}
- (id)initWithWorld:(b2World *)theWorld atLocation:(CGPoint)location {
if ((self = [super init])) {
world = theWorld;
[self setDisplayFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:#"Mosquito_anim_1.png"]];
gameObjectType = kMosquitoType;
characterHealth = 100.0f;
[self createBodyAtLocation:location];
[self initAnimations];
}
return self;
}
- (void) updateStateWithDeltaTime:(ccTime)deltaTime
andListOfGameObjects:(CCArray *)listOfGameObjects {
//CGPoint oldPosition = self.position;
if ((characterState == kStateDestroyed) &&
([self numberOfRunningActions] > 0)) {
return;
}
if (characterState != kStateFlying &&
[self numberOfRunningActions] == 0) {
[self changeState:kStateFlying];
}
}
#end
Thanks.
id repeatAnimation = [CCRepeatForever actionWithAction:action];
To repeat forever, you need to do that, otherwise you need to just do:
[self runAction:action];
again.
Also, you might want to consider not reassigning action to CCBlink and make another action and call
[self stopAllActions];
id blinkAction = [CCBlink actionWithDuration:1.0 blinks:3.0];
[self runAction:blinkAction];
This may Help you.
One of the easiest ways for sprite animation.
https://sites.google.com/site/rajanallathambi1/cocos2d-tutorials/sprite-animation-without-plist-file
Sorry about the poor question title, it's just that this seems to big for a title. So here's the dirt:
I am making a game (obviously) and I want the enemies to shoot (not necessarily at the player). I want the shoot method to be in the Enemies file, so as not to clutter up my HelloWorldLayer.m file even more. Here's what I'm using right now:
HelloWorldLayer.m
-(void)addEnemy:(BigAndStrongEnemy *)enemy {
enemy = nil;
if((arc4random() % 4) == 3) {
enemy = [BigAndStrongEnemy enemy];
} else {
enemy = [SmallAndFastEnemy enemy];
}
if(buffDude.position.y > character.position.y || buffDude.position.y < (character.position.y + 10)) {
}
int rand = arc4random() % 320;
if((arc4random() % 2 == 1)) {
[enemy setPosition:ccp(0,rand)];
}else{
[enemy setPosition:ccp(480,rand)];
}
[self animateEnemy:enemy];
[self addChild:enemy];
}
-(void)animateEnemy:(BigAndStrongEnemy *)enemy2 {
float randX = arc4random() % 480;
float randY = arc4random() % 320;
int rand = arc4random() % 320;
CGPoint moveToPoint = CGPointMake(randX, (randY - rand));
[enemies addObject:enemy2];
action = [CCSequence actions:
[CCMoveBy actionWithDuration:1 position:ccpMult(ccpNormalize(ccpSub(moveToPoint, enemy2.position)), 75)],
[CCMoveBy actionWithDuration:3 position:ccp(buffDude.position.x,buffDude.position.y)],
nil];
CCCallFuncO *a = [CCCallFuncO actionWithTarget:self selector:(#selector(shoot:)) object:enemy2];
CCSequence *s = [CCSequence actions:action,a, nil];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:s];
[enemy2 runAction:repeat];
}
And here's the Shoot info from the Enemies class:
Enemies.m:
-(void)shoot:(id)sender {
BigAndStrongEnemy *enemy = (BigAndStrongEnemy *)sender;
[enemy shoot];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *b = (CCSprite *)sender;
[self removeChild:b cleanup:YES];
}
-(void)shoot {
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
CCSprite *b = [CCSprite spriteWithFile:#"bullet.gif"];
b.position = ccp(self.position.x,self.position.y);
b.tag = 2;
[self addChild:b];
[bullets addObject:b];
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGPoint point = CGPointMake((winSize.width - (winSize.width - self.position.x)),0);
[b runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:0.5 position:point],
[CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)],
nil]];
}
Every time the 3 seconds goes by, the app crashes, and goes to the breakpoint in the CCCallFuncO file. I haven't touched it, is the thing. I am completely confused. Any help is greatly appreciated. Sorry about the long question. Thanks!!
It looks like your CCCallFuncO is calling [self shoot:enemy2] where self is the HelloWorldLayer object, but shoot is defined in the Enemies class.
Edit:
buffDude should be released before assigning it and retain it afterwards, like this:
Change this:
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
to this:
[buffDude release];
buffDude = [CCSprite spriteWithFile:#"bigAndStrongEnemy.gif"];
[buffDude retain];
This assumes that this is the only place where buffDude is assigned. If it is also assigned elsewhere, make sure you properly retain and release it there as well.
Although, the more I think about it, I don't understand why you create a new buffDude every time shoot is called. I'm not sure what you're doing, so I won't say it's wrong, but it doesn't look right to me anyway.
from what i see (and the fact that i only worked with cocos2d-x) i can only tell you to test whether it steps inside your shoot funciton or not, but i guess you are somhow using CCCallFuncO bad, maybe you have to call it passing enemy2 also for the actionWithTarget parameter (i can tell that becouse that's how cocos2d-x works), also check if big and small enemy types can be converted together freely.
I have three actions that are triggered in the CCSequence. The way I want it to be fired is that first the sprite should move in the center of the screen and then the scale action is fired. But for some reason the sprite moves to the center of the screen correctly but when the scale is fired it uses the old sprite position.
id actionRotate = [CCRotateBy actionWithDuration:0.6 angle:360];
id disappear = [CCFadeTo actionWithDuration:.5 opacity:0];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(removeAlphabetToFindFromView:)];
id actionScale = [CCScaleBy actionWithDuration:0.6 scaleX:10 scaleY:10];
id moveTo = [CCMoveTo actionWithDuration:0.6 position:ccp(windowSize.width/2, windowSize.height/2)];
//[self removeAlphabetToFindFromView2:alphabetToFind];
[alphabetToFind runAction:[CCSequence actions:moveTo,actionScale,disappear,actionMoveDone, nil]];
UPDATE 1:
Maybe the startAnimation method has something to do with this. I have public x and y variables which is used as x and y positions for 4 different sprites:
-(void) startAnimation:(CCSprite *) sprite
{
[self generateRandomCoordinates];
id actionMove = [CCMoveTo actionWithDuration:3.0 position:ccp(x,y)];
id actionRotate = [CCRotateBy actionWithDuration:0.0 angle:rotateBy];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(finishedMoving:)];
[sprite runAction:[CCSequence actions:actionMove,actionRotate, actionMoveDone, nil]];
}
-(void) finishedMoving:(id) sender
{
if(counter == randomAlphabets.count)
{
counter = 0;
}
CCSprite *sprite = [randomAlphabets objectAtIndex:counter];
[self generateRandomCoordinates];
[self startAnimation:sprite];
counter +=1;
}
UPDATE 2:
As expected the x and y used in the startAnimation method (getRandomCoordinates) were causing the problem. So, I removed all the actions before firing the sequence and now it works fine.