Proper way to simulate bouncing in libgdx java - java

I am trying to find a good way to simulate bouncing in my 3D program. Here is how I am trying to do it: I am saying if the position.y < the limit (which is -5) then bounce back up. Here is the code
if(position.y > LIMITS.y)
velocity.y += Main.GRAVITY/ 1000;
else{
velocity.y = -velocity.y / 1.5f;
System.out.println(true);
}
However, the bouncing sometimes works and sometimes stops very short, if anyone knows why this is happening and can help me improve this I would be extremely appreciative.

So I think what you mean by stops very short is it is bouncing well then randomly stops at the bottom. This could be because the object goes more than 50% of it's distance that it will travel the next frame below the LIMIT of y. So the way to combat it is to reset the y position to its position before it went below.
else {
position.y -= velocity.y; // reset to position before going under
velocity.y = -velocity.y / 1.5f; // then adjust the velocity
System.out.println(true);
}

Related

How to stop a ball from bouncing after the position hasnt changed much libgx java

I am writing a physics engine and when the ball hits a surface it bounces up at half the velocity it came down at(velocity.y = -velocity). However when the ball is almost at rest it switches velocities constantly and starts falling through the platform incredibly slow but still will eventually fall through if I let it run long enough, and this is not acceptable. I tried writing some code to stop it but it checks way too fast here is the update method that attempts to check it.
public void update() {
velocity.y += Globals.GRAVITY.y;
if(canFall)
position.y += velocity.y;
position.x += velocity.x;
oldPosition.y = position.y;
oldPosition.x = position.x;
elapsedTime += 1 * Gdx.graphics.getDeltaTime();
if(elapsedTime >= 5){
if(oldPosition.y - 5 <= position.y && oldPosition.y + 5 >= position.y){
elapsedTime = 0;
canFall = false;
}else{
canFall = true;
elapsedTime = 0;
}
}
}
The collision handler knows when it hits the top of the ball which is the only solution I need for this. How do I check when the ball is at rest.
This code attempts to check if the ball hasn't moved in a couple seconds, if it hasn't it sets canFall to false. I need a generic check that will see if the ball should be at a stop. The velocity of the ball when it is falling through the platform you can see from the picture below. The picture shows the ball "at rest" after ten seconds so as you can see the ball is slowly but surely falling through. Every three seconds with this "rest" velocity the y position goes down 1, the velocity changes from positive to negative so the velocity you see in the picture isn't constantly negative. Ignore the elapsed time variable Any help is greatly appreciated!
Why let time have anything to do with it? I'm not saying it coudln't, but should it? So maybe lose the if(elapsedTime ... ) conditional.
Isn't this what you want? If the magnitiude of the vertical difference between the last two positions is negligible (set tolerance accordingly; maybe it's 5), stop bouncing:
if(Math.abs(position.y - oldPosition.y) < tolerance)
{
canBounce = false;
...
}
else
{
canBounce = true;
...
}
or, if nothing else needs to change at the ... above:
canBounce = Math.abs(position.y - oldPosition.y) > tolerance;
Also, don't you need { and } somewhere in the segment below? Maybe not, if ball is bouncing vertically, but it looks like x can change, too, which might make the code above need adjusting. But the way code below is indented makes me think there's supposed to be more to do than just changing position.y:
if(canFall)
position.y += velocity.y;
position.x += velocity.x;
oldPosition.y = position.y;
oldPosition.x = position.x;
Finally, you're addding velocity to position. That seems questionable. Multiply velocity times time? Or is time = 1 always? (Doubt it.)
The problem may be external to this method. Something needs to keep ball's y from becoming less than the y of the top of the dark blue box. This code can't do that without knowing y of top of dark blue box (unless you apply physics formulas?). Maybe include this value in parameter list as topOfDarkBlueBox?
Then add code such as:
if(position.y < topOfDarkBlueBox.y) position.y = topOfDarkBlueBox.y
I'd rather see physics at work, but you might say, "Who'd notice?"
EDIT
You wrote, "The collision handler knows when it hits the top of the ball," but I assume you meant "when the ball hits the top of the dark blue box". Maybe call the collision handler instead of passing new parameter topOfDarkBlueBox?

Shooting object based on arm rotation in libgdx java

I am trying to shoot an object(a spell) depending on the rotation of the players arm. The spell is supposed to come out of the hand and shoot towards where the mouse cicked(the arm rotates and points to where the mouse is). This is how the arm rotates in game.
public boolean mouseMoved(int screenX, int screenY) {
tmp.x = screenX;
tmp.y = screenY;
tmp.z = 0;
cam.unproject(tmp);
rot = MathUtils.radiansToDegrees * MathUtils.atan2((float)tmp.y - (float)player.getArmSprite().getY() - player.getArmSprite().getHeight(),
tmp.x -player.getArmSprite().getX() - player.getArmSprite().getWidth());
if (rot < 0) rot += 360;
//Last right or left means if hes looking left or right
if(player.lastRight)
player.setObjectRotation(rot + 80);
if(player.lastLeft)
player.setObjectRotation(-rot - 80);
And this is how the spell is supposed to shoot based off rotation
//destination is a vector of where on screen the mouse was clicked
if(position.y < destination.y){
position.y += vel.y * Gdx.graphics.getDeltaTime();
}
if(position.x < destination.x){
position.x += vel.x * Gdx.graphics.getDeltaTime();
}
However this is very wonky and never really reacts the way it supposed to with a few exceptions. It fires from the hand and then if the y axis is equal it completely evens out and goes till it reaches the x position, I want it to fire from the hand to the position clicks perfectly straight from point a to point b, this is clearly a rotation problem that I just can't seem to figure out how to tackle.
Here is an image of what is happening
Example image
The red indicates where I clicked, as you can see it reached the x pos first and now is traveling to the y when it should have reached the x and y pos of where I clicked first
Any help with this problem is extremely appreciated!
I'm pretty bad at radians and tangents but luckily we have vectors.
Since you have the rot ation in degrees of the arm. I advice to use Vectors to use for any Vector related math now.
//A vector pointing up
Vector2 direction = new Vector2(0, 1);
//Let's rotate that by the rotation of the arm
direction.rotate(rot);
Now direction is the direction the arm is pointing. If your rotation is calculated where up = 0. So you might need to rotate it 180, 90 or -90 degrees. Or in the case you did something silly any degrees.
Your spell should have a Vector too for it's position. Set that to the hand or wherever you want to start from. Now all you need to do is scale that direction since it's currently has a length of 1. If you want to move 5 units each frame you can do direction.scl(5) now it is of length 5. But technically speaking it's no direction anymore now everybody calls it velocity so let's do.
//when you need to fire
float speed = 5;
Vector2 velocity = direction.cpy().scl(speed);
//update
position.add(velocity);
draw(fireballImage, position.x, position.y);
I copied direction first, otherwise it would also be scaled. Then I just added the velocity to the position and draw using that Vector.
And to show Vectors are awesome you should see this awesome badlogic vs mouse program I created. https://github.com/madmenyo/FollowMouse there are just a view lines of my own code. It just takes a little bit of vector knowledge and it's very readable.

Slow down enemy movement

I'm making a game using slick2d - and ive created a pathfinding algorithm, that will allow a 'zombie' to find the shortest path to the main hero.
public void findPrey(int characterXPosition,int characterYPosition){
Pathfinder p = new Pathfinder();
n = p.aStar(xPosition,yPosition,characterXPosition,characterYPosition);
//n is a linked list which holds node objects in the path
if(!n.isEmpty()){
xPosition = (n.get(0).x);
yPosition = (n.get(0).y);
}
}
At the moment this works, but it just moves the zombie a tile (32x32) really quickly - like way too quickly!
I tried this instead:
if(xPosition > n.get(0).x){
xPosition -= .1f * delta;
}
else if(xPosition < n.get(0).x){
xPosition += .1f * delta;
}
if(yPosition < n.get(0).y){
yPosition += .1f * delta;
}
else if(yPosition > n.get(0).y){
yPosition -= .1f * delta;
}
Which only works if the zombie goes up or left - even then its really jumpy and if its meant to go down or right it goes mental and just keeps going up out of the screen.
So anyone any idea how I can either slow down the movement of the first technique - or know why the second one isnt working?
Thanks for any help!
EDIT - ANSWER
Okay figured a solution out - was pretty basic , I think just staring at the same code for a few hours did me.
In the render method of my 'world' class where the zombies were getting rendered I just put this change in:
Iterator<Zombie> i = zombies.iterator();
while (i.hasNext()) {
Zombie z = i.next();
if (!z.isDead()) {
z.updateDelta(newDelta);
z.incrementCounter(); //put a counter variable in
if(z.getCounter() % 40 == 0){
z.findPrey((int)shiftX,(int)shiftY);
}
z.render(gc, sbg, g);
}else{
i.remove();
}
}
So i basically just added a counter variable in the Zombie class and then used modular so that it wouldnt get called as frequently.
Thanks for everyone for trying to help.
I suggest you use timers. Then on every computer game will work with the same speed and the movement of your units will be with fixed time.
Units move too fast, because every loop unit is moved. Amount fo loops should be less or decrease the distance moved by units.

Bring Ball To A Stop

I have the following methods in my program which keep a ball continuously bouncing. I have tried modifying but can't seem to get the ball to stop at the bottom of my GUI. My main goal is to have the methods simulate as if you were bouncing a real ball.
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
UPDATE:
Ball bounces and stops at the bottom of the gui.
public void verticalBounce(Container container) {
deltaY = deltaY - gravity;
y = y + deltaY;
if (y > getHeight()) {
y = getHeight(); // reset location
deltaY = (int) (deltaY * -0.9); // slows down ball
}
}
None of that code looks correct. You need to implement the equation(s) of rectilinear motion:
http://en.wikipedia.org/wiki/Linear_motion
The one you need is s = ut + 0.5 * a * t * t, where
s = distance
u = an initial velocity - regard as the speed at which it hits the ground
a = acceleration due to gravity (you can probably have this pretty arbitrary)
t = time
You reverse the sign of a on the way up.
To simulate lossy bouncing, reduce u by taking a certain factor of energy E out of the system:
new_u * new_u = (1 - E)u * u.
(This comes from the formula for the kinetic energy of a moving body).
I can see from your question that you are capable of implementing this, so I won't provide code; just the physics.
First, a bouncing ball doesn't have a random element in it. Its all determined by the forces acting on the ball and the speed and direction of the ball. If you add a little randomness, it may make it look a little more realistic because of things like wind and unbalance in the ball but its very little.
To program it, assume the ball gets shot up from the ground at some speed. You need to store:
Y = location in units above the ground. Start at 0.
deltaY = speed in units per time interval. Negative is down. Positive is up. Start at 10.
gravity = acceleration in units of change per time interval. Gravity is always negative and constant. Start with -2 and try some values.
Unless you want the ball to disappear off the screen as it reaches the top of the bounce, you will need to select a ceiling height. Say 100. (Which is best chosen to match your graphics area's height, though.)
So for every time interval/tick/loop you do the following:
Adjust for gravity by subtracting gravity from deltaY. (If the ball is moving down it will move faster. If its moving up, it will move slower.)
Move the ball by adding deltaY to Y.
Then you have to check: Did the ball hit the ground or the ceiling? Is Y greater than the ceiling value or less than the ground one (0).
If so, you have to bounce it by:
Move Y such that if it was X past the boundary (ground/ceiling) it becomes X within the boundary. (If Y = 110 and ceiling = 100, set Y to 90. If Y = -5, set it to +5.)
Negate deltaY. In a bounce the direction reverses. (deltaY = -deltaY)
Reduce deltaY by a percentage. Some energy is lost in the bounce so speed is slower after a bounce. (deltaY = deltaY * 0.90 or some other amount) #Bathsheba calls that removing energy from the system.
That's all there is to it. You have to fiddle with the numbers to make it take off at a reasonable speed. You have to adjust the time interval. You don't have to match real life. Just do what looks good.
As time goes by, the speed will reduce to 0.
(And despite what I said before, adding or subtracting a small random amount actually looks kind of cool.)
Your ball is bouncing randomly instead of slowly decreasing in velocity. You need to lower your velocity every bounce until the velocity is under minimumMovement then make the velocity 0 and stop bouncing.

Moving objects getting stuck in a corner

I am working on a program which simulates objects moving in a field. The field has a boundary of 1024x1024. The object cannot go below 0 in terms of x,y coordinate and it cannot go above 1024. I have a method for each object called "move()" which moves the object in its current direction at its current speed. If the object approaches the boundary, it then turns around with a new direction and same speed.
The problem I am having is that when one of my objects gets close to both the x and y bound (corner of the field), it gets stuck in the corner. It is almost as if it is trying to move away from the corner, but then it turns back. It must love that corner. I looked over my code and to me, my logic seems correct. I check to make sure the new direction is not negative or over 359. I check to make sure the new x,y coordinate with the new direction is within the bounds too. I even have a method to set a new direction.
I have tried re-implementing this method with different logic, but no luck. If anyone could possibly find a flaw in my programming or point out what may be causing it, then that would be much appreciated.
I have tried to debug and step through my program and I see that when it gets to the corner, it changes direction to turn around, moves about 3 spaces, then goes back to the corner. Must be a wonderful corner.
Code for move method is below:
public void move(){
localX = super.getX();
localY = super.getY();
float newX=0, newY=0;
float testX, testY;
boolean acceptX = false, acceptY = false;
testX = (float) (Math.cos(direction)*10) + localX;
testY = (float) (Math.sin(direction)*10) + localY;
int testDirection;
while(!acceptX){
if(testX >= 0 && testX <= bound){
newX = testX;
acceptX = true;
}//end if statement
else{
if(direction+180 > 359){
setDirection(direction-180);
testX = (float) (Math.cos(Math.toRadians(direction))*speed) + localX;
}
else{
setDirection(direction+180);
testX = (float) (Math.cos(Math.toRadians(direction))*speed) + localX;
}
}//end else
}//end while that checks for X value
while(!acceptY){
if(testY >= 0 && testY <= bound){
newY = testY;
acceptY = true;
}//end if statement
else{
if(direction+180 > 359){
setDirection(direction-180);
testY = (float) (Math.sin(Math.toRadians(direction))*speed) + localY;
}
else{
setDirection(direction+180);
testY = (float) (Math.sin(Math.toRadians(direction))*speed) + localY;
}
}//end else
}//end while that checks for Y value
super.setX(newX);
super.setY(newY);
}
and here is the code for setDirection
public void setDirection(int d) {
direction = d;
}
Say you have an object in the upper left corner, going up. Your first test turns it around so it goes down. Then comes your second check, which turns it around again to go up... again.
Your code could also use some more readability. The very first thing I noticed is that you're using the >359 checks to normalize the new direction to go in. Yet all cases include the movement code as well. I would do something like:
setDirection(direction + 180); //turn around
if (direction >= 360) direction -= 360; //normalize
testY = ...; //move
to move the movement code out of the direction checking if/else blocks. 360 is also a better magic number to use; 359 degrees means nothing. As has been suggested, you should ultimately use a vector library and thus throw away most of the math.
I'd really recommend storing your direction as a vector (x, y) instead of calculating that vector from a scalar; I think that would help you immensely with your code.
Issue: When your object hits an edge, you turn it 180 degrees. If it hits both edges, it'll spin in place, and the test coordinates will always be in the wrong spot.
When one of your objects hits an edge, it needs to bounce, not About Face! Angle of incidence == angle of refraction, or some such. In other words, if you're checking the x coordinate and it bounces, negate the x velocity, not both x & y.

Categories