Cocos2d. Rotate point around another point without hard math calculations? - cocos2d-iphone

I haven't seen easy examples about rotaion around a specified point. I tried something like this but it doesn't work:
//CCNode *node is declared
//In a function of a subclass of CCSprite
- (void)moveWithCicrlce
{
anchorNode = [CCNode node];
anchorNode.position = ccpSub(self.position, circleCenter);
anchorNode.anchorPoint = circleCenter;
[anchorNode runAction:[CCRotateBy actionWithDuration:1 angle:90]];
[self runAction:[CCRepeatForever actionWithAction:[CCSequence actions:[CCCallFunc actionWithTarget:self selector:#selector(rotate)], [CCDelayTime actionWithDuration:0.1], nil]]];
}
- (void)rotate
{
self.position = ccpAdd(anchorNode.position, anchorNode.anchorPoint);
}

Here's how you can rotate a node (sprite etc) around a certain point P (50,50) with a radius (distance from P) of 100:
CCNode* center = [CCNode node];
center.position = CGPointMake(50, 50);
[self addChild:center];
// node to be rotated is added to center node
CCSprite* rotateMe = [CCSprite spriteWithFile:#"image.png"];
[center addChild:rotateMe];
// offset rotateMe from center by 100 points to the right
rotateMe.position = CGPointMake(100, 0);
// perform rotation of rotateMe around center by rotating center
id rotate = [CCRotateBy actionWithDuration:10 rotation:360];
[center runAction:rotate];

My approximate solution:
#interface Bomb : NSObject {
CCSprite *center;
}
...
#end
and some methods:
- (void)explode
{
BombBullet *bullet = [BombBullet spriteWithFile:#"explosion03.png"];
[[[CCDirector sharedDirector] runningScene] addChild:bullet];
center = [CCSprite spriteWithTexture:bullet.texture];
center.position = explosionPoint;
center.anchorPoint = ccp(-0.5, -0.5);
center.visible = NO;
[[[CCDirector sharedDirector] runningScene] addChild:center];
[center runAction:[CCRotateBy actionWithDuration:1 angle:360]];
CCCallFunc *updateAction = [CCCallFuncN actionWithTarget:self selector:#selector(update:)];
[bullet runAction:[CCRepeatForever actionWithAction:[CCSequence actions:updateAction, [CCDelayTime actionWithDuration:0.01], nil]]];
}
- (void)update:(id)sender
{
BombBullet *bombBullet = (BombBullet *)sender;
bombBullet.rotation = center.rotation;
bombBullet.position = ccpAdd(center.position, center.anchorPointInPoints);
bombBullet.position = ccpAdd(bombBullet.position, ccp(-bombBullet.contentSize.width / 2, -bombBullet.contentSize.height / 2));
bombBullet.position = ccpRotateByAngle(bombBullet.position, center.position, bombBullet.rotation);
}
of course I should add sprite deleting.

Related

How to add multiple sprites with time interval of 3 seconds and run same CCAction for all in cocos2d

Please help me as am fed with the searches and new to cocos 2d. Only am getting is the last sprite got moving if i schedule addRed and i want all the sprites moving randomly in the screen. Any help will be Appreciated and thanks in advance.
-(void)addRed
{
redSprite = [CCSprite spriteWithImageNamed:#"Red.png"];;
CGSize screenSize = [[CCDirector sharedDirector] viewSize];
[redSprite setPosition:CGPointMake(screenSize.width/2, screenSize.height/2)];
[self resizeSprite:redSprite toWidth:80 toHeight:80];
[self addChild:redSprite z:10];
[self gameStart];
}
- (void)gameStart {
// Create the actions
CGSize result = [[UIScreen mainScreen] bounds].size;
CGPoint nextPoint;
if (redSprite.position.x == result.width-40.0) {
nextPoint.x = redSprite.position.x - kAccelXAxis;
backx = YES;
}
else {
if (redSprite.position.x == 40.0) {
nextPoint.x = redSprite.position.x + kAccelXAxis;
backx = NO;
}
else {
if (backx) {
nextPoint.x = redSprite.position.x - kAccelXAxis;
}
else
{
nextPoint.x = redSprite.position.x + kAccelXAxis;
}
}
}
if (redSprite.position.y == 40.0) {
nextPoint.y = redSprite.position.y + kAccelYAxis;
backy = YES;
}
else {
if (redSprite.position.y == result.height-40.0) {
nextPoint.y = redSprite.position.y - kAccelYAxis;
backy = NO;
}
else {
if (backy) {
nextPoint.y = redSprite.position.y + kAccelYAxis;
}
else
{
nextPoint.y = redSprite.position.y - kAccelYAxis;
}
}
}
CCAction *myAction = [CCActionSequence actions:[CCActionMoveTo actionWithDuration:0.01 position:nextPoint], [CCActionCallFunc actionWithTarget:self selector:#selector(gameStart)], [CCActionCallFunc actionWithTarget:self selector:#selector(updateCol:)],nil];
[myAction setTag:10];
[redSprite runAction:myAction];
}
Try creating a updater with an interval of 3 sec for creating your sprites. For your created sprites, use a CCRepeatForever which will generate your next positions for your sprite.
For your case, I also thought about using a custom CCSprite to store your next position to move.
You will need something like...
[self schedule:#selector(createSprite) interval:(3)]; //to schedule your sprite generator
// Your sprite generator with action
-(void)createSprite{
CCCustomRed *red = [CCCustomRed spriteWithFile:#"red.png"];
[self addChild:red];
CCCallFuncN *changePos = [CCCallFuncN actionWithTarget:self selector:#selector(setRandomPos:)];
CCMoveTo *move = [CCMoveTo actionWithDuration:1 position:red.nextPosition];
CCDelayTime *delay = [CCDelayTime actionWithDuration:1.0];
[red runAction:[CCRepeatForever actionWithAction:[CCSequence actions:move,changePos,delay,nil]]];
}
//Generate a random pos as your sprite next move
-(void)setRandomPos:(id)sender{
CCCustomRed *red = (CCCustomRed *) sender;
CGSize screenSize = [[CCDirector sharedDirector] winSize];
red.nextPosition = ccp(arc4random()%screenSize.width,arc4random()%screenSize.height);
}
Hope it helps :)

How to get perfect collision between 2 sprite in cocos 2D

I have 2 sprite. for collide i use bounding box. But its not perfect collision. its collide with transparent image also. i need perfect collision.
Suppose i have :
CCSprite *sprite1 = [CCSprite spriteWithFile:#"image.png"];
CCSprite *sprite2 = [CCSprite spriteWithFile:#"image.png"];
if (CGRectIntersectsRect([sprite1 boundingBox], [sprite2 boundingBox]))
{
// Collision Detected ....
}
But its create a prob . its collide but not perfectly collide.
anybody can help me? Thanks in advance
CCSprite *player = [CCSprite spriteWithFile:#"image.png"];
[self addChild:player];
CCSprite *enemy = [CCSprite spriteWithFile:#"image.png"];
[self addChild:enemy];
float pos_x = player.position.x - enemy.position.x;
float pos_y = player.position.y - enemy.position.y;
float pos_xy = (pos_x * pos_x) + (pos_y * pos_y);
float Collision = (10+5) * (10+5); // Let 10 be the radious of player & 5 be the radious of enemy
if (pos_xy <= Collision)
{
// Collision Detected
}
// But its is only for round shaped image . like: Ball.
And its create perfect collision using pythagorean Theorm

Move a whole animation sprite sheet

I have some sprite-sheet that i have to animate forever , and i would like to add it as a CCLayer
to my scene .
Later on , i have to move this whole animation sprite on the screen.
So, for example, i have some animation of a dog walking, from sprite sheet, this one is running forever. than i want to be able to move this dog on screen while animating.
What is the best way to do this ? (or the right way)
This is how i animate the frames :
CCSprite *boom;
boom = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#_00000.png",file]];
boom.position=touch;
[self addChild:boom];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 0; i < 5; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:
#"%#_0000%i.png",file,i]];
[animFrames addObject:frame];
}
CCAnimation* boxAnimation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.075f];
CCAnimate * boxAction = [CCAnimate actionWithAnimation:boxAnimation];
CCAction *call=[CCCallBlock actionWithBlock:^{[self removeFromParentAndCleanup:YES];}];
CCAction * sequence=[CCSequence actions:boxAction,[CCHide action],call,nil];
[boom runAction:sequence];
return self;
How would you move this whole thing ?
There are a few ways to do this. If you are not preocupied with collision detection, then one way would be to :
CGPoint egressPosition = ccp(0,0); // figure this out in your app
float moveDuration = 1.5f ; // whatever time you compute for desired speed and distance
id move = [CCMoveTo actionWithDuration:moveDuration position:egressPosition];
id spawn = [CCSpawn actions:sequence,move,nil];
[boom runAction:spawn];
otherwise, using your code as is
[self schedule:#selector(moveBox:)]; // optional, you could do this in update method
[boom runAction:sequence];
-(void) moveBoom:(CCTime) dt {
CGPoint newPosition;
delta = ccp(dt*speedX,dt*speedY); // crude , just to get the idea
newPosition = ccpAdd(boom.position,delta);
// here you can figure out collisions at newPosition before the collision
// and do whatever seems appropriate
boom.position = newPosition;
}

Cocos2d iPhone CCClippingNode doesn't do the clip

Here are my code how I am trying to draw an image and a hole on it. (The code is from the cocos2d test project)
CCSprite *target = [CCSprite spriteWithFile:#"blocks.png"];
target.anchorPoint = CGPointZero;
target.scale = 3;
CCClippingNode *outerClipper_ = [[CCClippingNode clippingNode] retain];
outerClipper_.contentSize = CGSizeApplyAffineTransform(target.contentSize, CGAffineTransformMakeScale(target.scale, target.scale));
outerClipper_.anchorPoint = ccp(0.5, 0.5);
outerClipper_.position = ccpMult(ccpFromSize([CCDirector sharedDirector].winSize), 0.5);
outerClipper_.stencil = target;
CCClippingNode *holesClipper = [CCClippingNode clippingNode];
holesClipper.inverted = YES;
holesClipper.alphaThreshold = 0.05;
[holesClipper addChild:target];
CCNode *holes_ = [[CCNode node] retain];
[holesClipper addChild:holes_];
CCNode *holesStencil_ = [[CCNode node] retain];
holesClipper.stencil = holesStencil_;
[outerClipper_ addChild:holesClipper];
[self addChild:outerClipper_ z:9999];
// Add the hole
CCSprite *hole = [CCSprite spriteWithFile:#"hole_effect.png"];
hole.position = [outerClipper_ convertToNodeSpace:ccpMult(ccpFromSize([CCDirector sharedDirector].winSize), 0.5)];
[holes_ addChild:hole];
CCSprite *holeStencil = [CCSprite spriteWithFile:#"hole_stencil.png"];
holeStencil.position = [outerClipper_ convertToNodeSpace:ccpMult(ccpFromSize([CCDirector sharedDirector].winSize), 0.5)];
[holesStencil_ addChild:holeStencil];
All the images can be found in the cocos2d test project.
The problem is that the images appear, but there is no hole on it. What I am doing wrong?
The problem was that I didn't setup my CCGLView correctly. I have to setup the depth format to GL_DEPTH24_STENCIL8_OES instead of the value 0.

Cocos2d/Box2d strange behavior for kinematic bodies

I'm developing a very simple game. Here's my enemy class named Machine's behavior code:
#import "Machine.h"
#implementation Machine
+(id)machineWithWorld:(b2World*)world position:(CGPoint)pos
{
return [[[self alloc] initWithWorld:world position:pos] autorelease];
}
-(id)initWithWorld:(b2World*)world position:(CGPoint)pos
{
if(self = [super initWithShape:[AppDelegate renameFrameForIpad:#"machine"] inWorld:world])
{
size = [CCDirector sharedDirector].winSize;
self.body->SetTransform([Helper toMeters:pos], 0.0);
self.body->SetType(b2_staticBody);
safetyCounter = 5;
[self schedule:#selector(machineSafetyCounter)];
movementWidthInMeters = (size.width-self.contentSize.width)/PTM_RATIO;
linearSpeed = 0.5;
[self schedule:#selector(startMoving) interval:1.5];
}
return self;
}
#pragma mark<Machine Behavior>
-(void)startMoving
{
[self unschedule:_cmd];
float distanceFromCenterInMeters = (size.width/2 - self.position.x)/PTM_RATIO;
float interval = ABS(distanceFromCenterInMeters/linearSpeed);
if(interval < 0.01f)
interval = 0.02f;
b2Vec2 motionDirection = (distanceFromCenterInMeters > 0.0f) ? b2Vec2(1.0, 0.0) : b2Vec2(-1.0, 0.0);
self.body->SetType(b2_kinematicBody);
self.body->SetLinearVelocity(linearSpeed*motionDirection);
[self schedule:#selector(startMotionFromBeginning) interval:interval-0.01];
CCLOG(#"startMoving distance-->%f, interval-->%f", distanceFromCenterInMeters, interval);
}
-(void)startMotionFromBeginning
{
[self unschedule:_cmd];
float interval = (movementWidthInMeters/2)/linearSpeed;
self.body->SetLinearVelocity(0.5*b2Vec2(1.0, 0.0));
[self schedule:#selector(moveRTL) interval:interval-0.01];
[self schedule:#selector(checkIfHelmetIsBelowMachine) interval:0.1];
CCLOG(#"startMotionFromBeginning interval-->%f", interval);
}
-(void)moveRTL
{
[self unschedule:_cmd];
float interval = movementWidthInMeters/linearSpeed;
self.body->SetLinearVelocity(0.5*b2Vec2(-1.0, 0.0));
[self schedule:#selector(moveLTR) interval:interval-0.01];
CCLOG(#"moveRTL interval-->%f", interval);
}
-(void)moveLTR
{
[self unschedule:_cmd];
float interval = movementWidthInMeters/linearSpeed;
self.body->SetLinearVelocity(0.5*b2Vec2(1.0, 0.0));
[self schedule:#selector(moveRTL) interval:interval-0.01];
CCLOG(#"moveLTR interval-->%f", interval);
}
-(void)checkIfHelmetIsBelowMachine
{
[self unschedule:_cmd];
Helmet* helmet = (Helmet*)[[[[[CCDirector sharedDirector] runningScene] children] objectAtIndex:0] getChildByTag:kTagHelmet];
float helmetPosX = helmet.position.x;
if((self.position.x > helmetPosX) && (self.position.x < helmetPosX+helmet.contentSize.width))
{
[self unscheduleAllSelectors];
[self schedule:#selector(machineSafetyCounter) interval:0.1];
[self schedule:#selector(startMovingDownwards) interval:0.0];
return;
}
[self schedule:_cmd interval:0.1];
}
-(void)startMovingDownwards
{
[self unschedule:_cmd];
self.body->SetLinearVelocity(0.25*b2Vec2(0.0, -1.0));
[self schedule:#selector(stopMovingDownwards) interval:1.0];
CCLOG(#"startMovingDownwards");
}
-(void)stopMovingDownwards
{
[self unschedule:_cmd];
self.body->SetLinearVelocity(b2Vec2(0.0, 0.0));
[self schedule:#selector(startMoving) interval:0.2];
CCLOG(#"stopMovingDownwards");
}
All I have done is following:
1) The body is static initially and is positioned at ccp(size.width*0.5, size.height*0.75).
2) After 1.5 seconds, It becomes kinematic and starts moving with a linear speed of 0.5 m/s.
3) It checks it's current distance (from screen width center keeping height same), evaluates the time needed to reach that spot, and then starts moving in that direction horizontally.
4) After reaching that spot, it starts it's signature motion, it starts moving from Left to right, if at any time helmet(another game object) passes underneath it, it starts moving down and stops after 1.0 seconds, then whole cycle repeats.
5) It moves LTR & RTL until it starts to move down when it finds the helmet underneath it.
Now the problem is, sometimes the behavior is exactly same as expected.
And many many times, it starts moving upwards and I have never set the y bit for motion vector in positive direction.
After initializing the body, you should not change its bodyType. When you first make the body, set it as kinematic so you don't run into problems later when trying to change it. Is the body attached to a CCSprite? If so, you should make the class a subclass of CCSprite so you can use [super initWithFile:(NSString *) world:(b2World *)] or some method of your choosing to facilitate your endeavors.