I've got a CCSprite with three animations: idle, walk and attack. I want to switch between idle and walk depending on whether or not the sprite is moving (if the joystick is beeing used). All of this works great.
For the attacking animation, I want it to run once, and then return to the previous animation when done (ex.: idle) how do I detect when the animation is done?
thanks,
Dave
Alright, so here's what i've done, and it works, although I have no clue if its the right or the best way:
1) store the current animation.
2) If the currentAnimation is attacking, do nothing.
3) when switching between animations, if the new animation is attacking, run a sequence on the sprite, the second action being a callback to a "onDoneAttacking"
4) in the callback, change the current animation
But this isn't veery smooth and it doesn't allow to attack very fast.
Here's what it looks like:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack" )
{
CCFiniteTimeAction *action = [CCAnimate actionWithAnimation:[self animationByName:name]];
CCRepeat *repeatAction = [CCRepeat actionWithAction:action times:1];
if(name == #"attack") {
id doneAttacking = [CCCallFunc actionWithTarget:self selector:#selector(onDoneAttacking)];
[self runAction:[CCSequence actionOne:repeatAction two:doneAttacking]];
}
else {
[self runAction:repeatAction];
}
currentAnimation = name;
}
}
-(void) onDoneAttacking {
currentAnimation = #"idle";
}
Related
I have a ball object that falls straight down a level made in SpriteBuilder as a layer. The level is added to the gameplay scene, which has a ccnode (_levelNode) as a child of the physics node. However, when the game runs it either doesn't scroll, or the view is messed up.
My code is:
- (void)didLoadFromCCB {
//_physicsNode.debugDraw = TRUE;
_loadedLevel = [CCBReader load:#"levels/Level1" owner:self];
[_levelNode addChild: _loadedLevel];
}
- (void)onEnter {
[super onEnter];
self.userInteractionEnabled = TRUE;
self.isGamePaused = FALSE;
_followBall = [CCActionFollow actionWithTarget:_ball worldBoundary:[_loadedLevel boundingBox]];
[_physicsNode runAction:_followBall];
}
When I do this:
[gameLayer pauseSchedulerAndActions];
Most of the game pauses, but the sprites that are undergoing this action do not pause spinning:
[sprite runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle: 360]]];
Also, those sprites that are running CCAnimations do not stop animating:
CCAnimation *theAnim = [CCAnimation animationWithSpriteFrames:theFrames delay:0.1];
CCSprite *theOverlay = [CCSprite spriteWithSpriteFrameName:#"whatever.png"];
self.theAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:theAnim]];
How can I get these to pause when the game is paused? I would expect “pauseSchedulerAndActions” to pause actions, but that doesn’t seem to be the case.
pauseSchedulerAndActions is not recursive, so it will only affect actions and schedules on the node you are pausing, not it's children.
if your scene/layer is shallow, you could probably just get away with looping through the layer's children and calling (pause/resume)SchedulerAndActions on each, otherwise, if you have a deeper graph, you'll probably want to call it recursively. I wrote up a small test and this worked for me:
-(void) pauseSchedulerAndActions: (BOOL) pause forNodeTree:(id)parentNode shouldIncludeParentNode:(BOOL)includeParent
{
if(includeParent)
{
(pause) ? [parentNode pauseSchedulerAndActions] : [parentNode resumeSchedulerAndActions];
}
for( CCNode *cnode in [parentNode children] )
{
(pause) ? [cnode pauseSchedulerAndActions] : [cnode resumeSchedulerAndActions];
if(cnode.children.count > 0)
{
[self pauseSchedulerAndActions:pause forNodeTree:cnode shouldIncludeParentNode:NO]; // on recurse, don't process parent again
}
}
}
so in your case you could try calling this method and passing in your gameLayer
Try [[CCDirector sharedDirector] pause]; It should pause all animations and movements.
Does anyone know of an easy way to animate a CCMenuItem when the mouse passes over it.
I have read this thread:
Cocos2d CCMenuItem animation upon selection
which seems to cover Cocoa Touch but does not work for me with OS X.
The cocos2d reference lists this method of CCMenuItemImage: which I used this way:
CCMenuItem *beginButtonMenuItem = [CCMenuItemImage itemWithNormalImage:#"BeginButton3.png"
selectedImage:#"BeginButtonSel3.png"
target:self
selector:#selector(beginButtonPressed:)];
However that menu item does not respond by changing the image when the mouse passes over, only when clicked.
the CCMenuItem reference has this method:
(void) selected, stating "The item was selected (not activated), similar to "mouse-over""
but has no sample code ...
Can anyone help implement this?
Thanks
I found it to be quite easy to make the CCMenu change any CCMenuItem to the selected state when the mouse passes over it, giving it a hover effect. First, make sure you've set [window_ setAcceptsMouseMovedEvents:YES];
Then add this function to CCMenu.m (perhaps just after ccMouseDragged definition):
- (BOOL) ccMouseMoved:(NSEvent *)event {
if( ! _visible || ! _enabled)
return NO;
CCMenuItem *currentItem = [self itemForMouseEvent:event];
if(!currentItem) {
if(_highlightedItem != _selectedItem) {
[_highlightedItem unselected];
}
[_highlightedItem release];
_highlightedItem = nil;
return NO;
}
if (currentItem != _highlightedItem) {
[_highlightedItem unselected];
_highlightedItem = currentItem;
[_highlightedItem retain];
[_highlightedItem selected];
}
return YES;
}
I have one question when infinite background scrolling is done, is the object remain fixed(like doodle in doodle jump, papy in papi jump) or these object really moves.Is only background move or both (background and object )move.plz someone help me.I am searching for this solution for 4/5 days,but can't get the solution.So plz someone help me. And if object does not move how to create such a illusion of object moving.
If you add the object to the same layer as the scrolling background, then it will scroll as the background scrolls.
If your looking for an effect like the hero in doodle jump, you may want to look at having two or more layers in a scene.
Layer 1: Scrolling Background Layer
Layer 2: Sprite layer
SomeScene.m
CCLayer *backgroundLayer = [[CCLayer alloc] init];
CCLayer *spriteLayer= [[CCLayer alloc] init];
[self addChild:backgroundLayer z:0];
[self addChild:spriteLayer z:1];
//Hero stays in one spot regardless of background scrolling.
CCSprite *squidHero = [[CCSprite alloc] initWithFile:#"squid.png"];
[spriteLayer addChild:squidHero];
If you want objects to scroll with the background add it to the background layer:
//Platform moves with background.
CCSprite *bouncePlatform= [[CCSprite alloc] initWithFile:#"bouncePlatform.png"];
[backgroundLayer addChild:bouncePlatform];
Another alternative is to use a CCFollow action. You would code as if the background is static (which it will be) and the player is moving (which it will be), but add a CCFollow action to the player. This essentially moves the camera so that it tracks your player.
You can also modify the classes so that you can get the CCFollow action to follow with an offset (i.e., so the player is not in the middle of the screen) as well as to have a smoothing effect to it, so that when the player moves, the follow action is not jerky. See the below code:
*NOTE I am using cocos2d-x, the c++ port. The methods are similar in cocos2d, and you should be able to modify these to fit the cocos2d syntax. Or search around -- I found these for cocos2d and then ported to c++.
//defines the action to constantly follow the player (in my case, "runner.p_sprite is the sprite pointing to the player)
FollowWithOffset* followAction = FollowWithOffset::create(runner.p_sprite, CCRectZero);
runAction(followAction);
And separately, I have copied the class definition for CCFollow to create my own class, CCFollowWithAction. This also has a smoothing effect (you can look this up more online) so that when the player moves, the actions are not jerky. I modified "initWithTarget," to take into account an offset, and "step," to add a smoothing action. You can see the modifications in the comments below.
bool FollowWithOffset::initWithTarget(CCNode *pFollowedNode, const CCRect& rect/* = CCRectZero*/)
{
CCAssert(pFollowedNode != NULL, "");
pFollowedNode->retain();
m_pobFollowedNode = pFollowedNode;
if (rect.equals(CCRectZero))
{
m_bBoundarySet = false;
}
else
{
m_bBoundarySet = true;
}
m_bBoundaryFullyCovered = false;
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_obFullScreenSize = CCPointMake(winSize.width, winSize.height);
//m_obHalfScreenSize = ccpMult(m_obFullScreenSize, 0.5f);
m_obHalfScreenSize = CCPointMake(m_obFullScreenSize.x/2 + RUNNER_FOLLOW_OFFSET_X,
m_obFullScreenSize.y/2 + RUNNER_FOLLOW_OFFSET_Y);
if (m_bBoundarySet)
{
m_fLeftBoundary = -((rect.origin.x+rect.size.width) - m_obFullScreenSize.x);
m_fRightBoundary = -rect.origin.x ;
m_fTopBoundary = -rect.origin.y;
m_fBottomBoundary = -((rect.origin.y+rect.size.height) - m_obFullScreenSize.y);
if(m_fRightBoundary < m_fLeftBoundary)
{
// screen width is larger than world's boundary width
//set both in the middle of the world
m_fRightBoundary = m_fLeftBoundary = (m_fLeftBoundary + m_fRightBoundary) / 2;
}
if(m_fTopBoundary < m_fBottomBoundary)
{
// screen width is larger than world's boundary width
//set both in the middle of the world
m_fTopBoundary = m_fBottomBoundary = (m_fTopBoundary + m_fBottomBoundary) / 2;
}
if( (m_fTopBoundary == m_fBottomBoundary) && (m_fLeftBoundary == m_fRightBoundary) )
{
m_bBoundaryFullyCovered = true;
}
}
return true;
}
void FollowWithOffset::step(float dt)
{
CC_UNUSED_PARAM(dt);
if(m_bBoundarySet){
// whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased
if(m_bBoundaryFullyCovered)
return;
CCPoint tempPos = ccpSub( m_obHalfScreenSize, m_pobFollowedNode->getPosition());
m_pTarget->setPosition(ccp(clampf(tempPos.x, m_fLeftBoundary, m_fRightBoundary),
clampf(tempPos.y, m_fBottomBoundary, m_fTopBoundary)));
}
else{
//custom written code to add in support for a smooth ccfollow action
CCPoint tempPos = ccpSub( m_obHalfScreenSize, m_pobFollowedNode->getPosition());
CCPoint moveVect = ccpMult(ccpSub(tempPos,m_pTarget->getPosition()),0.25); //0.25 is the smooth constant.
CCPoint newPos = ccpAdd(m_pTarget->getPosition(), moveVect);
m_pTarget->setPosition(newPos);
}
}
I am making a slot machine game in iphone. I am using cocos2d as its language. I am greatly disturb coding for the method that will animate score in the game. The animation looks like with the fps. Can you help me do it. Animating the score in cocos2d. Can you share sample code that looks like what i need now. Thanks in advance.
Here is how I do my score. it is not really animated, but if you want it to be like fps this will do it. Just call this method when your score changes.
in your init method:
// create and initialize the _scoreLabel
_scoreLabel = [CCLabel labelWithString:#" "
dimensions:CGSizeMake(labelSizes.width,labelSizes.height)
alignment:UITextAlignmentLeft
fontName:#"Helvetica"
fontSize:20.0];
_scoreLabel.color = ccc3(255,255,255);
_scoreLabel.position = ccp((labelSizes.width / 2), (winSize.height - (labelSizes.height / 2)));
[self addChild:_scoreLabel z:1];
This is the score update method:
-(void)updateScore {
[_scoreLabel setString:[NSString stringWithFormat:#"Score: %d / %d", _score, _scoreToWin]];
}
Then to update the score when the score changes call it like this:
// Then later to set the Score
[self updateScore];
I've done it in this way:
_odd = _odd + _stage*value;
[self schedule:#selector(pointAdder) interval:1.0/(3.0*_odd)];
and
- (void)pointAdder {
if (_odd==0) {
[self unschedule:#selector(pointAdder)];
return;
}
else {
int tmp = [_lblScore.string intValue];
[_lblScore setString:[NSString stringWithFormat:#"%i",tmp+1]];
_odd--;
}
}