Reputation:
Any ideas why my oval is not moving to the right? I have a game loop but somehow the circle stays where it appears, instead of moving by 2pixels to the right every cycle. The strange thing is that it enters the loop before actually painting. But then the graphics object show up(at a fixed position).
public class GamePanel extends JPanel implements Runnable {
public static int WIDTH = 1024;
public static int HEIGHT = WIDTH / 16 * 9;
private Thread t1;
boolean running;
private int FPS = 60;
private long optimalTime = 1000 / FPS;
private int heroX = 200;
private int heroY = 200;
public void addNotify(){
Dimension size = new Dimension(WIDTH,HEIGHT);
setPreferredSize(size);
setFocusable(true);
requestFocus();
running = true;
t1 = new Thread(this);
t1.start();
}
public void paintComponent (Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, WIDTH, HEIGHT);
g2.setColor(Color.BLACK);
g2.fillOval(heroX, heroY, 50, 50);
g2.dispose();
}
public void run() {
long startTime;
long passedTime;
long waitTime;
while (running){
startTime = System.nanoTime();
System.out.println("Runs");
update();
draw();
repaint();
passedTime = System.nanoTime() - startTime;
waitTime = optimalTime - passedTime / 1000000;
try {
if (waitTime <= 0){
waitTime = 2;
}
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void draw() {
}
private void update() {
heroX += 2;
}
}
Upvotes: 0
Views: 160
Reputation:
After reading and testing, I just wanted to do this. It works as intended, even if paintComponent is outside the EDT.
public class GamePanel extends JPanel implements Runnable {
public static int WIDTH = 1024;
public static int HEIGHT = WIDTH / 16 * 9;
private int cordX = WIDTH / 2;
private Thread t1;
private boolean running = true;
public void addNotify() {
super.addNotify();
Dimension size = new Dimension (WIDTH, HEIGHT);
setPreferredSize(size);
t1 = new Thread(this);
t1.start();
}
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillOval(cordX, HEIGHT /2 , 20, 20);
}
public void run() {
while(running) {
cordX += 2;
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Upvotes: 0
Reputation: 6618
You should use a swing Timer instead of trying to use threads. If you need to do something time consuming in the background, use SwingWorkers. It is possible to use your own threading with swing should you really need to (you need a twisted user case to need to do that), but do not try to do that until you have a good grasp of threads and the way to use them with swing.
public class GamePanel extends JPanel {
private static final int DELAY = 1000 / 60;
private final Timer timer;
// ...
private int heroX = 200;
private int heroY = 200;
public GamePanel() {
timer = new Timer(DELAY, new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
update();
repaint();
}
});
// ...
}
// No need to make this public
@Override
protected void paintComponent (Graphics g) {
// ...
}
@Override
public Dimension getPreferredSize() {
// Overriding is cleaner than using set*Size(). Search old questions to see why
}
public void startAnimation() {
timer.start();
}
public void stopAnimation() {
timer.stop();
}
// Remove addNotify() and run()
}
Upvotes: 1