How to change ZOrder in a CCSequence? - cocos2d-iphone

I would like to know how to change the ZOrder of a CCSprite in a CCSequence. I have tried using CCCallBlock as suggested in another thread but it has bugged out and stops the other sprites of the same class moving. Is there another method someone can suggest?
crystalEntryPoint = [self position];
float xD = [crystal position].x - crystalEntryPoint.x;
float yD = [crystal position].y - crystalEntryPoint.y;
CGPoint dest = ccp(crystalEntryPoint.x + (xD * 2),crystalEntryPoint.y + (yD * 2));
float easingRate = 2;
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:1 position:dest];
CCMoveTo *moveBack = [CCMoveTo actionWithDuration:1 position:crystalEntryPoint];
CCEaseInOut *easeTo = [CCEaseInOut actionWithAction:moveTo rate:easingRate];
CCEaseInOut *easeBack = [CCEaseInOut actionWithAction:moveBack rate:easingRate];
CCCallBlock *zOrderBehind = [CCCallBlock actionWithBlock:^{ [self setZOrder:kManaSpriteBehindCrystalZValue]; }];
CCCallBlock *zOrderInFront = [CCCallBlock actionWithBlock:^{ [self setZOrder:kManaSpriteZValue]; }];
CCSequence *seq = [CCSequence actions:easeTo,zOrderBehind,easeBack,zOrderInFront,nil]; //,zOrderInfront
CCRepeatForever *rep = [CCRepeatForever actionWithAction:seq];
[self runAction:rep];

Try CCCallBlockN which gives the block the node running the action as parameter. The current setup retains self inside the block which may cause the node not to dealloc later on because the sequence runs forever and thus holds a strong self-reference until the node deallocates - I can't say if cocos2d is able to clean it up properly, it should but it might not.
Not sure if this is related to your issue or not but it seems to me a likely explanation considering everything else in the code snippet looks fine.
CCCallBlockN *zOrderBehind = [CCCallBlockN actionWithBlock:^(CCNode* node){
[node setZOrder:kManaSpriteBehindCrystalZValue];
}];
CCCallBlockN *zOrderInFront = [CCCallBlockN actionWithBlock:^(CCNode* node){
[node setZOrder:kManaSpriteZValue];
}];
If that doesn't work either then try CCActionTween which allows changing any property by name.
id zOrderChange = [CCActionTween actionWithDuration:0.0
key:"zOrder"
from:kManaSpriteZValue
to:kManaSpriteZValue];
I'm not sure if from / to having the same value will work. If it doesn't try using 0 as the from parameter and perhaps even increasing duration to some low value like 0.01.

Related

CCEaseIn etc inside CCSequence

How do you exactly use easing inside CCSequence?
Related to Using CCEaseOut together with CCSequence?
here is an example. This brings back my mapNode to the left border, for example when a LHS menu is popped out. Move duration and acceleration are computed as a function of the expected displacement :
- (void)setLeftClamp:(float)leftClamp {
_leftClamp = leftClamp;
CGPoint currentPosition = self.mapNode.position;
if (currentPosition.x > self.maxX) {
// ease right back in position
CGPoint delta = ccp (self.maxX - currentPosition.x, 0);
id move = [CCMoveBy actionWithDuration:[self moveDuration:delta] position:delta];
id ease = [CCEaseIn actionWithAction:move rate:[self moveAcceleration:delta]];
id delay = [CCDelayTime actionWithDuration:.1f];
id easeAndCenter = [CCSequence actions:ease, delay, [CCCallFunc actionWithTarget:self selector:#selector(onMoveComplete)], nil];
[self.mapNode runAction:easeAndCenter];
targetMapLocation_ = ccpAdd(self.mapNode.position, delta);
mapDisplacement_ = delta;
isMapMoving_ = YES;
}
}

put sprites hidden on screen,than fade them in

I need to put some CCsprites on screen that later on will be fade in to screen.
I cant hide them ,because the CCFade action will not work on hidden sprite , or a sprite with opacity=0 .
What i do is put them on screen and fade them out :
[colors[i] runAction:[CCFadeOut actionWithDuration:0]];
[self addChild:colors[i] z:0];
it turned out that fading out in zero time is not unseen, so they appear for a second the moment i add them to CCScene.
How would i put them on screen to be unseen, and than fade them in with CCFadeIn action ?
You can stack actions using a sequence. See the example below from one of my projects :
CCSprite *frame1 = [CCSprite spriteWithSpriteFrame:[frames objectAtIndex:0]];
frame1.flipX = self.flipX;
frame1.scale = self.scaling;
frame1.visible = NO;
frame1.opacity = 255;
frame1.rotation = self.rotation;
frame1.position = self.offset;
animation = [CCAnimation animationWithSpriteFrames:frames delay:(duration / self.numberOfFrames)];
id stall = [CCDelayTime actionWithDuration:delay];
id show = [CCShow action];
id animate = [CCAnimate actionWithAnimation:animation];
id hide = [CCHide action];
id clean = [CCCallBlock actionWithBlock:^{
[frame1 removeFromParentAndCleanup:YES];
}];
id enchiladas = [CCSequence actions:stall, show, animate, hide, clean, nil];
[node addChild:frame1 z:5];
[frame1 runAction:enchiladas];
Similar thing. I want to run an animation that will appear after a set delay time, then vanish and cleanup after itself when complete.
YOU can use sprite.opacity =0; initially
and in actions you can increase the opacity

Cocos2d - Orbiting/spinning one sprite around another

I've got to sprites, essentially a nucleus (parent) and an electron (child). I'm trying to find a way to have the electron orbit the nucleus. I've found a few posts here and there on moving anchor points, but that is apparently related to the texture of the sprite, not the sprite itself.
This is my current init method for my parent sprite:
self = [super init];
if (self) {
CCSprite *orbitAnchor = [CCSprite new];
[self addChild:orbitAnchor];
orbitAnchor.position = ccp(32,32);
CCSprite *orbiter = [CCSprite spriteWithFile:#"line.png" rect:CGRectMake(0, 0, 8, 8)];
[orbitAnchor addChild:orbiter];
orbiter.position = ccp(40,40);
CCAction *orbitAction = [CCRepeatForever actionWithAction:[CCRotateTo actionWithDuration:1 angle:720]];
[orbitAnchor runAction:orbitAction];
[self initAnimations];
}
return self;
Those numbers are all totally arbitrary though - I just stuck them in there and got what looked best. I'm sure there's a more programatic way to do what I want.
Basically, I'm looking for a way to set the child's axis point at the center of the parent, and then have it rotate around that point. It seems like a relatively simple thing to do using CCRotate and such, but I think I'm missing what to search for in order to move the anchor point of the child. Any suggestions/other posts?
Thanks
You have [CCSprite new] which is an unusual use, probably not supported. Unless the orbit anchor node should display a texture, you can just use a CCNode as anchor.
Technically you're doing everything correct from what I can see. You might want to try without the rotate actions and instead change the direction manually in a scheduled update method.
CCNode *orbitAnchor = [CCNode node];
[self addChild:orbitAnchor z:0 tag:1];
orbitAnchor.position = ccp(32,32);
CCSprite *orbiter = [CCSprite spriteWithFile:#"line.png" rect:CGRectMake(0, 0, 8, 8)];
[orbitAnchor addChild:orbiter z:0 tag:2];
orbiter.position = ccp(40,40);
[self scheduleUpdate];
Update method:
-(void) update:(ccTime)delta
{
CCNode* orbitAnchor = [self getChildByTag:1];
orbitAnchor.direction += 5;
}
From the image filename it looks like you're trying to draw a line from the orbitAnchor to the orbiter. You can do that with ccDrawLine:
-(void) draw
{
CCNode* orbitAnchor = [self getChildByTag:1];
CCNode* orbiter = [self getChildByTag:2];
ccDrawLine(orbitAnchor.position, orbiter.position);
}
Anchor points. Automatically, objects are placed based on the center of an object right? with anchor points you can move that around, so if you rotate the object it will rotate around the anchorpoint. http://www.qcmat.com/understanding-anchorpoint-in-cocos2d/

Run CCAction on multiple sprites

I have an array of sprites and run an action on each element. the issue I am having is that the last sprite is the only one that moves.
If I add 3 arrays and iterate through each and use the following
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:moveSequence];
[[row1 objectAtIndex:i] runAction:repeat];
it only move the last drawn sprite.
How does one run an action on every element in an Array?
I need the objects to move at the same time. So all sprites should run the action simultaneously. Is this possible with cocos2d
EDIT*****************
- (void) moveAliens
{
id left = [CCMoveBy actionWithDuration:10 position:ccp(-35, 0)];
id right = [CCMoveBy actionWithDuration:10 position:ccp(35, 0)];
id moveSequence = [CCSequence actions:left, [CCDelayTime actionWithDuration:20], right, [CCDelayTime actionWithDuration:20], nil];
id repeatMoveSequence = [CCRepeatForever actionWithAction:moveSequence];
for (int i = 0; i < [row1 count]; i++)
{
NSLog(#"i is %d", i);
//CCRepeatForever *repeat = [CCRepeatForever actionWithAction:moveSequence];
[[row1 objectAtIndex:i] runAction:repeatMoveSequence];
}
}
Thanks
Place:
left = [CCMoveBy actionWithDuration:10 position:ccp(-35, 0)];
right = [CCMoveBy actionWithDuration:10 position:ccp(35, 0)];
moveSequence = [CCSequence actions:left, [CCDelayTime actionWithDuration:20], right, [CCDelayTime actionWithDuration:20], nil];
repeatMoveSequence = [CCRepeatForever actionWithAction:moveSequence];
inside your for loop. And the variable declarations above it.
You can't use one CCAction for multiple CCNodes simultaneously.

How do you make a sprite rotate in cocos2D while using SpaceManager

I just have a simple sprite - how can I get it to rotate?
A good answer would show how to rotate both a dynamic sprite and a static_mass sprite
If the sprite is dynamic / non-static, just do like so:
cpBodySetAngVel(ObjSmSprite.shape->body,0.25);
For a static body, you can do something like this:
[ObjSmStaticSprite.shape runAction:[CCRepeatForever actionWithAction:
[CCSequence actions:
[CCRotateTo actionWithDuration:2 angle:180],
[CCRotateTo actionWithDuration:2 angle:360],
nil]
]];
smgr.rehashStaticEveryStep = YES; //Setting this would make the smgr recalculate all static shapes positions every step
To Summarize, here is a spinning static sprite, following be spinning dynamic sprite.
// Add Backboard
cpShape *shapeRect = [smgr addRectAt:cpvWinCenter mass:STATIC_MASS width:200 height:10 rotation:0.0f ];// We're upgrading this
cpCCSprite * cccrsRect = [cpCCSprite spriteWithShape:shapeRect file:#"rect_200x10.png"];
[self addChild:cccrsRect];
// Make static object update moves in chipmunk
// Since Backboard is static, and since we're going to move it, it needs to know about spacemanager so its position gets updated inside chipmunk.
// Setting this would make the smgr recalculate all static shapes positions every step
// cccrsRect.integrationDt = smgr.constantDt;
// cccrsRect.spaceManager = smgr;
// Alternative method: smgr.rehashStaticEveryStep = YES;
smgr.rehashStaticEveryStep = YES;
// Spin the backboard
[cccrsRect runAction:[CCRepeatForever actionWithAction:
[CCSequence actions:
[CCRotateTo actionWithDuration:2 angle:180],
[CCRotateTo actionWithDuration:2 angle:360],
nil]
]];
// Add the hoop
cpShape *shapeHoop = [smgr addCircleAt:ccp(winSize.width/2.0f,winSize.height/2.0f - 55.0f) mass:1.0 radius: 50 ];
cpCCSprite * cccrsHoop = [cpCCSprite spriteWithShape:shapeHoop file:#"hoop_100x100.png"];
[self addChild:cccrsHoop];
cpBodySetAngVel(cccrsHoop.shape->body,0.25);
Disclaimer: I'm trying to answer my own question, and this answer might be missing important subtleties - it just represents what I know, so far.
If using cocos2d
use this code in tick to update positon all time _number1.position is the position you would update to, so when _number1 moves _logo2 will rotate to face it
_logo2.rotation = CC_RADIANS_TO_DEGREES(-ccpToAngle(ccpSub(_number1.position, _logo2.position)));
update _logo1 rotation by touch put this code in touch event handler
_logo2.rotation = CC_RADIANS_TO_DEGREES(-ccpToAngle(ccpSub(location, _logo2.position)));
use this as an action
[_logo2 runAction:[CCRotateTo actionWithDuration:0.0 angle:CC_RADIANS_TO_DEGREES(-ccpToAngle(ccpSub(location, _logo2.position)))]];
hope this helps someone took me ages to work it out