I'm working on a small FPS (personal project), written in java and using JBullet (port of bullet). I got a basic rendering engine with OpenGL and bullet works well. I've implemented a character using a RigidBody, but my character keeps going through every object, except the ground. here is a demo of what happens
This is my first project involving bullet, but I didn't find anyone having this strange behavior on google (nor StackExchange).
Here is a summary of my code.
Main class:
public class Fps {
public static void main(String[] args) {
//Initialization stuff
// Loading level
// Creating DiscreteDynamiWorld
player = new Player(0, -50, 0);
//Mainloop:
while(!Display.isCloseRequested()) {
//GL stuff
//InputHandleR.poll(player);
update();
render();
//GL and timing stuff
}
}
public static void update() {
world.stepSimulation((float) delta / 1000f, 10);
for(int i = 0; i < objects.size(); i++)
objects.get(i).update();
}
public static void render() {
// stuff
}
}
Player:
public class Player implements tk.azertyfun.fps.objects.Object {
// Attributes...
public Player(float x, float y, float z) {
c = new Camera(x, y, z); // Objects that has pos, yaw, pitch, and calls glRotate and glTranslate each frame
//Creating RigidBody with a CapsuleShape (using BoxShape doesn't change anything)
shape = new CapsuleShape(1.75f * CHAR_SCALE, 1.75f * CHAR_SCALE);
Transform trans = new Transform(new Matrix4f(new Quat4f(1, 0, 0, 0), new javax.vecmath.Vector3f(x, y, z), 1f));
motionState = new DefaultMotionState(trans);
javax.vecmath.Vector3f inertia = new javax.vecmath.Vector3f(0, 0, 0);
shape.calculateLocalInertia(1, inertia);
RigidBodyConstructionInfo bodyRbCi = new RigidBodyConstructionInfo(1, motionState, shape, inertia);
bodyRb = new RigidBody(bodyRbCi);
//We wan't our body to stay up
bodyRb.setSleepingThresholds(0.0f, 0.0f);
bodyRb.setAngularFactor(0.0f);
Fps.btWorld.addRigidBody(bodyRb); //Adding body to the world (already trying adding it in the main class, doesn't change anything).
bodyRb.setGravity(new javax.vecmath.Vector3f(0, 50, 0)); //Strange behavior that seems linked to my bug ; this body doesn't act like others, and has reversed gravity.
}
// This function is called by InputHandler and just uses body.setLinearVelocity(vel);. X and Z velocity is reset each frame (i want my player reactive, not walking with soap instead of foots). Anyway, it doesn't change our bug if not reset.
public void move(boolean left, boolean right, boolean forward, boolean backwards, boolean up, boolean down) {
float velX = 0;
float velY = 0;
float velZ = 0;
javax.vecmath.Vector3f vel = new javax.vecmath.Vector3f();
bodyRb.getLinearVelocity(vel);
velY = vel.y;
double delta = Util.getDelta();
if(forward) {
velX -= SPEED * (float) (Math.sin(Math.toRadians(c.yaw))) * delta;
velZ += SPEED * (float) (Math.cos(Math.toRadians(c.yaw))) * delta;
}
if(backwards) {
velX += SPEED * (float) (Math.sin(Math.toRadians(c.yaw))) * delta;
velZ -= SPEED * (float) (Math.cos(Math.toRadians(c.yaw))) * delta;
}
if(left) {
velX -= SPEED * (float) (Math.sin(Math.toRadians(c.yaw - 90))) * delta;
velZ += SPEED * (float) (Math.cos(Math.toRadians(c.yaw - 90))) * delta;
}
if(right) {
velX += SPEED * (float) (Math.sin(Math.toRadians(c.yaw - 90))) * delta;
velZ -= SPEED * (float) (Math.cos(Math.toRadians(c.yaw - 90))) * delta;
}
if(up)
velY += SPEED * (float) delta / 7f;
if(down)
velY -= SPEED * (float) delta / 7f;
javax.vecmath.Vector3f velocity = new javax.vecmath.Vector3f(velX, velY, velZ);
bodyRb.setLinearVelocity(velocity);
}
//Called each frame, sets the camera pos to the body pos.
#Override
public void update() {
Transform trans = new Transform();
bodyRb.getMotionState().getWorldTransform(trans);
c.pos.set(trans.origin.x, trans.origin.y, trans.origin.z);
}
}
Why isn't my body concerned by physics like the other ones? I have to revert the gravity for it and the only colliding object is the ground (which may be as buggy as the player). It looks like I didn't understand something.
Related
I am trying to make a game where enemies spawn from the top (like a vertical scrolling game) and one kind of enemy will basically follow the player's X coordinate while going down. The enemy class is called Follower and right now it does points to the player (see update function on Follower) but it's not as accurate as I need it to be. For example, if the player accelerates, the follower won't be able to see him all the time.
One way to look at it is that I want the position of the player to be a coordinate in a radiant system and make the vertices of my Follower accurately just rotate and create a straight line looking at it every frame
here is the Follower Class:
public class Follower {
Player target; //follow this
//position
private Vector2 position;
private float x;
private float y;
//speed
private Vector2 velocity;
private float speed;
private float radians;
private float faceTarget;
//dimensions
private float[] shapeX;
private float[] shapeY;
private int numPoints; //vertices for the shape
private boolean remove; //to remove from the game
public Follower(float x,float y, Player target){
this.target = target;
this.x = x;
this.y = y;
velocity = new Vector2(0, 0);
numPoints = 4;
speed = 200;
shapeX = new float[numPoints];
shapeY = new float[numPoints];
radians = 3.1415f / 2;
setShape();
}
public void setShape(){
//top vertice
shapeX[0] = x + MathUtils.cos(radians) * 30;
shapeY[0] = y + MathUtils.sin(radians) * 30;
//left vertice
shapeX[1] = x + MathUtils.cos(radians - 4 * 3.1415f / 10) * 30;
shapeY[1] = y + MathUtils.sin(radians - 4 * 3.1415f / 10) * 30;
//bottom vertice
shapeX[2] = x + MathUtils.cos(radians + 3.1415f) * 60;
shapeY[2] = y + MathUtils.sin(radians + 3.1415f) * 60;
//left vertice
shapeX[3] = x + MathUtils.cos(radians + 4 * 3.1415f / 10) * 30;
shapeY[3] = y + MathUtils.sin(radians + 4 * 3.1415f / 10) * 30;
}
public boolean shouldRemove() {
return remove;
}
public void update(float dt) {
float angle = (float) Math.atan2(target.getPosition().y - y, target.getPosition().x - x); //angle between the follower and target
velocity.set((float) Math.cos(angle) * speed , -speed); //setting direction to follow the target
radians += Math.cos(angle) * dt; //THIS HERE IS MAKING IT ROTATE
x += velocity.x * dt;
y += velocity.y * dt;
setShape();
if(y <= 0 - 60)
remove = true;
else
remove = false;
}
public void draw(ShapeRenderer sp){
sp.setColor(1, 1, 1 ,1);
sp.begin(ShapeRenderer.ShapeType.Line);
for(int i = 0, j = shapeX.length - 1;
i < shapeX.length;
j = i++) {
sp.line(shapeX[i], shapeY[i], shapeX[j], shapeY[j]);
}
sp.end();
}
}
I am not adding the GameScreen because I do not see the need of showing how they are rendered, either way, it'll stay the same.
Also, with the line of code, I am using the Follower points to the player with the bottom vertice as the "eyes"
Thanks for the answers!
I'm trying to learn how to make a 2D Game without Game Engines, anyways I already created a background scrolling right now my goal is to make my character jump. But the thing is whenever I start my app the character is spinning up and down and it will just go away to the background.
Here's my character code
public class Deer extends GameCharacter {
private Bitmap spritesheet;
private double dya;
private boolean playing;
private long startTime;
private boolean Jump;
private Animate Animation = new Animate();
public Deer(Bitmap res, int w, int h, int numFrames) {
x = 20;
y = 400;
dy = 0;
height = h;
width = w;
Bitmap[] image = new Bitmap[numFrames];
spritesheet = res;
for (int i = 0; i < image.length; i++)
{
image[i] = Bitmap.createBitmap(spritesheet, i*width, 0, width, height);
}
Animation.setFrames(image);
Animation.setDelay(10);
startTime = System.nanoTime();
}
public void setJump(boolean b){
Jump = b;
}
public void update()
{
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100)
{
}
Animation.update();
if(Jump){
dy = (int)(dya+=5.5);
}
else{
dy = (int)(dya+=5.5);
}
if(dy>14)dy = 14;
if(dy>14)dy = -14;
y += dy*2;
dy = 0;
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(Animation.getImage(),x,y,null);
}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
public void resetDYA(){dya = 0;}
}
x - character's horizontal position
y - character's vertical position
dx - character's horizontal acceleration
dy - character's vertical acceleration
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
if(!deer.getPlaying()) {
deer.setPlaying(true);
}
deer.setJump(true);
return true;
}
return super.onTouchEvent(event);
}
I can't say for sure if this is the only problem because you have other suspicious code but it looks like you jump no matter what.
if(Jump){
dy = (int)(dya+=5.5);
} else {
dy = (int)(dya+=5.5);
}
If Jump is true you set the vertical acceleration. But you also set the vertical acceleration to the same value if Jump is false. You also don't show in your code where Jump is ever set to false.
Another odd bit of code is:
if(dy>14)dy = 14;
if(dy>14)dy = -14;
Here, if dy>14 you set it to 14. Then you check dy>14 immediately after. Of course, this time it's false. But because those two conditions are the same the second one will never pass since the one before it ensures it won't. The only other option is they both fail. IOW, you'll never be able to enter the second if.
All that aside, I'm not sure why you're taking this approach. You can simply rely on physics equations with constant acceleration, give an initial velocity, check for a collision with the ground (or at least the original height), and just let it run. For example:
// These are the variables you need.
int x = 200, y0 = 0, y = 0, velocity = 15;
double t = 0.0, gravity = -9.8;
// This is the statement that should run when you update the GUI.
// It is the fundamental equation for motion with constant acceleration.
// The acceleration is the gravitational constant.
y = (int) (y0 + velocity * t + .5 * gravity * t * t);
if (y < 0) {
y = y0 = 0;
//Stop jumping!
Jump = false;
} else {
// Swap the y values.
y0 = y;
// Increase the time with the frame rate.
t += frameRate;
}
// Draw the character using the y value
The best part about this is you don't need to worry about when you get to the maximum height because the equation will automatically bring you down. It also looks more natural as if the mechanics are real. Try it out.
A simple Swing example that you can play around with. Note that the values are different to deal with the way the components are drawn to the screen. Normally, you would deal with that with transformations but this will do for the task.
public class Main {
static Timer timer;
Main() {
JFrame frame = new JFrame("Hello sample");
frame.setSize(new Dimension(550, 550));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
timer = new Timer(5, (e) -> panel.repaint());
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::new);
}
class MyPanel extends JPanel {
int x = 200, y0 = 300, y = 0, w = 200, h = 200, v = -8;
double t = 0.0, gravity = 9.8;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
y = (int) (y0 + v * t + .5 * gravity * t * t);
if (y > 300) {
y = y0 = 300;
// To prevent it from stopping comment the timer.stop() and
// uncomment the t = 0.0 statements.
//t = 0.0;
timer.stop();
} else {
y0 = y;
t += .025;
}
g.drawOval(x, y, w, h);
}
}
}
I am using Slick and Tiled2D to make a top-down RPG style game. I am trying to do collision, but the player seems to be able to go through blocks that are on the left side of a building, or the left half of a block. The full project is here: http://github.com/Cj1m/RPG
Here is my code for the player movement and collision detection:
#Override
public void update(GameContainer gc, int delta) throws SlickException {
input = gc.getInput();
if(input.isKeyDown(Input.KEY_W)){
if(!isBlocked(x, y - delta * 0.1f)){
y-=0.1 * delta;
timer(0,1,delta);
}
}else if(input.isKeyDown(Input.KEY_S) && y < screenBottomEdge){
if (!isBlocked(x, y + playerHeight + delta * 0.1f)){
y+=0.1 * delta;
timer(0,0,delta);
}
}else if(input.isKeyDown(Input.KEY_A) && x > screenLeftEdge){
if (!isBlocked(x - delta * 0.1f, y)){
x-=0.1 * delta;
timer(0,2,delta);
}
}else if(input.isKeyDown(Input.KEY_D) && x < screenRightEdge){
if (!isBlocked(x + playerWidth + delta * 0.1f, y)){
x+=0.1 * delta;
timer(0,3,delta);
}
}
}
and
private boolean isBlocked(float x, float y) {
int xBlock = (int)x / 30;
int yBlock = (int)y / 30;
return blocked[xBlock][yBlock];
}
I guess the x and y in isBlocked are the player's pixel-accurate x and y-positions, while xBlock and yBlock are the tile-accurate positions.
When you say they go through half of the block this seems to me like a rounding-problem at
int xBlock = (int)x / 30;
int yBlock = (int)y / 30;
Try something along the lines of
(int) Math.round(x/30.0);
I'm working with tutorial from this site - "Fixed timestep" section.
Here's the code - http://pastebin.com/QaHgcLaR
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GameLoopTest extends JFrame implements ActionListener
{
private GamePanel gamePanel = new GamePanel();
private JButton startButton = new JButton("Start");
private JButton quitButton = new JButton("Quit");
private JButton pauseButton = new JButton("Pause");
private boolean running = false;
private boolean paused = false;
private int fps = 60;
private int frameCount = 0;
public GameLoopTest()
{
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
p.add(startButton);
p.add(pauseButton);
p.add(quitButton);
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
startButton.addActionListener(this);
quitButton.addActionListener(this);
pauseButton.addActionListener(this);
}
public static void main(String[] args)
{
GameLoopTest glt = new GameLoopTest();
glt.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
Object s = e.getSource();
if (s == startButton)
{
running = !running;
if (running)
{
startButton.setText("Stop");
runGameLoop();
}
else
{
startButton.setText("Start");
}
}
else if (s == pauseButton)
{
paused = !paused;
if (paused)
{
pauseButton.setText("Unpause");
}
else
{
pauseButton.setText("Pause");
}
}
else if (s == quitButton)
{
System.exit(0);
}
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop()
{
Thread loop = new Thread()
{
public void run()
{
gameLoop();
}
};
loop.start();
}
//Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running)
{
double now = System.nanoTime();
int updateCount = 0;
if (!paused)
{
//Do as many game updates as we need to, potentially playing catchup.
while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER )
{
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if ( now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
drawGame(interpolation);
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime)
{
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while ( now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
}
}
private void updateGame()
{
gamePanel.update();
}
private void drawGame(float interpolation)
{
gamePanel.setInterpolation(interpolation);
gamePanel.repaint();
}
private class GamePanel extends JPanel
{
float interpolation;
float ballX, ballY, lastBallX, lastBallY;
int ballWidth, ballHeight;
float ballXVel, ballYVel;
float ballSpeed;
int lastDrawX, lastDrawY;
public GamePanel()
{
ballX = lastBallX = 100;
ballY = lastBallY = 100;
ballWidth = 25;
ballHeight = 25;
ballSpeed = 25;
ballXVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
ballYVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
public void setInterpolation(float interp)
{
interpolation = interp;
}
public void update()
{
lastBallX = ballX;
lastBallY = ballY;
ballX += ballXVel;
ballY += ballYVel;
if (ballX + ballWidth/2 >= getWidth())
{
ballXVel *= -1;
ballX = getWidth() - ballWidth/2;
ballYVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
else if (ballX - ballWidth/2 <= 0)
{
ballXVel *= -1;
ballX = ballWidth/2;
}
if (ballY + ballHeight/2 >= getHeight())
{
ballYVel *= -1;
ballY = getHeight() - ballHeight/2;
ballXVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
else if (ballY - ballHeight/2 <= 0)
{
ballYVel *= -1;
ballY = ballHeight/2;
}
}
public void paintComponent(Graphics g)
{
//BS way of clearing out the old rectangle to save CPU.
g.setColor(getBackground());
g.fillRect(lastDrawX-1, lastDrawY-1, ballWidth+2, ballHeight+2);
g.fillRect(5, 0, 75, 30);
g.setColor(Color.RED);
int drawX = (int) ((ballX - lastBallX) * interpolation + lastBallX - ballWidth/2);
int drawY = (int) ((ballY - lastBallY) * interpolation + lastBallY - ballHeight/2);
g.fillOval(drawX, drawY, ballWidth, ballHeight);
lastDrawX = drawX;
lastDrawY = drawY;
g.setColor(Color.BLACK);
g.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
}
private class Ball
{
float x, y, lastX, lastY;
int width, height;
float xVelocity, yVelocity;
float speed;
public Ball()
{
width = (int) (Math.random() * 50 + 10);
height = (int) (Math.random() * 50 + 10);
x = (float) (Math.random() * (gamePanel.getWidth() - width) + width/2);
y = (float) (Math.random() * (gamePanel.getHeight() - height) + height/2);
lastX = x;
lastY = y;
xVelocity = (float) Math.random() * speed*2 - speed;
yVelocity = (float) Math.random() * speed*2 - speed;
}
public void update()
{
lastX = x;
lastY = y;
x += xVelocity;
y += yVelocity;
if (x + width/2 >= gamePanel.getWidth())
{
xVelocity *= -1;
x = gamePanel.getWidth() - width/2;
yVelocity = (float) Math.random() * speed*2 - speed;
}
else if (x - width/2 <= 0)
{
xVelocity *= -1;
x = width/2;
}
if (y + height/2 >= gamePanel.getHeight())
{
yVelocity *= -1;
y = gamePanel.getHeight() - height/2;
xVelocity = (float) Math.random() * speed*2 - speed;
}
else if (y - height/2 <= 0)
{
yVelocity *= -1;
y = height/2;
}
}
public void draw(Graphics g)
{
}
}
}
After run this code, the ball has kind of lag, but there is still 60 FPS. After I move mouse over application's window and move it in random directions, the ball is moving smoothly. It happens even if window application isn't focused! What's wrong? Can it be fixed?
I'm using Ubuntu 13.04 with Oracle JDK7.
I've found that it happens with every application. Similar things happens even in LWJGL application, but effect of the "lag" is much less than in swing application.
17 sec video showing my problem
http://www.youtube.com/watch?v=J8SBjKncgRw
I had same problem under Kubuntu 13.04
I googled something which works for me: http://www.java-gaming.org/index.php?topic=19224.0
The basic idea is to put Toolkit.getDefaultToolkit().sync(); after drawing something. In your code it should be after drawGame(interpolation);.
The explanation seems to be that the window system manages the update intervals, so it is not Java's fault and only occures with some window mangers.
The repaints should be triggered from a Swing based Timer, which ensures that GUI updates are called on the EDT. See Concurrency in Swing for more details.
This appears to be a bug in the VM since Java 6. I had the same problem and found an ugly, but simple workaround: Create a Robot object and let it press a key or position the mouse in each cycle. The animation will then run smoothly. Example:
final Robot robot = new Robot();
javax.swing.Timer timer = new javax.swing.Timer(initialDelay, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// update your image...
robot.keyPress(62);
}
});
See also: Java animation stutters when not moving mouse cursor
You could invoke setIgnoreRepaint(true) and use a BufferStrategy for drawing that particular component instead. A BufferStrategy allows you to perform the drawing whenever you want. You can also invoke paintComponent methods inside your drawing method.
I have an object(which is a ball) having its position at the top of the screen that fall directly whenever I start running the program. The problem is that the ball fall to its constant speed, I want it to fall accelerating with gravity effects and when it reach the ground, I want it to bounce a few more times before it stop moving. Could someone help me about this?
Here's what I've tried:
public class Balls
{
private double x;
private double y;
private double speed;
private double mass;
private final double gravity = -9.8;
private final double width = 100;
private double height = 100;
private final Board board;
private boolean isFalling = false;
private double distance_y;
private double distance_x = 0;
public Balls(double x, double y, double speed, double mass, Board board)
{
this.x = x;
this.y = y;
this.board = board;
this.speed = convertToMeterSpeed(speed);
this.mass = mass;
}
private double convertToMeterSpeed(double speed)
{
return speed / 3.6;
}
public void moveBall(long dt)
{
double time = dt / 1e9; // seconds
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (distance_y >= height)
{
distance_y = distance_y + (0.5 * gravity * (time * time)); // represents the 1/2,
distance_y = board.getHeight() - height;
y += velocity_y;
}
else
{
isFalling = false;
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void render(Graphics2D g2d)
{
g2d.fillOval((int) x, (int) y, (int) width, (int) height);
}
}
speed = v0 + gt^2/2,
where
v0 - initial speed
g = 9.81 on Earth.
t - time
Now you can calculate the speed at any time.
You probably want to define a maximum speed (terminal velocity) so your ball doesn't accelerate to an enormous speed. Gravity accelerates at 9.8m/s/s. Once the ball hits the "ground" you just reverse the speed and update the current position to make it bounce, then on your next iteration gravity will be applied again so it will go back down. Eventually, the speed will get to 0 as the ball doesnt bounce so much, and will stop.
Here's an (untested) example:
private static final double GRAVITY = 9.8;
private static final double TERMINAL_VELOCITY = 100;
private double speed;
private int current_y;
public void fallAndBounce() {
speed = speed + GRAVITY;
if (speed > TERMINAL_VELOCITY) { speed = TERMINAL_VELOCITY; }
if (current_y >= bottomOfScreen)
{
//We have hit the "ground", so bounce back up. Reverse
//the speed and divide by 4 to make it slower on bouncing.
//Just change 4 to 2 or something to make it faster.
speed = -speed/4;
}
current_y += speed;
}
Your problem is that you are trying to animate a ball falling, but you are instead writing an algorithm for solving its position given a certain time.
This means you should take your time variable dt completely out of the equation, and just move your ball with each iteration of a loop like this:
while (true)
{
moveBall();
render();
try {
Thread.sleep(10)
} catch(InterruptedException e) {
e.printStackTrace();
}
}
Also, change your variables slightly:
// Add this to your variables
private final double GRAVITY = -9.8; // Final variables should be capitalized
private final double TERMINAL_VELOCITY = -30; // Whatever you want it to be
Here is the main change:
public void moveBall()
{
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (height < distance_y)
{
if (velocity_y <= TERMINAL_VELOCITY)
velocity_y += GRAVITY; // implementing acceleration (gravity)
// just means adding it to velocity.
y += velocity_y;
}
Really, I don't know how this was possibly working before.