This is re-question
I want to destroy bodies after collision but with an delay of 4-6 seconds.
I am successful in detection of collision & destruction of body after collision but now i want a delay in it.
I don't know how to delay.
Make One function which will take B2Body as argument and call that function with delay.
Call function like this:
std::vector<b2Body *>::iterator pos;
for(pos = bodyToDestroy.begin();pos != bodyToDestroy.end(); ++pos){
b2Body *body = *pos;
if(body->GetUserData() != NULL){
CCPhysicsSprite *sprite = (CCPhysicsSprite *) body->GetUserData();
[sprite removeFromParentAndCleanup:YES];
}
[self performSelector:#selector(myfunc) withObject:body afterDelay:4.0];
}
And The function will be
-(void)myfunc : (b2Body *)body{
world->destroyBody(body);
}
Related
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.
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.
In cocos2d, you can ease in CCSprites and move them around in all kinds of ways. Most importantly - they can have easing in/out. For most games this is desirable for smooth movement etc.
id action = [CCMoveTo actionWithDuration:dur position:pos];
move = [CCEaseInOut actionWithAction:action rate:2];
[self runAction: move];
When moving a box2d body, the sprite attached to it is updated after the box2d step(). Moving the sprite and then updating the body is not an option here, as it entirely defeats the purpose of the physics framework.
So the other option, which I have successfully implemented, is to calculate the displacement, velocity and acceleration of a sprite by treating it as a mechanics entity in its own right. Each time I call my update() on the sprite so the character can decide where to move etc, my superclass also stores the previous position and velocity. These are stored as box2d compliant values by dividing by the PTM_RATIO.
In the subclass of CCSprite, called FMSprite:
-(CGPoint) displacement {
return ccpSub(self.position, lastPos);
}
-(b2Vec2) getSpriteVelocity:(ccTime)dt {
return b2Vec2(self.displacement.x / dt / PTM_RATIO,
self.displacement.y / dt / PTM_RATIO);
}
-(b2Vec2) getSpriteAccel:(ccTime)dt {
b2Vec2 currVel = [self getSpriteVelocity:dt];
if (dt == 0) {
return b2Vec2(0,0);
} else {
float accelX = (currVel.x - lastVel.x)/dt;
float accelY = (currVel.y - lastVel.y)/dt;
return b2Vec2(accelX, accelY);
}
}
// This is called each update()
-(void) updateLast:(ccTime)dt {
// MUST store lastVel before lastPos is updated since it uses displacement
lastVel = [self getSpriteVelocity:dt];
lastPos = ccp(self.X, self.Y);
}
// Leave this method untouched in subclasses
-(void) update:(ccTime)dt {
[self updateObject:dt];
// Store previous update values
[self updateLast:dt];
}
// Override this method in subclasses for custom functionality
-(void) updateObject:(ccTime)dt {
}
I have then subclassed "FMSprite" into "FMObject", which stores a b2Body etc.
In order to move the body, I must first move a sprite and track its acceleration, through which I can find the required force (using the mass) needed to follow the sprite's motion. Since I can't move the object's sprite (which is synchronized to the body), I make another sprite called a "beacon", add it as a child to the object, and move it around. All we need to do then is to have a function to synchronize the position of the box2d body with this beacon sprite using the forces I mentioned before.
-(void) followBeaconWithDelta:(ccTime)dt {
float forceX = [beacon getSpriteAccel:dt].x * self.mass;
float forceY = [beacon getSpriteAccel:dt].y * self.mass;
[self addForce:b2Vec2(forceX, forceY)];
}
The result is brilliant, a smooth easing motion of the b2body moving where ever you want it to, without playing around with any of its own forces, but rather copying that of a CCSprite and replicating its motion. Since it's all forces, it won't cause jittering and distortions when colliding with other b2Body objects. If anyone has any other methods to do this, please post an answer. Thanks!
What I do is different from yours, but can also Moving Box2d Bodies Like CCSprite Objects and even use the CCAction.
The most important thing is to create an object that contain ccSprite and b2body.
#interface RigidBody : CCNode {
b2Body *m_Body;
CCSprite *m_Sprite;
}
And then, rewrite the setPosition method.
-(void)setPosition:(CGPoint)position
{
CGPoint currentPosition = position_;
b2Transform transform = self.body->GetTransform();
b2Vec2 p = transform.p;
float32 angle = self.body->GetAngle();
p += [CCMethod toMeter:ccpSub(position, currentPosition)];
self.body->SetTransform(p, angle);
position_ = position;
}
The setPosition method calculate how much the position change,and set it to the b2body.
I hope I have understanding your question and the answer is helpful for you...
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);
}
}
}
I use the following to to interchange only the position of 2 sprite.
CCSprite *sprite1 = (CCSprite*)[self getChildByTag:tagOfFirstSprite];
CCSprite *sprite2 = (CCSprite*)[self getChildByTag:tagOfSecondSprite];
CGPoint SpritePosition1 = [sprite1 position];
CGPoint SpritePosition2 = [sprite2 position];
[sprite1 runAction:[CCMoveTo actionWithDuration:1.0 position:ccp(SpritePosition2.x, SpritePosition2.y)]];
[sprite2 runAction:[CCMoveTo actionWithDuration:1.0 position:ccp(SpritePosition1.x, SpritePosition1.y)]];
These are box2d body.But it doesn't work.......any idea??
I assume that you are using Box2D sample template which implements the "tick()" function that is continuously called by the scheduler. This function calls the world->step() function and the updates the position of the box2D bodies and then update the position of your sprites according to the new position of box2D bodies.
When you just call the runAction, it doesn't effect the position of your Box2D bodies, so each time tick() function will be called, the position of your sprites will be set according to the position of box2D bodies.
Now even if your runAction is moving your sprites, it gets reset after couple of times every second when tick() function is called.
I hope you understand.