Cocos2D checking if sprite is off screen? - iphone

Im using this code to fire upwards:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent* )event
{
//Spawn the bullet
CCSprite * projectile = [CCSprite spriteWithFile:#"Projectile.png" rect:CGRectMake(0, 0, 17.5, 10)];
projectile.position = ccp(donk.position.x , 50);
[self addChild:projectile];
//Actualy Fire
[projectile runAction: [CCMoveTo actionWithDuration:.2 position: ccp (donk.position.x , 350)]];
}
It works like I want but how can i use an if statement to check if the projectile it is off the top off the screen so I can remove it?
I tried using this:
if (projectile.position.y >= 330) {
CCLOG(#"Removed");
[self removeChild:projectile cleanup:YES];
}
but I forgot that touches ended is only called once.

Think about when you should be checking whether the bullet is offscreen. Not at the same instant it was fired, right?
There are many ways to do this.
You have a moveTo action already. CCActions can have callbacks that tell you when they're completed; see the header.
You can define an update: method and enable it with scheduleUpdates to be able to test the position every frame.
If you use a physics engine, you can make a "wall" for the edge of the screen and remove the bullet in response to collision detection.
There are probably other ways, too. Look into what the framework provides.

What about this:
[projectile runAction:[CCSequence actions:
[CCMoveTo actionWithDuration:.2 position:ccp(donk.position.x,350)],
[CCCallBlock actionWithBlock:^{
[projectile removeFromParentAndCleanup:YES];
}],
nil]];
(not tested)

Related

Fade in/Fade out in Cocos 2d not working

I'm trying to make a fade in-fade out effect in cocos 2d, using a black png image. Its to make a better way to show something, instead of the casual way...
Is something wrong on this code?
- (void) effectFade {
CCSprite *effectScreen = [CCSprite spriteWithFile:#"black-iphone.png"];
effectScreen.opacity = 0;
[effectScreen runAction:[CCSequence actions:
[CCFadeIn actionWithDuration:1],
[CCCallFunc actionWithTarget:self selector:#selector(hideOutShowIn)],
[CCFadeOut actionWithDuration:1],
[CCCallFunc actionWithTarget:self selector:#selector(finish)],
nil]];
CCFadeTo *fadeIn = [CCFadeIn actionWithDuration:1];
CCFadeTo *fadeOut = [CCFadeOut actionWithDuration:1];
CCSequence *fadeSequence = [CCSequence actionOne:fadeIn two:fadeOut];
}
You don't specify what is not working as expected, but it seems to me that you are not adding effectScreen to any layer or other node, so that it can be displayed.
As to the rest, the code seems correct to me (aside from fadeIn, fadeOut, fadeSequence that are not used).
EDIT:
you are definitely using effectScreen in an ObjC/C sense; what you are not doing is adding it to your scene by doing something like:
[self addChild:effectScene];
(assuming self is your scene or another CCNode class).
The thing about not using fadeSequence is a bit different, since you are not using it in the ObjC/C sense: you define it and never ever reference it again.

How to move the PhysicsSprite in box2d

I am having a physicsSprite of kinematics body type and I want to move the body and sprite bit down and back to its position. I tried it like this Inside update method:
for (NSValue *bodyValue in [self getGoalPostBodiesList])
{
b2Body *gPBody = (b2Body *)[bodyValue pointerValue];
PhysicsSprite *pSprite =(PhysicsSprite *) gPBody->GetUserData();
NSLog(#"\n tag value of Sprite = %d",pSprite.tag);
if(pSprite == goal1)
{
pSprite.position = CGPointMake((gPBody->GetPosition().x)*32.0,(gPBody->GetPosition().y)*32.0);
float angle = gPBody->GetAngle();
pSprite.rotation = -(CC_RADIANS_TO_DEGREES(angle));
id moveDownAction = [CCMoveTo actionWithDuration:0.5 position:CGPointMake(pSprite.position.x,(pSprite.position.y )- 40)];
id moveUpAction = [CCMoveTo actionWithDuration:0.5 position:CGPointMake(pSprite.position.x,(pSprite.position.y )+ 40)];
CCSequence *seqAction = [CCSequence actions:moveDownAction,moveUpAction, nil];
[pSprite runAction:seqAction];
b2Vec2 pos = b2Vec2(pSprite.position.x/32.0, pSprite.position.y/32.0);
gPBody->SetTransform(pos, CC_DEGREES_TO_RADIANS(pSprite.rotation));
gPBody->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
gPBody->SetAngularVelocity(0.0f);
}
}
Still the sprite is not changing its position.
Anyone's help will be deeply appreciated.
Thanks all,
MONISH
To summarize your code, you update the position of your sprite to reflect that of the body, start an animation, and then update the position of the body to correspond to the position of the sprite. So naturally, nothing should move here, since your CCMoveTo actions have not exerted any effect on your sprite yet.
Second, your update method may be called very often, like dozens of times per second, so the animation gets reset continously and will not make any visible progress.
To follow a consistent pattern, how about you set the velocity of your kinematic bodies. Also, update the position of your sprites to correspond to these bodies as you would do for dynamic bodies, but don't set the transformation of your bodies to correspond to their sprites.

CCFollow with CCParticleSystem

I'm trying to follow some sprite by some instance of CCParticleSystem using CCFollow. I don't want to make instance of CCParticleSystem a child of sprite, because I want it to be displayed some time after sprite removed.
When moving sprite from bottom-left to top-right corner my ParticleSystem moves from center to bottom-left corner. I can't understand why does it happen.
Here is sample code:
-(id) init
{
if( (self=[super init]) ) {
CCSprite *someSprite = [CCSprite spriteWithFile:#"Icon.png"];
[self addChild:someSprite];
id action = [CCMoveTo actionWithDuration:5 position:ccp(480,320)];
[someSprite runAction:action];
CCParticleSystemQuad *effect = [CCParticleMeteor node];
// effect.positionType = kCCPositionTypeFree;
// effect.positionType = kCCPositionTypeRelative;
// effect.positionType = kCCPositionTypeGrouped; changing of positionType to any of this options does not make any sense
[effect runAction:[CCFollow actionWithTarget:someSprite]];
[self addChild:effect];
}
return self;
}
It's a case of bad documentation.
I tried this myself and got the same result. By looking at the code and the fragment of documentation that exists, the CCFollow action is intended to be used only on fullscreen nodes like CCLayer, CCScene and perhaps CCNode. I would document it as follows:
CCFollow is an action for scrolling the entire screen by allowing the
layer or scene follow another node, such as a player object. It's an
alternative for moving the Camera object or updating the position
manually.

Cocos2d - how to make individual particles follow the layer, not the emitter?

I have a CCSprite and a CCParticleSystemQuad that are both children of the CCLayer. In my update method, I set the emitter's position to that of the sprite, so it tracks the sprite around. The smoke puff fall out the bottom of the sprite like you'd expect and even though you move the sprite around, the smoke appears to be part of the background layer.
The problem come if I match up their rotations. Now, for example if my sprite is rocking back and forth, the puffs of smoke swing in an arc and appear attached to the sprite.
How can I make the puffs of smoke continue along the parent layer in a straight line and not rotate with the sprite? They don't translate with the sprite when I move it, so why do they rotate with it?
EDIT: adding code...
- (id)init
{
if (!(self = [super init])) return nil;
self.isTouchEnabled = YES;
CGSize screenSize = [[CCDirector sharedDirector] winSize];
sprite = [CCSprite spriteWithFile:#"Icon.png"]; // declared in the header
[sprite setPosition:ccp(screenSize.width/2, screenSize.height/2)];
[self addChild:sprite];
id repeatAction = [CCRepeatForever actionWithAction:
[CCSequence actions:
[CCRotateTo actionWithDuration:0.3f angle:-45.0f],
[CCRotateTo actionWithDuration:0.6f angle:45.0f],
[CCRotateTo actionWithDuration:0.3f angle:0.0f],
nil]];
[sprite runAction:repeatAction];
emitter = [[CCParticleSystemQuad particleWithFile:#"jetpack_smoke.plist"] retain]; // declared in the header - the particle was made in Particle Designer
[emitter setPosition:sprite.position];
[emitter setPositionType:kCCPositionTypeFree]; // ...Free and ...Relative seem to behave the same.
[emitter stopSystem];
[self addChild:emitter];
[self scheduleUpdate];
return self;
}
- (void)update:(ccTime)dt
{
[emitter setPosition:ccp(sprite.position.x, sprite.position.y-sprite.contentSize.height/2)];
[emitter setRotation:[sprite rotation]]; // if you comment this out, it works as expected.
}
// there are touches methods to just move the sprite to where the touch is, and to start the emitter when touches began and to stop it when touches end.
I found the answer on a different site - www.raywenderlich.com
I don't know why this is true, but it seems that CCParticleSystems don't like to be rotated while you move them around. They don't mind changing their angle property. Actually, there may be cases where you want that behavior.
Anyway I made a method that adjusts the emitter's angle property and it works fine. It takes your touch location and scales the y component to be the angle.
- (void)updateAngle:(CGPoint)location
{
float width = [[CCDirector sharedDirector] winSize].width;
float angle = location.x / width * 360.0f;
CCLOG(#"angle = %1.1f", angle);
[smoke_emitter setAngle:angle]; // I added both smoke and fire!
[fire_emitter setAngle:angle];
// [emitter setRotation:angle]; // this doesn't work
}
CCSprite's anchorPoint is {0.5f, 0.5f), while the emitter descends directly from CCNode, which has an anchorPoint of {0.0f, 0.0f}. Try setting the emitter's anchorPoint to match the CCSprite's.

Animating a CCSprite on cocos2d?

Hey guys, I'm new to cocos2d and iPhone development, im currently trying to create a game like "PapiJump",
What I'm currently having problems with, is animating the character CCSprite in my game,
I have created 3 images of my character, character pointing right, left and middle (http://i53.tinypic.com/ngzoyh.png)
so when the character changes its direction (left or right), it wont "jump" directly to the other direction but will animate..
In my code im using the TouchesEnded method, in this method im setting a variable named "touchState",
so if the user touched the right side of the screen it will set "touchState" to 1, otherwise it sets it to 2 (means left).
then in the "init" method i created a "schedule" that runs another method every 0.5 sec that is named: "updateGame",
the "updateGame" method updates the player's position, it works like that:
player.position = ccp(player.position.x , player.position.y - playerGravity.y);
I've read Ray's tutorial on animating CCSprites but i have no idea how to achieve the result that i need..
Thanks in advance and sorry for my bad english!
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 4; ++i)
{
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"spr_fillin_0%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.0333f];
_sprite = [CCSprite spriteWithSpriteFrameName:#"spr_fillin_01.png"];
[_sprite runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]]];
[<CCLAYER OR BATCH NODE> addChild:_sprite];
Edit: Looks like you're talking about just flipping the image around. You can just refetch a sprite with
_sprite = [CCSprite spriteWithSpriteFrameName:#"<New Sprite File>"];
(Or cache them and switch)
Can you clarify your question? If you want to set a different sprite frame, you can use setDisplayFrame:
CCSpriteFrame *spriteFrame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:frameName];
[sprite setDisplayFrame:frame];
or if you have an animation:
[sprite runAction:[CCAnimate actionWithAnimation:runAnimation restoreOriginalFrame:NO]];
But I feel like the question is a little vague.
if i got your question properly i can suggest two ways to solve your problem:
first you could rotate your object to till it is upside down, and the continue your previous animations using FlipX(or FlipY) flag marks as true or you can add an animation wich animates only characters rotation and when ever it's finnished change the FLipX(or FlipY) status.