I am using...
[self addChild:self.blue_action];
[self schedule:#selector(updateTimer1:) interval:1.0f];
Via this line, I want to show an image in the any position and after some time that image will remove, through '[self removeChild: self.blue_action cleanUp:Yes];'
-(void)updateTimer1:(id)sender {
if(time_1 == 0) {
NSLog(#"time value ");
[self removeChild:self.blue_action cleanup:YES];
[self schedule: #selector(updateTimer1:) interval:0.10];
}
else {
--time_1;
}
}
In this case the updateTimer1:(id)sender method was already scheduled.
To schedule this again you obvious must unscheduled this method by [self unschedule:_cmd];
And it's a good practice do not remove sprite every time when you want it to disappear, try to just make it invisible self.blue_action.visible = NO
You want to fire method once after specific time? Action is helpful.
-(void)addBlueAction {
[self addChild:self.blue_action];
[self runAction:[CCSequence actions:
[CCDelayTime actionWithDuration:1],
[CCCallFunc actionWithTarget:self
selector:#selector(removeBlueAction)],
nil]];
}
-(void)removeBlueAction {
[self removeChild:self.blue_action cleanup:YES];
}
If your app's target is for after iOS 4.0, you can use Blocks.
-(void)addBlueAction {
[self addChild:self.blue_action];
[self runAction:[CCSequence actions:
[CCDelayTime actionWithDuration:1],
[CCCallBlock actionWithBlock:^{
[self removeChild:self.blue_action cleanup:YES];
}],
nil]];
}
Related
I'm making a top down tile based game (think old Pokemon and Zelda games on GameBoy). I'm having problems with the character moving smoothly. I think the problem is the delay between finishing an action and starting a new one.
Here's what the code looks like:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchCoor = [self coordinateForTouch:touch];
// If the character was touched, open their dialogue
if (CGPointEqualToPoint(touchCoor, ebplayer.coordinate)) {
[[CCDirector sharedDirector] replaceScene:
[CCTransitionMoveInR transitionWithDuration:1.0 scene:[HelloWorldLayer scene]]];
}
else // otherwise, move the character
{
activeTouch = [self directionForPoint:[touch locationInView:[touch view]]];
[self movePlayer:nil inDirection:activeTouch];
}
return YES;
}
// given in screen dimension points
// is the base movement function for all movements
- (void)movePlayer:(NSString*)pid toPosition:(CGPoint)position{
CGPoint playerCoordinate = [self coordinateForPositionPoint:position];
// if we're not already moving, and we can move, then move
if(!isAnimating && [self coordinateIsOnMap:playerCoordinate] && [self isPassable:playerCoordinate]){
id doneAction = [CCCallFuncN actionWithTarget:self selector:#selector(finishedAnimating)];
id moveAction = [CCMoveTo actionWithDuration:WALK_DURATION position:position];
id animAction = [CCAnimate actionWithAnimation: [ebplayer animateDirection:activeTouch withDuration:WALK_DURATION]];
id walkAndMove = [CCSpawn actionOne:moveAction two:animAction];
id action = [CCSequence actions: walkAndMove, doneAction, nil];
isAnimating = YES;
[player runAction:action];
ebplayer.coordinate = playerCoordinate;
[self setViewpointCenter:position Animated:YES];
}
// if it's not passable, just run the animation
if(!isAnimating){
id doneAction = [CCCallFuncN actionWithTarget:self selector:#selector(finishedAnimating)];
id animAction = [CCAnimate actionWithAnimation: [ebplayer animateDirection:activeTouch withDuration:WALK_DURATION]];
id action = [CCSequence actions: animAction, doneAction, nil];
isAnimating = YES;
[player runAction: action];
}
}
Then when that action is finished, try and start it up again:
(void)finishedAnimating{
isAnimating = NO;
[self movePlayer:nil inDirection:activeTouch];
}
You will always end up with a 1-frame delay when sequencing multiple CCMove* actions.
What happens is the following:
frame 0-100: move action runs, sprite is moving
frame 101: move action ended, CCCallFunc runs
frame 102: new move action begins
This one-frame delay is one of the main problems of sequencing move actions, and the reason why I wouldn't recommend using move actions for gameplay purposes.
The alternative is to move objects manually in a scheduled update method by modifying their position. You can use the CCMove* action code as basis.
I'm trying to set a delay within a for loop in an iphone app. Basically I'll have a for loop with a few actions and I want a 1 sec delay between each action:
for loop { action 1, delay 1sec, action 2, delay 1sec, action 3, delay 1sec}
How would I code this?
for (loop) {
[self action1];
[self performSelector:#selector(action2) withObject:nil afterDelay:1.0];
[self performSelector:#selector(action3) withObject:nil afterDelay:1.0];
}
Hope this is what you are looking for!!
Edit
Try this.. It will finish up running the current method and move to the next.
for (loop) {
[self performSelectorOnMainThread:#selector(action1) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:#selector(action2) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:#selector(action3) withObject:nil waitUntilDone:YES];
}
This doesn't involve a for loop but will take a list of actions and perform them with increasing delays.
NSArray *selectorStrings = #[ #"action1", #"action2", #"action3" ];
[selectorStrings enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
SEL selector = NSSelectorFromString((NSString *)obj);
NSTimeInterval delay = (NSTimeInterval)idx;
[self performSelector:selector withObjet:nil afterDelay:delay];
}];
Hope this helps! Let me know if you have questions.
I am developing a 2d game in which on my game screen I have to implement a reverse timer from 30 sec till 0 sec and if a player does not move his character he will win otherwise he will lose and the game will be over.
This is my init method:
-(id)init
{
if(self==[super init])
{
self.isTouchEnabled=YES;
self.isAccelerometerEnabled=YES;
CGSize size=[[CCDirector sharedDirector] winSize];
screenwidth=size.width;
screenheight=size.height;
west_pic=[CCSprite spriteWithFile:#"west_pic.png"];
west_pic.anchorPoint=ccp(1, 1);
west_pic.scaleX=1.4;
west_pic.position=ccp(size.width, size.height);
[self addChild:west_pic];
label1=[CCLabelTTF labelWithString:#"Level One" fontName:#"Arial" fontSize:20];
label1.position=ccp(size.width/3.8,size.height/1.2);
[self addChild:label1];
label2=[CCLabelTTF labelWithString:#"Lives :" fontName:#"ArcadeClassic" fontSize:18];
label2.position=ccp(size.width/1.5,size.height/8.2);
[self addChild:label2];
player=[CCSprite spriteWithFile:#"player.png"];
player.position=ccp(size.width/1.7, size.height/2);
player.scale=0.2;
player.tag=2;
player.anchorPoint=ccp(1, 0);
[self addChild:player];
[self schedule:#selector(updateplayer:) interval:1.0f/60.0f];
}
return self;
}
for example, you can have an instance with number of seconds, that player must not to move character, then you must have ssome event methods to know when the character begins and stops movement, create updatable label(if you want to show the rest of the time to player) and schedule timer, which will decrease number of seconds. smth like this
- (void) onEnter
{
[super onEnter];
// if player character not move on start
[self schedule:#selector(reduceRestTime) interval:1.f];
}
- (void) onExit
{
[self unscheduleAllSelectors];
[super onExit];
}
- (void) onCharacterStop
{
m_restTime = // your time left. in your case, 30 sec
// if you have time label
[self updateRestTimeLabel];
[self schedule:#selector(reduceRestTime) interval:1.f];
}
- (void) onCharacterBeginMovement
{
[self unscheduleSelector:#selector(reduceRestTime)];
}
- (void) reduceRestTime
{
m_restTime--;
// if you have time label
[self updateRestTimeLabel];
if( m_timeLeft == 0 )
{
[self unscheduleSelector:#selector(reduceRestTime)];
// your win code
}
}
- (void) updateRestTimeLabel
{
[m_timeLabel setString:[NSString stringWithFormat:#"Time left: %d", m_timeLeft]];
}
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?
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