I am writing a basic demo (Java applet) that has bouncing balls. Currently I only have collision detection against the edges. My game loop is time based which updates the position of the balls and calls repaint(). My problem is say I have a ball that is 3 pixels from the right edge and the ball is moving at 10 pixels per frame to the right. Now on the next loop, the ball will end up 7 pixels from the right edge and moving to the left. So in other words you never see the ball hit the edge. Is this how it should be?
Also for ball collision I found this thread http://www.gamedev.net/community/forums/topic.asp?topic_id=176238 that said you handle them as follows:
1. For each ball, you calculate a vector representing a distance travelled in time t.
2. You check each of these for collisions, and determine which collision is earliest.
3. You move everything up to that point, recalculate the vectors, and go back to step 1.
How do I integrate this algorithm into the time based game loop?
By the way, I''m using a time based game loop so I can create realistic speeds for the balls. That is if 100 pixels represents a meter and the ball moves 100 pixels in a second, then the ball is travelling at 1 meter per second. Is there other approaches to achieve this?
P.S. I am working towards writing a simple pool game (no spin or jump shots).
import java.awt.event.*;
import javax.swing.*;
public class Main extends JApplet implements ActionListener {
Timer gameTimer;
Table table; // The applet''s content pane
int loopSpeed = 10; // Loop every 10ms
private void createGUI() {
// Custom component to draw the current image
// at a particular offset.
table = new Table(getWidth(), getHeight());
setContentPane(table);
}
public void init() {
// Execute a job on the event-dispatching thread:
// creating this applet''s GUI.
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn''t successfully complete");
}
// Set up the timer that will perform the animation.
gameTimer = new javax.swing.Timer(loopSpeed, this);
//timer.setInitialDelay(pause);
//timer.setCoalesce(false);
gameTimer.start(); //Start the animation.
}
public void start() {
gameTimer.restart();
}
public void stop() {
gameTimer.stop();
}
public void actionPerformed(ActionEvent evt) {
table.nextFrame();
table.repaint();
}
}
import java.awt.*;
import javax.swing.*;
public class Table extends JComponent {
private Ball ballA = new Ball(10, 10, 5, 2, Color.BLUE);
private Ball ballB = new Ball(50, 50, -2, -3, Color.RED);
private Ball ballC = new Ball(30, 30, 3, 1, Color.GREEN);
private int width;
private int height;
public Table(int tableWidth, int tableHeight) {
setOpaque(true);
setBackground(Color.WHITE);
width = tableWidth;
height = tableHeight;
}
public void nextFrame() {
ballA.hitTableEdge(width, height);
ballB.hitTableEdge(width, height);
ballC.hitTableEdge(width, height);
ballA.nextFrame();
ballB.nextFrame();
ballC.nextFrame();
}
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
// clear screen in background
g2d.setColor(getBackground());
g2d.fillRect(0, 0, this.getSize().width, this.getSize().height);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ballA.paint(g2d);
ballB.paint(g2d);
ballC.paint(g2d);
}
}
import java.awt.*;
public class Ball {
private Color c;
private int radius;
private int x_pos;
private int y_pos;
private int x_speed;
private int y_speed;
private int dx;
private int dy;
public Ball(int x, int y, int xSpeed, int ySpeed, Color ballColor) {
radius = 10;
c = ballColor;
x_pos = x;
y_pos = y;
x_speed = xSpeed;
y_speed = ySpeed;
}
public void hitTableEdge(int tableWidth, int tableHeight) {
// Clip left edge
if (x_pos - radius + x_speed < 0) {
dx = -(x_pos - radius);
x_speed = -x_speed;
}
// Clip right edge
else if (x_pos + radius + x_speed > tableWidth) {
dx = tableWidth - (x_pos + radius);
x_speed = -x_speed;
}
// Clip top edge
else if (y_pos - radius + y_speed < 0) {
dy = -(y_pos - radius);
y_speed = -y_speed;
}
// Clip bottom edge
else if (y_pos + radius + y_speed > tableHeight) {
dy = tableHeight - (y_pos + radius);
y_speed = -y_speed;
}
}
public void nextFrame() {
x_pos += x_speed + dx;
y_pos += y_speed + dy;
dx = 0;
dy = 0;
}
public void paint(Graphics2D g) {
g.setColor(c);
// paint ball
g.fillOval(x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
}
}