2011-12-29 84 views
0

看起來這個applet只會在窗口被調整大小或最小化時繪製並更新DRAWS。所以這個小程序不會一直重畫,只有在操作窗口時纔會重畫。這個applet gameloop有什麼問題?

我在這裏做錯了什麼?

我下面的gameloop這裏介紹: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(); 
    } 
    }); 
} 
} 
+2

即200+線代碼在編譯時有10個錯誤。爲了更快地獲得更好的幫助,請發佈[SSCCE](http://sscce.org/)。 – 2011-12-29 02:17:54

+0

我看到的一個確定的問題是,你在事件線程之外調用'repaint()'。 – Bill 2011-12-29 02:28:25

+1

@AndrewThompson:完成,用另一個取代版本,並抱歉。 – SCH 2011-12-29 02:30:43

回答

1

GameApplet

了一些修改看到這個代碼。

// <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