Created
December 31, 2013 16:53
-
-
Save akhikhl/8199472 to your computer and use it in GitHub Desktop.
2d graphics simulation of a ball in gravity field. Energy conservation law is respected.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import java.awt.Color; | |
import java.awt.event.*; | |
import java.awt.geom.*; | |
import java.awt.Graphics; | |
import java.awt.Graphics2D; | |
import java.awt.Rectangle; | |
public class Ball extends JComponent { | |
public static final int physicsTimerInterval = 1; // milliseconds, means 1000 computes / second | |
public static final int paintTimerInterval = 20; // milliseconds, means 50 frames / second | |
private double scale = 50; // pixels/meter | |
private double diameter = 1; | |
private double x = diameter; | |
private double y = diameter; | |
private double vx = 3; | |
private double vy = 0; | |
private double g = 9.8; | |
private double dt = physicsTimerInterval / 1000.0; // in seconds | |
private double energy; | |
private long stepsComputed = 0; | |
public Ball() { | |
} | |
void computePhysics() { | |
Rectangle r = getBounds(null); | |
double bx = r.x / scale; | |
double by = r.y / scale; | |
double bwidth = r.width / scale; | |
double bheight = r.height / scale; | |
if(stepsComputed == 0) | |
energy = (vx*vx + vy*vy) / 2 + g * (bheight - y) | |
if(x < bx + diameter / 2) { | |
x = Math.max(x, bx + diameter / 2); | |
vx = -vx; | |
} else if (x > bx + bwidth - diameter / 2) { | |
x = Math.min(x, bx + bwidth - diameter / 2); | |
vx = -vx; | |
} | |
if(y < by + diameter / 2) { | |
y = Math.max(y, by + diameter / 2); | |
vy = -vy; | |
} else if (y > by + bheight - diameter / 2) { | |
y = Math.min(y, by + bheight - diameter / 2); | |
vy = -vy; | |
} | |
vy += g * dt; | |
x += vx * dt; | |
// y += vy * dt; | |
// respect energy conservation law | |
y = bheight - (energy - (vx*vx + vy*vy) / 2) / g; | |
++stepsComputed; | |
} | |
public void paintComponent(Graphics g) { | |
Graphics2D g2d = (Graphics2D)g; | |
double screenX = x * scale; | |
double screenY = y * scale; | |
double screenDiameter = diameter * scale; | |
Ellipse2D.Double circle = new Ellipse2D.Double(screenX - screenDiameter / 2, screenY - screenDiameter / 2, screenDiameter, screenDiameter); | |
g2d.setPaint(new Color(0, 128, 128)); | |
g2d.fill(circle); | |
} | |
} | |
public class Main { | |
private static void createAndShowGUI() { | |
JFrame frame = new JFrame("Java 2d graphics test"); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setSize(800, 600); | |
final Ball component = new Ball(); | |
frame.add(component); | |
final Timer physicsTimer = new Timer(Ball.physicsTimerInterval, new ActionListener() { | |
public void actionPerformed(ActionEvent evt) { | |
component.computePhysics(); | |
} | |
}); | |
final Timer repaintTimer = new Timer(Ball.paintTimerInterval, new ActionListener() { | |
public void actionPerformed(ActionEvent evt) { | |
component.repaint(); | |
} | |
}); | |
physicsTimer.start(); | |
repaintTimer.start(); | |
frame.addWindowListener(new WindowAdapter() { | |
public void windowClosing(WindowEvent e) { | |
physicsTimer.stop(); | |
} | |
}); | |
frame.setVisible(true); | |
} | |
public static void main(String[] args) { | |
javax.swing.SwingUtilities.invokeLater(new Runnable() { | |
public void run() { | |
createAndShowGUI(); | |
} | |
}); | |
} | |
} | |
new Main().main([] as String[]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment