Following the tutorial for the breakout game I've created 3 sprites with their own bodies - ball and 2 paddles. My question might be very simple so sorry, I'm still learning. Anyway, my problem is unlike in the example, my sprites are scaled i.e.:
-(id)init {
p1 = [CCSprite spriteWithFile:#"1.png"];
p1.position = ccp(160, winSize.height * 0.08);
p1.scaleX = 190 / 2 / p1.contentSize.width;
p1.scaleY = 58 / 2 / p1.contentSize.height;
b2BodyDef p1BodyDef;
p1BodyDef.type = b2_dynamicBody;
p1BodyDef.position.Set(160/PTM_RATIO, 40/PTM_RATIO);
p1BodyDef.userData = p1;
_p1Body = _world->CreateBody(&p1BodyDef);
b2PolygonShape p1Shape;
p1Shape.SetAsBox(p1.contentSize.width/PTM_RATIO/2, p1.contentSize.height/PTM_RATIO/2);
b2FixtureDef p1ShapeDef;
p1ShapeDef.shape = &p1Shape;
p1ShapeDef.density = 0.3f;
p1ShapeDef.friction = 1.0f;
p1ShapeDef.restitution = 0.0f;
_p1Fixture = _p1Body->CreateFixture(&p1ShapeDef);
}
After creating the body, I created an update method which detect the collision between my paddle and ball using the contact listener. This works okay however, I noticed while testing the game that there are instances wherein the ball bounces even though it hasn't collided with the actual sprite's position like around 2-3cm off for both the top and sides of the paddle. I suspect that this is because the shape of my polygon and the scale-x and -y of my sprite are different. So my question is, how can I set the body's size to be the same as the scaled sprite? I tried something like:
p1Shape.SetAsBox(190 / 2 / p1.contentSize.width/PTM_RATIO/2, 58 / 2 / p1.contentSize.height/PTM_RATIO/2);
But the collision was ignored as if the body wasn't there at all. So how do I make the b2body of my paddle the same size of the paddle sprite if it's been scaled?
I'm not 100% sure but I think I figured it out after some more research. Here's how I set the shape of the body:
p1Shape.SetAsBox(p1.contentSize.width/PTM_RATIO/2 * p1.scaleX, p1.contentSize.height/PTM_RATIO/2 * p1.scaleY);
I can't say for certain that this is the correct solution since I don't have debug draw enabled and I can't figure out just yet how to make it work but judging from the collisions after trying to run some tests on my game, this seems like it fixed my problem. If there's anybody else who might think there's a more correct way of doing this, please let me know. Thanks
Related
i'm losing myself in this...
Situation:
Working on a game in cocos2d with box2d and I have a ropejoint between one fixed body and one dynamic body.
When I drop the dynamic body is swings from left to right and then from right to left due to the gravity in the world.
The problem:
The swings are getting shorter and shorter till finally the dynamic body hangs still beneath the fixed body. This is normal behavior but I need it to keep swinging.
My thoughts:
I think I need to apply a tangential force to the ropejoint in the direction of the swinging but how to do this is a mystery for now :)
Try setting the damping factor of the rope joint to zero
ropeJointDef.dampingRatio = 0.0f;
Hope it helps!
Here is a little code that should help you with your little problem
bool YourClass::init(){
CCCallFunc *swingL = CCCallFunc::create(this,callfunc_selector(YourClass::swingLeft));
CCDelayTime *delay = CCDelayTime::create(5);
CCCallFunc *swingR = CCCallFunc::create(this, callfunc_selector(YourClass::swingRight));
this->runAction(CCRepeatForever::create(CCSequence::create(swingL,delay,swingR,NULL)));
}
void YourClass::swingLeft(){
b2Body *dynamicBody = get your body from b2world;
dynamicBody->SetLinearVelocity(b2Vec2(-10, 0));//set velocity of the swing
}
void YourClass::swingRight(){
b2Body *dynamicBody = get your body from b2world;
dynamicBody->SetLinearVelocity(b2Vec2(10, 0));//set velocity of the swing
}
I've looked around quite a bit and haven't been able to find a concise answer to this question. For my Cocos2D game I have integrated the Chipmunk physics engine. On initialization, I setup the boundaries of the 'playing field' by establishing a series of bodies and static shapes as follows:
- (void)initPlayingField {
// Physics parameters
CGSize fieldSize = _model.fieldSize;
CGFloat radius = 2.0;
CGFloat elasticity = 0.3;
CGFloat friction = 1.0;
// Bottom
CGPoint lowerLeft = ccp(0, 0);
CGPoint lowerRight = ccp(fieldSize.width, 0);
[self addStaticBodyToSpace:lowerLeft finish:lowerRight radius:radius elasticity:elasticity friction:friction];
// Left
CGPoint topLeft = ccp(0, fieldSize.height);
[self addStaticBodyToSpace:lowerLeft finish:topLeft radius:radius elasticity:elasticity friction:friction];
// Right
CGPoint topRight = ccp(fieldSize.width, fieldSize.height);
[self addStaticBodyToSpace:lowerRight finish:topRight radius:radius elasticity:elasticity friction:friction];
// Top
[self addStaticBodyToSpace:topLeft finish:topRight radius:radius elasticity:elasticity friction:friction];
}
This setup works, except for one thing-- the positions of the boundaries appear to be off by a significant amount of pixels to the right. After initializing a player, and sending him towards the boundary walls, it does not bounce off the edges of the screen (as I would expect by setting up the bounding box at 0,0), but rather some number of pixels (maybe 30-50) inwards from the edges of the screen. What gives?
I initially thought the issue came from where I was rendering the player sprite, but after running it through the debugger, everything looks good. Are there special protocols to follow when using chipmunk's positions to render sprites? Do I need to multiply everything by some sort of PIXELS_PER_METER? Would it matter if they are in a sprite sheet? A sprite batch node? Here is how I set the sprite position in my view:
Player *player = [[RootModel sharedModel] player];
self.playerSprite.position = player.position;
self.playerSprite.rotation = player.rotation;
And here is how I set the position in my Model:
- (void)update:(CGFloat)dt {
self.position = self.body->p;
self.rotation = self.body->a;
}
(Yes, I know it's redundant to store the position because chipmunk does that inherently.)
Also, bonus question for for those who finished reading the post. How might you move a body at a constant velocity in whatever direction it is facing, only allowing it to turn left or right at any given time, but never slow down?
What's the shape of the physics body? Perhaps you simply forgot to consider making the shape the same size of the sprite. If you only consider the position, then the sprite will be able to move halfway outside the screen at any border because its position is at the center of the sprite.
To move a body at constant velocity, set its velocity while disabling friction (set to 0?) and allowing it to rebound off of collisions with its impact speed (in Box2D that would be restitution = 1, don't know about Chipmunk).
Have you tried debug drawing the collision shapes? Cocos2D 2.1 has my CCPhysicsDebugNode class in it that makes it pretty easy to add. That will let you know if your geometry is lined up with your graphics. How thick are your boundary shapes? Are you possibly adding the sprites to a parent node that might be offsetting them?
Chipmunk doesn't require you to tune it for any real units. You can just use pixels or whatever.
Lastly, #LearnCocos2D has the right idea about the constant velocity. Set friction to 0 and elasticity to 1.0. You will also probably want to check it's velocity every frame and accelerate it back towards it's normal velocity each frame. Colliding with non-static geometry will cause it to lose speed.
For the past days, I've been trying to make a ping pong like game. I have 2 paddles and a ball. All dynamic sprites. Everything's been working well except for one issue I'm having. The ball tends to bounce on the same angle at some point. So there would be times when the player can simply move the paddle on a specific part and the game can go on for a while or might be forever, since the ball doesn't change its angular velocity regardless of which part of the paddle it hits. I'm using a combination of linear and angular velocity to keep the ball moving like so:
if(_isPaused == FALSE)
{
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if(sprite.tag == 2)
{
b2Vec2 dir = b->GetLinearVelocity();
dir.Normalize();
float currentSpeed = dir.Length();
int maxSpeed = 60;
float accelerate = vel;
if(currentSpeed <= maxSpeed)
{
b->SetLinearVelocity(accelerate * dir);
}
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
//Keep sprite from bouncing in a straight angle
b->SetAngularVelocity(_body->GetAngle());
}}}
So my question is, how can I manipulate the angular velocity to keep the ball bouncing on different angles everytime it collides with my paddle? I'm thinking something like getting the current angular velocity then multiplying it with some value but I'm not sure if that's the right way to approach the issue I'm having. Any suggestions or ideas would be greatly appreciated. Thanks in advanced.
The way I see it, you have two options:
Check the location of a collision. If it's close to the top/bottom edge of the paddle, deflect the outgoing velocity by an angular amount proportional to the surface "curvature" at that point. Of course, this is cheating, but if the artwork and code are in agreement, it looks correct. And graphics is "the art of cheating without getting caught".
You could take into account the current velocity of the paddle as well as that of the ball. Eg: if the ball is moving downwards and to the right, and the paddle is moving down, then you can compute the outgoing direction using conservation of linear momentum. Just make sure you restrict the paddle's change in momentum along the horizontal axis to be zero.
Finally, you could combine the above techniques, but now you'd have to use accurate collision detection (not the hack I described in (1) above).
Hope that helps!
A few pointers, you should use SetLinearVelocity() and SetAngularVelocity() rarely. Each alters a property of the body definition, which could make you run into problems later on when things get more complex. It would be better to use ApplyForceToCenter() or ApplyLinearImpulse() in the place of SetLinearVelocity() as these two are much more versatile functions and are a bit more coder-friendly. In my opinion, I don't think you should use b->SetAngularVelocity(_body->GetAngle()); If you wanted to change the angular velocity each time it collided, you could, in your beginContact method, write that every time the body collides with the paddle body, a random angular impulse is applied to the ball, using ApplyAngularImpulse().Hope that helps.
I try to detect collision between two sprite.
if(CGRectIntersectsRect([SpriteA BoundingBox], [SpriteB boundingBox]))
But when i Rotate any sprite than collision detection is not perfect..
I know to use pixel perfect Collision but i have no idea about it.
Please anyone help me for how to detect collision, Give me any block of code if any.
You can use box2d to make it detect all collisions for you
In two ways you can do.
Use box2D body for your sprite. Example: CLICK HERE
Use CGMutablePathRef, and use CGPathContainsPoint() instead of CGRectIntersectsRect.
Example: CLICK HERE
You can also refere the Ray Wenderlich Tutorial for the detection of the Collision between any 2 Box2D bodies.
it's possible! try with CGPath.
I had the same problem. I've resolved with this tutorial: http://bobueland.com/cocos2d/2011/the-magic-of-cgpaths/
for rotate the path try this method, it rotated the path round the center of the boudingBox:
-(CGPathRef) rotateCGPath:(CGPathRef)path corner:(CGFloat)radians
{
CGRect bounds = CGPathGetBoundingBox(path);
CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGAffineTransform transf = CGAffineTransformIdentity;
transf = CGAffineTransformTranslate(transf, center.x, center.y);
transf = CGAffineTransformRotate(transf, -radians);
transf = CGAffineTransformTranslate(transf, -center.x, -center.y);
return CGPathCreateCopyByTransformingPath(path, &transf);
}
after this you detect the collision simple with:
if (CGPathContainsPoint(Collisionpath, NULL, collisionPoint, NO))
{ //is inside the path }
good luck!
I have an arrow sprite, and it is for aiming purposes in my Cocos2d game. Therefore, I want it to point to where the user touches the screen. How do I program the rotation of the sprite so it will rotate to the user's touch location? Thanks!
These tutorials may be helpful:
http://www.learn-cocos2d.com/knowledge-base/cocos2d-iphone-faq/learn-cocos2d-public-content/manual/cocos2d-general/14826-how-to-rotate-a-sprite-in-a-circular-motion/
http://www.raywenderlich.com/2343/how-to-drag-and-drop-sprites-with-cocos2d
Also, this question is asked (with code) and answered (with more code) here: Rotating Sprite with Touch - Cocos2d
I haven't actually done this before, but I have adapted some of my code (that makes a enemy ship face the player ship) to what you need. Hopefully this is correct.
//rotate to face the touch
CGPoint diff = ccpSub(sprite.position, touch.position);
float angleRadians = atanf((float)diff.y / (float)diff.x);
float angleOffset = CC_DEGREES_TO_RADIANS(90);
if(diff.x < 0)
{
angleRadians += angleOffset;
}
else
{
angleRadians -= angleOffset;
}
PengOne's answer (cool name BTW) was great though and I am voting it up because you should make use of it.