The Coding Wombat The Coding Wombat - 5 months ago 10
Java Question

Painted shape keeps vibrating after stopping

I tried to recreate some physics by creating a ball that bounces from the sides and that slows down. The ball stops moving in the x direction, but it keeps vibrating like only 1 pixel up and down in the y direction. Also it does this a little bit above the bottom border.

Also, is my code readable/good practise?

Bouncy.java

package Bouncy;

import javax.swing.*;

public class Bouncy {

private static void createAndShowGui() {
JFrame frame = new JFrame("Bouncy Balls");
Board board = new Board();
frame.getContentPane().add(board);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocation(2000, 50);
board.requestFocusInWindow();
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}

}


Board.java

package Bouncy;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Board extends JPanel implements ActionListener {

public static final int BOARDWIDTH = 800;
public static final int BOARDHEIGHT = 800;

private Ball ball;

public Board() {

Dimension preferedDimension = new Dimension(BOARDWIDTH, BOARDHEIGHT);
setPreferredSize(preferedDimension);
ball = new Ball(15, 0);
Timer animationTimer = new Timer(17, this);
animationTimer.start();
}

public void actionPerformed(ActionEvent e) {
ball.applyPhysics();
repaint();
}

public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(rh);

ball.display(g2d);

g2d.dispose();
}
}


Ball.java

package Bouncy;

import java.awt.*;

public class Ball {

private int xPos;
private int yPos;
private double dx;
private double dy;
private int ballWidth;
private int ballHeight;

public Ball() {
this(0, 0);
}

public Ball(int dx, int dy) {
ballWidth = 50;
ballHeight = ballWidth;
xPos = 0;
yPos = 0;
this.dx = dx;
this.dy = dy;
}

public void applyPhysics() {
bounceX();
applyXFriction();
bounceY();
}

public void bounceX() {
if (xPos > Board.BOARDWIDTH - ballWidth) {
xPos = Board.BOARDWIDTH - ballWidth;
dx = -dx;
} else if (xPos < 0) {
xPos = 0;
dx = -dx;
} else {
xPos += dx;
}
}

public void applyXFriction() {
final double xFriction = .95;

if (yPos == Board.BOARDHEIGHT - ballHeight) {
dx *= xFriction;
if (Math.abs(dx) < .5) {
dx = 0;
}
}
}

public void bounceY() {
final int gravity = 12;
final double energyLoss = .75;
final double dt = .2;

if (yPos > Board.BOARDHEIGHT - ballHeight){
yPos = Board.BOARDHEIGHT - ballHeight;
dy = -dy * energyLoss;
} else if (yPos < 0) {
yPos = 0;
dy *= -energyLoss;
} else {
dy += gravity * dt;
yPos += dy * dt + .5 * gravity * dt * dt;
}
}

public void display(Graphics2D g2d) {
g2d.fillOval(xPos, yPos, ballWidth, ballHeight);
}
}

Answer

Inside your apply friction method, where you set dx to 0, also set dy to 0. This will stop the ball moving along both the X and Y axis

if (Math.abs(dx) < .5)
{
       dx = 0;
       dy = 0;
}

This will stop the ball vibrating:

if (Math.abs(dy * dt + .5 * gravity * dt * dt) < 1.5 && yPos == Board.BOARDHEIGHT - ballHeight) 
{
    dy = 0;
    yPos = Board.BOARDHEIGHT - ballHeight;
}
Comments