Java 这个小程序gameloop有什么问题?

Java 这个小程序gameloop有什么问题?,java,applet,game-loop,Java,Applet,Game Loop,这个小程序似乎只会在窗口调整大小或最小化时绘制和更新绘制。因此,小程序不会一直重新绘制,而只是在操作窗口时 我做错什么了吗 我将遵循此处介绍的gameloop: 代码如下: package newapplet; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GameApplet extends JApplet { // main class for the game as

这个小程序似乎只会在窗口调整大小或最小化时绘制和更新绘制。因此,小程序不会一直重新绘制,而只是在操作窗口时

我做错什么了吗

我将遵循此处介绍的gameloop:

代码如下:

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();
     }
  });
}
}
packagenewapplet;
导入java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
公共类GameApplet将游戏的JApplet{//main类扩展为Swing应用程序
//为游戏定义常量
静态最终int CANVAS_WIDTH=493;//游戏屏幕的宽度和高度
静态最终整型画布高度=411;
静态最终整型更新_RATE=4;//每秒游戏更新次数
静态最终长更新周期=1000000000L/更新速率;//纳秒
静态整数=0;
// ......
//游戏状态的枚举。
公共枚举博弈状态{
初始化、连接、播放、断开连接
}
私人游戏状态;
//为游戏对象定义实例变量
// ......
// ......
//自定义图形面板的控制柄
私人游戏画布;
//构造函数来初始化UI组件和游戏对象
公共GameApplet(){
//初始化游戏对象
gaminit();
//用户界面组件
canvas=新游戏画布();
setPreferredSize(新维度(画布宽度、画布高度));
这个.setContentPane(画布);
//其他UI组件,如按钮、记分板(如有)。
// ......
此.setVisible(true);
}
//所有与游戏相关的代码都在这里
//初始化所有游戏对象,只在主类的构造函数中运行一次。
public void gaminit(){
// ...... 
state=gameState.INITIALIZED;
}
//关闭游戏,清理只运行一次的代码。
公共空间关闭(){
// ...... 
状态=游戏状态。断开连接;
}
//开始并重新开始游戏。
public void gameStart(){
//创建一个新线程
线程gameThread=新线程(){
//重写run()以提供此线程的运行行为。
@凌驾
公开募捐{
gameLoop();
}
};
//启动线程。Start()调用run(),run()又调用gameLoop()。
gamesthread.start();
}
//在这里运行游戏循环。
私有void gameLoop(){
//为新游戏重新生成游戏对象
// ......
//状态=状态。播放;
//游戏循环
漫长的开始,耗时的,永恒的;
while(true){
beginTime=System.nanoTime();
if(state==gameState.DISCONNECTED)break;//中断循环以完成当前游戏
if(state==gameState.PLAYING){
//更新所有游戏对象的状态和位置,
//检测碰撞并提供响应。
gameUpdate();
}
//刷新显示
重新油漆();
//延迟定时器,提供必要的延迟,以满足目标速率
timetake=System.nanoTime()-beginTime;
timeLeft=(更新周期-timetake)/1000000L;//以毫秒为单位
如果(timeLeft<10)timeLeft=10;//设置最小值
试一试{
//提供必要的延迟,并产生控制,以便其他线程可以执行工作。
线程。睡眠(timeLeft);
}catch(InterruptedException ex){}
}
}
//更新所有游戏对象的状态和位置,
//检测碰撞并提供响应。
public void gameUpdate(){
}
//刷新显示。通过调用paintComponent()的rapaint()调用。
私有void gameDraw(Graphics2D-g2d){
开关(状态){
案例初始化:
g2d.setColor(Color.red);
g2d.拉索(“初始”,20,20);
打破
案例分析:
g2d.setColor(Color.red);
g2d.drawString(“play”,20,20);
打破
案例连接:
g2d.setColor(Color.red);
g2d.抽绳(“连接”,20,20);
打破
断开连接的情况:
g2d.setColor(Color.red);
g2d.抽绳(“断开”,20,20);
打破
}
g2d.setColor(Color.GREEN);
g2d.drawString(“重新喷漆:”+图纸,30,30);
这个.DRAWS++;
// ...... 
}
//处理按键事件。更新当前状态。
按下公共无效游戏键(int keyCode){
开关(钥匙代码){
case KeyEvent.VK_UP:
// ......
打破
case KeyEvent.VK_向下:
// ......
打破
case KeyEvent.VK_左:
// ......
打破
case KeyEvent.VK_RIGHT:
// ......
打破
}
}
//处理密钥释放事件。
public void gameKeyReleased(int-keyCode){}
//处理键类型的事件。
public void gameKeyTyped(char-keyChar){}
//其他方法
// ......
//自定义绘图面板,作为内部类编写。
类GameCanvas扩展JPanel实现KeyListener{
//建造师
公共游戏画布(){
setFocusable(true);//以便可以接收键事件
requestFocus();
addKeyListener(此);
}
//替代paintComponent以进行自定义绘图。
//通过重新绘制()回调。
@凌驾
公共组件(图形g){
Graphics2D g2d=(Graphics2D)g;
super.paintComponent(g2d);//绘制背景
setBackground(Color.BLACK);//可以使用图像作为背景
//绘制游戏对象
游戏绘制(g2d);
}
//关键事件处理程序
@凌驾
按下公共无效键(按键事件e){
gameKeyPressed(例如getKeyCode());
}
@凌驾
公共无效密钥已释放(密钥事件e){
gameKeyReleased(如getKeyCode());
}
@凌驾
public void keyTyped(KeyEvent e){
gameKeyTyped(如getKeyChar());
}
}
//主要
公共静态void main(字符串[]args){
//使用事件分派线程来构建线程安全的UI。
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
新的GameApplet();
}
});
}
}

快速浏览该代码,我可以看到您正在事件分派线程之外调用repaint(),这可能会导致类似您所看到的问题。invokeAndWait(Runnable r)将允许您将
// <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