I am trying to create a sprite animation of a character firing a gun in Cocos2d. I am struggling to find a way to instantiating and start moving the bullet sprite at the appropriate frame of the load/aim/fire animation of my character.
For example, my character goes through an 12 frame animation to fire his gun and the bullet should be released at frame 7.
Can anyone help?
Thanks in advance
Al
Here is one way of doing this, a similar scenario in a game i am developping. I want , on frame 10 of 16, to schedule an 'attackTurnAround' method (to animate damage animations, hurt on the victim, etc...). Dont waste time on 'frame notifications', sometimes a frame will be skipped, and you will end up with no notifications.
caveat : timing is key. Before getting at this point, i preload EVERYTHING that will happen in 'attackTurnAround' , namely the hurt (or dead) animation, the damage animation, the soundFx that will be heard when the sword hits on frame 10, etc .....
BattleAnimation *ba = [self attackerAttackAnination];
_attackerAttackSprite = ba.firstSprite;
[_attackerNode addChild:_attackerAttackSprite];
CCActionAnimate *anim = [CCActionAnimate actionWithAnimation:ba.animation];
id endAttack = [CCActionCallBlock actionWithBlock:^{
[self endAttack];
}];
id seq = [CCActionSequence actions:anim, endAttack, nil];
_attackerAttackSprite.visible = YES;
_attackerIdleSprite.visible = NO;
[_attackerAttackSprite runAction:seq];
[self scheduleOnce:#selector(attackTurnAround) delay:9. * ba.duration / 16.];
Related
I have a problem in pausing a sprite kit game with physics. The game contains a ball which moves in the SpriteScene and has the following parameters:
self.ball.physicsBody.friction = 0;
self.ball.physicsBody.linearDamping = 0;
self.ball.physicsBody.restitution = 1.0f;
self.ball.physicsBody.affectedByGravity = NO;
self.ball.physicsBody.usesPreciseCollisionDetection = YES;
The problem is that when I pause the game, I call these methods:
self.scene.physicsWorld.speed = 0;
self.ball_velocity = self.ball.physicsBody.velocity;
self.ball.physicsBody.velocity = CGVectorMake(0, 0);
self.ball.speed = 0;
self.ball.physicsBody.dynamic = NO;
[self.scene.view setPaused:YES];
and when resume, call these:
self.scene.physicsWorld.speed = 1;
self.ball.physicsBody.velocity = self.ball_velocity;
self.ball.physicsBody.dynamic = YES;
self.ball.speed = 1;
[self.scene.view setPaused:NO];
This stops the ball animation, but when resume, the ball position is changed and it seems if that was moving during the pause duration.
BTW, it works fine on iOS 8 but on iOS 9 it always fails.
Any suggestions ?!!
After chatting, we have come to the conclusion that between iOS8 and iOS9, Apple has done a change that pausing the scene now pauses the update loop. Since the update loop is being paused, the change in time is not being calculated correctly. What is now happening, is the change in time will be the time at unpause - the time at pause, simulating a lag state. The velocity will take the math into effect, and move objects based on this difference in time. To combat this issue, just make a parent node that will house all of your scenes's objects, and pause the parent. This will allow the update to still be called, thus allowing the change in time to stay consistent with the frame rate.
Working on a game for iOS, using the sprite-kit framework to build it. The game runs smoothly for about the first minute in a half (maintaining the 60 fps rate), but as the player progresses into the game, the frame rate slowly starts to decrease. With time it even drops as low as 8 fps. I thought this was a result of the added debris and obstacles in the game, so I made an effort to remove a lot of them from the parent after time. This is how the game is set up:
There are 6 NSMutableArrays for the different types of debris that fall in the game. This is the format for each of them:
-(void)spawnDebris6 {
SKSpriteNode * debris6 = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:#"debris6.png"] size:CGSizeMake(20, 20)];
debris6.zPosition = 1.0;
SKEmitterNode *debrisTrail = [SKEmitterNode kitty_emitterNamed:#"Dtrail"];
debrisTrail.zPosition = -1.0;
debrisTrail.targetNode = self;
[debris6 addChild:debrisTrail];
debris6.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:25];
debris6.physicsBody.allowsRotation = NO;
debris6.physicsBody.categoryBitMask = CollisionDebris;
//set up a random position for debris
//RandomPosition = arc4random() %248;
//RandomPosition = RandomPosition + 10;
debris6.position = CGPointMake (302, self.size.height + 65);
[_debris6 addObject:debris6];
[self addChild:debris6];
//next Spawn:
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:deb6Time],
[SKAction performSelector:#selector(spawnDebris6) onTarget:self],
]]];
if (_dead == YES) {
[self removeAllActions];
}
if (debris6.position.y > 568) {
[self removeFromParent];
}
}
Each of the NSMutableArrays appear over time - The first one appears at 0s, 2 # 10s, 3 # 40s, 4 #80s, etc. And when a new one appears I've added code to make former ones appear less frequently and also removed some (to lower the frame rate) yet I still notice a slower frame rate after about 90 seconds.
I don't see why this would be affecting the frame rate as I've minimised the particle birth rate, and life span, and made an effort to delete and slow down spawn rates of the debris over time. Why is the FPS rate slowly depreciating?
If more info is needed please let me know and I'll update this post.
I had a similar problem. It is probably the SKEmitterNodes. Continue to play around with them and lower birth rates and life spans, maybe even range etc. If the problem persists, see if you can take them out. It may not look as good, but sometimes you have to sacrifice looks for functionality. Also I'd recommend maybe having the debris appear at different times and heights, so you still have a full screen, but also a smooth running screen.
I write the code for scrolling image in background of game. Simply define two sprite and set their position.
CGSize screenSize=[[CCDirector sharedDirector]winSize];
sky1 = [CCSprite spriteWithFile:#"sky1.png"];
sky1.position=ccp(screenSize.width/2, screenSize.height/2);
[self addChild:sky1];
CCLOG(#"sky1 position width=%f height=%f",sky1.position.x,sky1.position.y);
sky2=[CCSprite spriteWithFile:#"sky2.png"];
sky2.position=ccp(screenSize.width/2, sky1.position.y+sky1.contentSize.height/2+sky2.contentSize.height/2);
[self addChild:sky2];
[self schedule:#selector(scroll:) interval:0.01f];
And write the code for scrolling in scroll method:
-(void)scroll:(ccTime)delta{
CGSize screen=[[CCDirector sharedDirector] winSize];
CCLOG(#"come from schedule method pos.y=%f",sky1.position.y);
sky1.position=ccp(sky1.position.x, sky1.position.y-1);
sky2.position=ccp(sky2.position.x, sky2.position.y-1);
if(sky1.position.y <= -([sky1 boundingBox].size.height));
{
sky1.position=ccp(sky1.position.x, sky2.position.y+[sky2 boundingBox].size.height);
CCLOG(#"COMING IN first ifin scroll mwthod position width=%f pos.y=%f",sky1.position.x,sky1.position.y);
}
if(sky2.position.y<= -[sky2 boundingBox].size.height);
{
sky2.position=ccp(sky2.position.x, sky1.position.y+[sky1 boundingBox].size.height);
CCLOG(#"coming in secnond if ");
}
}
When I remove the if conditions then it works properly for one time. I don't know what is wrong with my condition and what the hell is going on with my code.
Can anybody explain?
I'm not too sure why your code isn't working properly. One thought that pops in my head is your interval may be too short. In other words, 0.01f (1/100) is shorter than your game update speed which is most likely 0.016 (1/60). So first thing I would try is tweaking your interval to maybe 0.02f. You could also drop the interval argument from the schedule call so it just runs once every frame. I would also try dropping the ccTime argument since it isn't being used.
[self schedule:#selector(scroll)];
-(void)scroll {}
But besides all that, this is probably best handled using CCActions. This looks like a simple pair of CCMoveTo actions combined with a CCRepeatForever to get the effect you want. This is the way I would go.
EDIT: here is a bit more detail about using CCActions to accomplish this. There are multiple ways of doing the same thing, but here is one you could try:
float moveDuration = 3; // or however fast you want it to scroll
CGPoint initialPosition = ccp(screenSize.width/2, screenSize.height/2);
CGPoint dp = ccp(0, -1*sky1.contentSize.height); // how far you want it to scroll down
CCMoveBy *scrollSky1 = [CCMoveBy actionWithDuration:moveDuration position:dp];
CCMoveTo *resetSky1 = [CCMoveTo actionWithDuration:0 position:initialPosition];
CCSequence *sequence = [CCSequence actionOne:scrollSky1 two:resetSky1];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:sequence];
[sky1 runAction:repeat];
Perhaps this question have been repeated many time, but I couldn't found helpful material. Also this is my first project in cocos2D, i want to implement the ProgressBar, CCProgressTimer in cocos2D. I have two sprites, first is moving and the second one is the player (to which you can move), If user successfully eat the first moving object then the progress should be incremented else if it misses then the progress will be decremented. I need your help. Thanks in advance.
Here is my code I used for rounded CCProgressTimers (it looks like clock). You possibly need to have a background sprite and a "movable" sprite above background sprite.
CCSprite *movableSprite = [CCSprite spriteWithFile:#"health100.png"];
CCProgressTimer *healthBar = [CCProgressTimer progressWithSprite:movableSprite];
healthBar.type = kCCProgressTimerTypeRadial; // This is for round progress timer. Possible value for horizontal bar will be kCCProgressTimerTypeHorizontalBarLR
healthBar.midpoint = ccp(0,0.5); // Here is where all magic is
healthBar.barChangeRate = ccp(1, 0); // If you need horizontal bar progress play with these parameters.
// Here we will start an animation process.
// You can do it without animation just setting up healthBar.progress = 45.0f; (45%)
[healthBar runAction:[CCProgressFromTo actionWithDuration:2.0f from:0.0f to:100.0f]];
healthBar.position = ccp(100, 100); // It's your position
[self addChild:healthBar];
I thought doing a simple animation would be easy but is is taking hours and Im not getting even close to have the expected effect...
I need to simulate a simple Flash Motion Tween like for iphone/ipad using xcode
this is the desired effect: http://www.swfcabin.com/open/1340330187
I already tried setup a timer adding X position and it doens't get the same effect, my cooworkers suggested me cocos 2d to do this using actions and sprites, which might would be fine although I wouldn't like to third party frameworks, but if there is a way to do the same with cocos I would definitively use it.
Does anybody have any suggestions, I feel like it might be simpler than I thought
thanks all
If there is no troubles to you, that you will have to do it insinge OpenGL view, it is really very simple. To show some info, you need CCLabel class. To change it's position, you need CCMoveTo/CCMoveBy action, to change opacity, you need CCFadeTo/CCFadeIn/CCFadeOut actions, to make delay you need CCDelayTime. To make it all work together you need CCSpawn and CCSequence.
CCSpawn will run several actions at the same time(for example fade in and move from right to the center), CCSequence will run several actions one by one (sequence to fade in + move to center, delay for same time, sequence to fade out + move from center to the left). Then you should only schedule method, that will create labels and run actions on them. In code it will be something like
lets define full animation time
#define ANIMATION_TIME 4.f
schedule method in any place you want to start animation
[self schedule:#selector(runNextMessage) interval:ANIMATION_TIME];
it will call runNextMessage method every ANIMATION_TIME seconds
- (void) runNextMesage
{
NSString* message = //get next message
CCLabelTTF* label = [CCLabelTTF labelWithString:message
dimensions:desiredDimensionsOfTheLabel
alignment:UITextAlignmentLeft
lineBreakMode:UILineBreakModeWordWrap
fontName:#"Arial"
fontSize:20.f];
CGSize winSize = [[CCDirector sharedDirector] winSize];
// place the label out the right border
[label setPosition: ccp(winSize.width + label.contentSize.width, winSize.height / 2)];
// adding it to the screen
[self addChild:label];
ccTime spawnTime = ANIMATION_TIME / 3;
// create actions to run
id appearSpawn = [CCAction actionOne:[CCMoveTo actionWithDuration:spawnTime]
two:[CCFadeIn actionWithDuration:spawnTime]];
// create show action and disappear action
// create result sequence
id sequence = [CCSequence actions: appearSpawn, showAction, disappearAction, nil];
[label runAction: sequence];
}