看起来这个小程序只会在调整窗口大小或最小化时绘制和更新DRAWS。所以applet不会一直重绘,而只是在操作窗口时。
我在这里做错了吗?
我正在关注此处提供的游戏循环:http://www3.ntu.edu.sg/home/ehchua/programming/java/J8d_Game_Framework.html
代码在这里:
package newapplet;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameApplet extends JApplet { // main class for the game as a Swing application
// Define constants for the game
static final int CANVAS_WIDTH = 493; // width and height of the game screen
static final int CANVAS_HEIGHT = 411;
static final int UPDATE_RATE = 4; // number of game update per second
static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE; // nanoseconds
static int DRAWS = 0;
// ......
// Enumeration for the states of the game.
public enum gameState {
INITIALIZED, CONNECTING, PLAYING, DISCONNECTED
}
private gameState state;
// Define instance variables for the game objects
// ......
// ......
// Handle for the custom drawing panel
private GameCanvas canvas;
// Constructor to initialize the UI components and game objects
public GameApplet() {
// Initialize the game objects
gameInit();
// UI components
canvas = new GameCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
this.setContentPane(canvas);
// Other UI components such as button, score board, if any.
// ......
this.setVisible(true);
}
// All the game related codes here
// Initialize all the game objects, run only once in the constructor of the main class.
public void gameInit() {
// ......
state = gameState.INITIALIZED;
}
// Shutdown the game, clean up code that runs only once.
public void gameShutdown() {
// ......
state = gameState.DISCONNECTED;
}
// To start and re-start the game.
public void gameStart() {
// Create a new thread
Thread gameThread = new Thread() {
// Override run() to provide the running behavior of this thread.
@Override
public void run() {
gameLoop();
}
};
// Start the thread. start() calls run(), which in turn calls gameLoop().
gameThread.start();
}
// Run the game loop here.
private void gameLoop() {
// Regenerate the game objects for a new game
// ......
//state = State.PLAYING;
// Game loop
long beginTime, timeTaken, timeLeft;
while (true) {
beginTime = System.nanoTime();
if (state == gameState.DISCONNECTED) break; // break the loop to finish the current play
if (state == gameState.PLAYING) {
// Update the state and position of all the game objects,
// detect collisions and provide responses.
gameUpdate();
}
// Refresh the display
repaint();
// Delay timer to provide the necessary delay to meet the target rate
timeTaken = System.nanoTime() - beginTime;
timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L; // in milliseconds
if (timeLeft < 10) timeLeft = 10; // set a minimum
try {
// Provides the necessary delay and also yields control so that other thread can do work.
Thread.sleep(timeLeft);
} catch (InterruptedException ex) { }
}
}
// Update the state and position of all the game objects,
// detect collisions and provide responses.
public void gameUpdate() {
}
// Refresh the display. Called back via rapaint(), which invoke the paintComponent().
private void gameDraw(Graphics2D g2d) {
switch (state) {
case INITIALIZED:
g2d.setColor (Color.red);
g2d.drawString ("init",20,20);
break;
case PLAYING:
g2d.setColor (Color.red);
g2d.drawString ("play",20,20);
break;
case CONNECTING:
g2d.setColor (Color.red);
g2d.drawString ("connecting",20,20);
break;
case DISCONNECTED:
g2d.setColor (Color.red);
g2d.drawString ("disconnect",20,20);
break;
}
g2d.setColor (Color.GREEN);
g2d.drawString ("Re-paint: " + DRAWS,30,30);
this.DRAWS++;
// ......
}
// Process a key-pressed event. Update the current state.
public void gameKeyPressed(int keyCode) {
switch (keyCode) {
case KeyEvent.VK_UP:
// ......
break;
case KeyEvent.VK_DOWN:
// ......
break;
case KeyEvent.VK_LEFT:
// ......
break;
case KeyEvent.VK_RIGHT:
// ......
break;
}
}
// Process a key-released event.
public void gameKeyReleased(int keyCode) { }
// Process a key-typed event.
public void gameKeyTyped(char keyChar) { }
// Other methods
// ......
// Custom drawing panel, written as an inner class.
class GameCanvas extends JPanel implements KeyListener {
// Constructor
public GameCanvas() {
setFocusable(true); // so that can receive key-events
requestFocus();
addKeyListener(this);
}
// Override paintComponent to do custom drawing.
// Called back by repaint().
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d); // paint background
setBackground(Color.BLACK); // may use an image for background
// Draw the game objects
gameDraw(g2d);
}
// KeyEvent handlers
@Override
public void keyPressed(KeyEvent e) {
gameKeyPressed(e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
gameKeyReleased(e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) {
gameKeyTyped(e.getKeyChar());
}
}
// main
public static void main(String[] args) {
// Use the event dispatch thread to build the UI for thread-safety.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GameApplet();
}
});
}
}
答案 0 :(得分:1)
快速浏览一下代码我可以看到你在Event Dispatch Thread之外调用repaint(),这会导致你看到的问题。 javax.swing.SwingUtilties.invokeAndWait(Runnable r)将允许您将该repaint()调用放在EDT上。
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
答案 1 :(得分:1)
请参阅此代码以进行一些更正。
// <applet code='GameApplet' width=400 height=50></applet>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameApplet extends JApplet { // main class for the game as a Swing application
// Define constants for the game
static final int CANVAS_WIDTH = 493; // width and height of the game screen
static final int CANVAS_HEIGHT = 411;
static final int UPDATE_RATE = 4; // number of game update per second
static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE; // nanoseconds
Timer timer;
static int DRAWS = 0;
// ......
// Enumeration for the states of the game.
public enum gameState {
INITIALIZED, CONNECTING, PLAYING, DISCONNECTED
}
private gameState state;
// Define instance variables for the game objects
// ......
// ......
// Handle for the custom drawing panel
private GameCanvas canvas;
// Constructor to initialize the UI components and game objects
public GameApplet() {
// Initialize the game objects
gameInit();
// UI components
canvas = new GameCanvas();
// set the size of the applet in HTML, not the content pane!
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
this.setContentPane(canvas);
// Other UI components such as button, score board, if any.
// ......
//this.setVisible(true);
}
// All the game related codes here
// Initialize all the game objects, run only once in the constructor of the main class.
public void gameInit() {
// ......
state = gameState.INITIALIZED;
gameStart();
}
// Shutdown the game, clean up code that runs only once.
public void gameShutdown() {
// ......
state = gameState.DISCONNECTED;
}
@Override
public void destroy() {
timer.stop();
}
// To start and re-start the game.
public void gameStart() {
// Create a new thread
//Thread gameThread = new Thread() {
// Override run() to provide the running behavior of this thread.
// @Override
// public void run() {
gameLoop();
// }
//};
// Start the thread. start() calls run(), which in turn calls gameLoop().
//gameThread.start();
}
// Run the game loop here.
private void gameLoop() {
// Regenerate the game objects for a new game
// ......
//state = State.PLAYING;
// Game loop
ActionListener al = new ActionListener() {
long beginTime, timeTaken, timeLeft;
public void actionPerformed(ActionEvent ae) {
beginTime = System.nanoTime();
if (state == gameState.DISCONNECTED) {
//break; // break the loop to finish the current play
System.out.println("do SOMETHING here..");
}
if (state == gameState.PLAYING) {
// Update the state and position of all the game objects,
// detect collisions and provide responses.
gameUpdate();
}
// Refresh the display
repaint();
// Delay timer to provide the necessary delay to meet the target rate
timeTaken = System.nanoTime() - beginTime;
timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L; // in milliseconds
if (timeLeft < 10) timeLeft = 10; // set a minimum
}
};
timer = new Timer(40,al);
timer.start();
}
// Update the state and position of all the game objects,
// detect collisions and provide responses.
public void gameUpdate() {
}
// Refresh the display. Called back via rapaint(), which invoke the paintComponent().
private void gameDraw(Graphics2D g2d) {
switch (state) {
case INITIALIZED:
g2d.setColor (Color.red);
g2d.drawString ("init",20,20);
break;
case PLAYING:
g2d.setColor (Color.red);
g2d.drawString ("play",20,20);
break;
case CONNECTING:
g2d.setColor (Color.red);
g2d.drawString ("connecting",20,20);
break;
case DISCONNECTED:
g2d.setColor (Color.red);
g2d.drawString ("disconnect",20,20);
break;
}
g2d.setColor (Color.GREEN);
g2d.drawString ("Re-paint: " + DRAWS,30,30);
this.DRAWS++;
// ......
}
// Process a key-pressed event. Update the current state.
public void gameKeyPressed(int keyCode) {
switch (keyCode) {
case KeyEvent.VK_UP:
// ......
break;
case KeyEvent.VK_DOWN:
// ......
break;
case KeyEvent.VK_LEFT:
// ......
break;
case KeyEvent.VK_RIGHT:
// ......
break;
}
}
// Process a key-released event.
public void gameKeyReleased(int keyCode) { }
// Process a key-typed event.
public void gameKeyTyped(char keyChar) { }
// Other methods
// ......
// Custom drawing panel, written as an inner class.
class GameCanvas extends JPanel implements KeyListener {
// Constructor
public GameCanvas() {
setFocusable(true); // so that can receive key-events
requestFocus();
addKeyListener(this);
}
// Override paintComponent to do custom drawing.
// Called back by repaint().
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d); // paint background
setBackground(Color.BLACK); // may use an image for background
// Draw the game objects
gameDraw(g2d);
}
// KeyEvent handlers
@Override
public void keyPressed(KeyEvent e) {
gameKeyPressed(e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
gameKeyReleased(e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) {
gameKeyTyped(e.getKeyChar());
}
}
}
请注意,在源代码顶部添加单行注释意味着(一旦编译)它可以使用..从命令行启动..
> appletviewer GameApplet.java