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

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

Related

cocos2d v3 chipmunk collision method not firing

ok so i've been messing around with chipmunk a bit, and i can get two sprites to bounce off of each other, but when i try to use the following method, it never fires,
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair tower:(CCNode *)nodeA BG:
(CCNode *)nodeB
{
NSLog(#"HELLO");
return YES;
}
Heres where I create the physics node:
_physics = [CCPhysicsNode node];
_physics.debugDraw = YES;
[self addChild:_physics z:1];
_physics.collisionDelegate = self;
I use this code to create the first sprite:
background = [CCSprite spriteWithImageNamed:gameLevelImage];
[background setPosition:ccp(winSize.width/2,winSize.height/2)];
background.physicsBody.collisionType = #"BG";
background.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:self.position];
and this for the other :
tower = [[TowerType alloc] initWithTheGame:self location:ccp(winSize.width/2, winSize.height/2)];
[towers addObject:tower];
[self MenuItemsVisible];
tower.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:tower.position];
tower.physicsBody.collisionType = #"tower";
I also have the protocol in the h file.
if anyone knows whats happening help would be greatly appreciated. (:
First of all, are both bodies under the same CCPhysicsNode?
Second, ccPhysicsCollisionBegin is just called when the collision BEGIN, so as both of your bodies are one over the other and they aparenttly will move together due to gravity the collision will never begin, because they started colliding. The cycle for collision evaluation is:
ccPhysicsCollisionBegin: called once both bodies start colliding
ccPhysicsCollisionPreSolve: called every frame update, before physics calculations
ccPhysicsCollisionPostSolve : called every frame, after physics calculations
ccPhysicsCollisionSeparates: called once they separate
Make sure your sprites are allocated properly before you try to set the collisionType. That was the issue for me in my similar case.

How to change ZOrder in a CCSequence?

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.

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/

Repeatedly move a box2d body in a similar way to moving CCSprites with CCRepeatForever

I've got a problem with my current project.
What I'd like to do is make a b2Body move up and down repeatedly. I already know how to do this with a CCSprite:
[paddle runAction:[CCRepeatForever actionWithAction:
[CCSequence actions:
[CCMoveTo actionWithDuration:1.0 position:ccp([paddle position].x,[paddle position].y+40)],
[CCMoveTo actionWithDuration:1.0 position:ccp([paddle position].x,[paddle position].y)],
nil
]]];
Can anybody help me do the same thing with a b2Body?
Thanks in advance!
You will have to implement the sequence yourself, which involves:
keeping track of the current target position
from the current position of the body, detect whether it has reached the target
if it has, change the target position
apply force, impulse or set velocity as necessary to move the body
You might be able to extend CCMoveTo to make your own class to do this... I would look into that first.
i've got it dude,
in almost explanation, every CCsprite move depend on b2body movement -that movement is placed at 'tick' method-.
in my case, i reverse that way, i move b2body according to CCsprite movement on tick method, so i give these code on tick method:
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if (sprite.tag == 4 || sprite.tag == 5) {
b2Vec2 b2Position = b2Vec2(sprite.position.x/PTM_RATIO,
sprite.position.y/PTM_RATIO);
float32 b2Angle = -1 * CC_DEGREES_TO_RADIANS(sprite.rotation);
b->SetTransform(b2Position, b2Angle);
}
}
}