How to apply gravity on specific body - libgdx

Applying gravity to the physics world is easy, you just need to create a Vector2 and set its horizontal and vertical gravity value. What if I want to create a top-down 2D game with zero gravity, and only apply gravity to specific body like a projectile motion of an arrow. Of course it's easy to have an projectile motion if you set your world to have a gravity at first.
float GRAVITY_EARTH = -9.8f;
Vector2 gravity = new Vector2(0, GRAVITY_EARTH);
World world = new World(gravity, true);
Box2d body class has a method that cancel or reverse the gravity, but I don't want to use it every time, just like in the below code example.
body.setGravityScale(0); // set 0 to cancel the gravity, and set -1 to reverse the gravity
But I want to be versatile, I want to apply gravity to specific body only. For example I'm using the method setLinearVelocity to move the body to specific destination. Now if the world has the gravity y of -9.8f it will automatically have a projectile motion.
Vector2 initialVelocity = targetPoint.sub(originPoint).nor();
initialVelocity.scl(speed); // to apply constant speed
body.setLinearVelocity(initialVelocity);
I tried increment the initial velocity of y to -9.8 to apply gravity. But it didnt work, what am I missing?
initialVelocity.y += -9.8f;
body.setLinearVelocity(initialVelocity);
// or
body.applyForce(initialVelocity, body.getWorldCenter(), true);

The gravity is a force, not a velocity.
Calling something like
Vector2 gravity = new Vector2(0, GRAVITY_EARTH);
body.applyForceToCenter(gravity, true);
in the step function should do it. Please note that you need to apply the force at every frame since they are cleared.

You have to apply the opposing force in every step to cancel out gravity.
See the answers of this question for other options.

Related

Rotation issue While Reflected (2D Platform Game)

My player's arm is programmed to follow my mouse and rotate accordingly and I've programmed bullets to be fired using this rotational value
(Math.atan2(this._dy, this._dx) * 180 / Math.PI
where _dy is the y location of the mouse (-) the y of my player's arm and the _dx is the x location of mouse (-) the y of my player's arm.
However, when I program the player to reflect when the mouse has crossed the x-coordinates, the bullet angle is also reflected. How would I fix this issue?
I've already tried subtracting 180 from the angle but it still doesn't fire towards the direction of the mouse.
First, make sure you have this parent-child-sibling relationship:
"A" should be the parent of "B" and "C". "B" and "C" should have no direct link. Their connection is that they have the same parent. So when you want to move the character, move the parent, and both will move. Now, for the good stuff:
Use key frames and sibling relationship
beginner level approach
Make the character and the arm both children of the same parent display object container (Movie Clip in this case). Now, instead of flipping anything by xScale, which I assume you did, you can just have both MC children (arm and character) go to frame 2 (or whatever is available) where the graphics are flipped.
xScale body, move arm to frame 2, change z order
moderate level approach (best result)*
Alternatively, you could do that same "sibling" setup as above, and then scale the character but not the arm (I think scaling the arm will mess it up again, but you could have the arm go to frame 2 and have it drawn reversed so the thumb and handle are pointing the right way. Bonus points for changing the z stacking order so the arm goes to the other side of the body. xScale for only the body allows you to only have one set of frames for animation of his legs and torso etc. but also avoid scaling the arm at all).
Global properties
advanced approach
A third option is to use global rotation and global points. I won't illustrate that here because I'm not that advanced and it would take me a while to figure out the exact syntax. If you already have mastered global properties, try this; if not, try one of the ones above.
* Example (best result)
if (facingRight == true && stage.mouseX < totalChar.x){
// totalChar is on the stage
// and contains two children:
// armAndGun and bodyHeadLegs
totalChar.armAndGun.gotoAndStop(2);
// in frame 2 of the arm MC, draw the
// arm and gun in the flipped orientation
totalChar.addChild(bodyHeadLegs);
// re-ads body to parent so it's
// z-order is above the arm;
totalChar.bodyHeadLegs.xScale = -1;// flips body and any animation of legs and head
facingRight = false;
// use a variable or property like this
// to keep him from constantly flipping
}
You'll need similar code to flip him back the other way.

How to detect collision force?

Is there any way in cocos2d-x to detect collision force? I would like to make a different sound effects depending on collision force or disable sound effect at all in some cases.
For example: when I perform scaleTo action on my sprite that is lying on the ground, it starts changing it's size every moment and so it hits the ground every moment too. On every hit the application plays sound effect. I would like to play it only when my sprite falls from some real height.
Do you detect the collision in some update() function, isn't it? So, you need to remember object position on previous update() call. Something like this:
Vec2 previousPosition;
void YourClass::update(float dt)
{
…
this->detectCollision();
this->updatePhysics();
this->makeSomethingElse();
…
}
void YourClass::detectCollision()
{
currentPosition = yourObject->getPosition();
float distance = currentPosition.getDistance(previousPosition)
if (obstacleRect.intersectsRect(yourObjectRect))
{
// collide handler
if (distance == 0)
// do nothing
if (distance > threshold)
// play some sound
}
…
previousPosition = currentPosition;
…
}
Depends of distance between current and previous object location you can calculate object’s speed and estimate it force.
In your example, when object collides through ScaleTo, its position is stable, and distance and speed = 0.
If you move the object and the obstacle, the calculation of speed is more complicated and must be carried out according to the rules of vector addition

detect collision only on top of the object in box2d & cocos2dx

I am creating a game like bounce ball using cocos2d-x and box2d. I have different objects like rectangle, square etc.. I am able to detect collision, but i want to detect collision only on top of the objects. What exactly i want is, when the ball is on the top of the object, then only i want to jump the ball.
But, when the ball is collide on remaining side(bottom or left or right) i don't want to jump the ball.
In touchbegan, i am using the following code to the bounce ball. So every touch it is jumping when it collide with remaining side.
if(_ball->boundingBox().intersectsRect(rect->boundingBox()))
{
b2Vec2 force = b2Vec2(0, 550);
_body->ApplyLinearImpulse(force, _body->GetPosition());
}
Any advice?
Following steps can solve your problem-
1) CCRect projectileRect = CCRect(float x, float y, float width, float height);
if(_ball->boundingBox().intersectsRect(projectileRect))
{
b2Vec2 force = b2Vec2(0, 550);
_body->ApplyLinearImpulse(force, _body->GetPosition());
}
2) - Make body of an object and then check their collision.
I got the solution for my question from the below link.
http://www.raywenderlich.com/28606/how-to-create-a-breakout-game-with-box2d-and-cocos2d-2-x-tutorial-part-2

AS3 - Finding an objects x and y position relative to the stage

I'm new to ActionScript 3 and I have a character which you can control, the screen scrolls right along the stage and he can fire missiles.
The problem I'm getting is the missiles are created via these co-ords:
bullet.x = hero.mc.x;
bullet.y = hero.mc.y
These work fine untill the screen has scrolled to the right. I assume it's because the bullets are being spawned as a result of them using the canvas x,y and not the stages x,y
So i'm wondering how to find out the x and y of my hero in relative to the canvas so i can spawn the missiles on top of him!
Thanks, and if you need any more information let me know, I'm new to all this. Thank you.
You can do that with localToGlobal and globalToLocal. Your solution would be something like:
bulletPos = bullet.parent.localToGlobal(new Point(bullet.x, bullet.y));
Beware, though, as those are last resort functions. Normally, you'd have all your elements using the same 'layer', so comparisons are easier and faster.

How do I apply gravity to my bouncing ball application?

I've written a fairly simple java application that allows you to drag your mouse and based on the length of the mouse drag you did, it will shoot a ball in that direction, bouncing off walls as it goes.
Here is a quick screenshot:
alt text http://img222.imageshack.us/img222/3179/ballbouncemf9.png
Each one of the circles on the screen is a Ball object. The balls movement is broken down into an x and y vector;
public class Ball {
public int xPos;
public int yPos;
public int xVector;
public int yVector;
public Ball(int xPos, int yPos, int xVector, int yVector) {
this.xPos = xPos;
this.yPos = yPos;
this.xVector = xVector;
this.yVector = yVector;
}
public void step()
{
posX += xVector;
posY += yVector;
checkCollisions();
}
public void checkCollisions()
{
// Check if we have collided with a wall
// If we have, take the negative of the appropriate vector
// Depending on which wall you hit
}
public void draw()
{
// draw our circle at it's position
}
}
This works great. All the balls bounce around and around from wall to wall.
However, I have decided that I want to be able to include the effects of gravity. I know that objects accelerate toward the earth at 9.8m/s but I don't directly know how this should translate into code. I realize that the yVector will be affected but my experimentation with this didn't have the desired effect I wanted.
Ideally, I would like to be able to add some gravity effect to this program and also allow the balls to bounce a few times before settling to the "ground."
How can I create this bouncing-elastic, gravity effect? How must I manipulate the speed vectors of the ball on each step? What must be done when it hits the "ground" so that I can allow it to bounce up again, but somewhat shorter then the previous time?
Any help is appreciated in pointing me in the right direction.
Thanks you for the comments everyone! It already is working great!
In my step() I am adding a gravity constant to my yVector like people suggested and this is my checkCollision():
public void checkCollision()
{
if (posX - radius < 0) // Left Wall?
{
posX = radius; // Place ball against edge
xVector = -(xVector * friction);
}
else if (posX + radius > rightBound) // Right Wall?
{
posX = rightBound - radius; // Place ball against edge
xVector = -(xVector * friction);
}
// Same for posY and yVector here.
}
However, the balls will continue to slide around/roll on the floor. I assume this is because I am simply taking a percentage (90%) of their vectors each bounce and it is never truly zero. Should I add in a check that if the xVector becomes a certain absolute value I should just change it to zero?
What you have to do is constantly subtract a small constant (something that represents your 9.8 m/s) from your yVector. When the ball is going down (yVector is already negative), this would make it go faster. When it's going up (yVector is positive) it would slow it down.
This would not account for friction, so the things should bounce pretty much for ever.
edit1:
To account for friction, whenever it reverses (and you reverse the sign), lower the absolute number a little. Like if it hits at yVector=-500, when you reverse the sign, make it +480 instead of +500. You should probably do the same thing to xVector to stop it from bouncing side-to-side.
edit2:
Also, if you want it to react to "air friction", reduce both vectors by a very small amount every adjustment.
edit3:
About the thing rolling around on the bottom forever--Depending on how high your numbers are, it could be one of two things. Either your numbers are large and it just seems to take forever to finish, or you are rounding and your Vectors are always 5 or something. (90% of 5 is 4.5, so it may round up to 5).
I'd print out a debug statement and see what the Vector numbers are like. If they go to somewhere around 5 and just stay there, then you can use a function that truncates your fraction to 4 instead of rounding back to 5. If it keeps on going down and eventually stops, then you might have to raise your friction coefficient.
If you can't find an easy "rounding" function, you could use (0.9 * Vector) - 1, subtracting 1 from your existing equation should do the same thing.
When the balls are all rolling around on the ground, yes, check to see if the velocity is below a certain minimum value and, if so, set it to zero. If you look at the physics behind this type of idealized motion and compare with what happens in the real world, you'll see that a single equation cannot be used to account for the fact that a real ball stops moving.
BTW, what you're doing is called the Euler method for numerical integration. It goes like this:
Start with the kinematic equations of motion:
x(t) = x0 + vx*t + 0.5*axt^2
y(t) = y0 + vyt + 0.5*ayt^2
vx(t) = vx0 + axt
vy(t) = vy0 + ay*t
Where x and y are position, vx and vy are velocity, ax and ay are acceleration, and t is time. x0, y0, vx0, and vy0 are the initial values.
This describes the motion of an object in the absence of any outside force.
Now apply gravity: ay = -9.8 m/s^2
To this point, there's no need to do anything tricky. We can solve for the position of each ball using this equation for any time.
Now add air friction: Since it's a spherical ball, we can assume it has a coefficient of friction c. There are typically two choices for how to model the air friction. It can be proportional to the velocity or to the square of velocity. Let's use the square:
ax = -cvx^2
ay = -cvy^2 - 9.8
Because the acceleration is now dependent on the velocity, which is not constant, we must integrate. This is bad, because there's no way to solve this by hand. We'll have to integrate numerically.
We take discrete time steps, dt. For Euler's method, we simply replace all occurances of t in the above equations with dt, and use the value from the previous timestep in place of the initial values, x0, y0, etc. So now our equations look like this (in pseudocode):
// Save previous values
xold = x;
yold = y;
vxold = vx;
vyold = vy;
// Update acceleration
ax = -cvxold^2;
ay = -cvyold^2 - 9.8;
// Update velocity
vx = vxold + axdt;
vy = vyold + aydt;
// Update position
x = xold + vxold*dt + 0.5*axdt^2;
y = yold + vyolddt + 0.5*ay*dt^2;
This is an approximation, so it won't be exactly correct, but it'll look OK. The problem is that for bigger timesteps, the error increases, so if we want to accurately model how a real ball would move, we'd have to use very tiny values for dt, which would cause problems with accuracy on a computer. To solve that, there are more complicated techniques. But if you just want to see behavior that looks like gravity and friction at the same time, then Euler's method is ok.
Every time slice you have to apply the effects of gravity by accelerating the ball in teh y downwards direction. As Bill K suggested, that's as simple as making a subtraction from your "yVector". When the ball hits the bottom, yVector = -yVector, so now it's moving upwards but still accelarating downwards. If you want to make the balls eventually stop bouncing, you need to make the collisions slightly inelastic, basically by removing some speed in the y-up direction, possibly by instead of "yVector = -yVector", make it "yVector = -0.9 * yVector".
public void step()
{
posX += xVector;
posY += yVector;
yVector += g //some constant representing 9.8
checkCollisions();
}
in checkCollisions(), you should invert and multiply yVector by a number between 0 and 1 when it bounces on the ground. This should give you the desired effect
It's a ballistic movement. So you got a linear movement on x-axis and an uniform accelerated movement on y-axis.
The basic idea is that the y-axis will follow the equation:
y = y0 + v0 * t + (0.5)*a*t^2
Or, in C code, for example:
float speed = 10.0f, acceleration = -9.8f, y = [whatever position];
y += speed*t + 0.5f*acceleration*t^2;
Where here I use tiem parametrization. But you could use Torricelli:
v = sqrt(v0^2 + 2*acceleration*(y-y0));
And, on this model, you must maintain the last values of v and y.
Finally, I've done something similar using the first model with dt (time's differential) being fixed at 1/60 second (60 FPS).
Well, both models give good real-like results, but sqrt(), for example, is expensive.
You really want to simulate what gravity does - all it does is create force that acts over time to change the velocity of an object. Every time you take a step, you change the velocity of your ball a little bit in order to "pull" it towards the bottom of the widget.
In order to deal with the no-friction / bouncing ball settles issue, you need to make the "ground" collision exert a different effect than just strict reflection - it should remove some amount of energy from the ball, making it bounce back at a smaller velocity after it hits the ground than it would otherwise.
Another thing that you generally want to do in these types of bouncy visualizations is give the ground some sideways friction as well, so that when it's hitting the ground all the time, it will eventually roll to a stop.
I agree with what "Bill K" said, and would add that if you want them to "settle" you will need to reduce the x and y vectors over time (apply resistance). This will have to be a very small amount at a time, so you may have to change your vectors from int to a floating point type, or only reduce them by 1 every few seconds.
What you want to do is change the values of xVector and yVector to simulate gravity and friction. This is really pretty simple to do. (Need to change all of your variables to floats. When it comes time to draw, just round the floats.)
In your step function, after updating the ball's position, you should do something like this:
yVector *= 0.95;
xVector *= 0.95;
yVector -= 2.0;
This scales the X and Y speed down slightly, allowing your balls to eventually stop moving, and then applies a constant downward "acceleration" to the Y value, which will accumulate faster than the "slowdown" and cause the balls to fall.
This is an approximation of what you really want to do. What you really want is to keep a vector representing the acceleration of your balls. Every step you would then dot product that vector with a constant gravity vector to slightly change the ball's acceleration. But I think that my be more complex than you want to get, unless you're looking for a more realistic physics simulation.
What must be done when it hits the
"ground" so that I can allow it to
bounce up again
If you assume a perfect collision (ie all the energy is conserved) all you have to do reverse the sign of one of the velocity scalar depending on which wall was hit.
For example if the ball hits the right or left walls revese the x scalar component and leave the the y scalar component the same:
this.xVector = -this.xVector;
If the ball hits the top or bottom walls reverse the y scalar component and leave the x scalar component the same:
this.yVector = -this.yVector;
but somewhat shorter then the previous
time?
In this scenario some of the energy will be lost in the collision with the wall so just add in a loss factor to take of some of the velocity each time the wall is hit:
double loss_factor = 0.99;
this.xVector = -(loss_factor * this.xVector);
this.yVector = -(loss_factor * this.yVector;