【问题标题】:How to pause and resume a simple game in Java如何在 Java 中暂停和恢复一个简单的游戏
【发布时间】:2011-11-28 16:31:53
【问题描述】:

我用java做了一个简单的游戏,关于“网球背景”和“网球”,球是随机自动移动的,

我的游戏包含两个文件,第一个文件用于 Jpanel,第二个文件用于 JFrame,

我的问题是:我需要通过单击鼠标来控制“停止和恢复”球, 我试图在线程运行循环期间放置wait(),但它失败了,我不知道是什么原因! ,所以请检查我的代码,然后告诉我有什么问题,以及在我的简单游戏中“暂停和恢复”线程的真正方法是什么!

tennis.java 文件(包含线程):

/*
 * tennis.java
 *
 * Created on Nov 15, 2011, 3:35:28 PM
 */
package io;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;


public class tennis extends javax.swing.JPanel implements Runnable{

    BufferedImage ball;
    BufferedImage bg;
    int ball_h = 0;
    int ball_w = 0;
    int height = 0;
    int width  = 0;
    int yPos   = -1;
    int xPos   = 10;
    int pause  = 20;

    // Move Speed
    int xMov   = 5;
    int yMov   = 10;
    boolean clicked = false;
    int play    =   0;

    Thread runner;

    /** Creates new form tennis */
    public tennis() throws IOException {

        ball = ImageIO.read(new File("tennis/ball.png"));
        bg = ImageIO.read(new File("tennis/bg.jpg"));
        ball_h = 50;
        ball_w = 50;
        height = 600 - ball_h;
        width  = 800  - ball_w;

        runner = new Thread(this);
        runner.start();

    }

    public void start(){
       if(play == 0){

           play     =   1;
           clicked = true;

       }else{
           play    =  0;
           clicked = true;
       }

       System.out.println(play);
    }

    public void stop(){
        runner = null;
    }




    @Override
    public void paint(Graphics g){
        Graphics2D g2D  =   (Graphics2D) g;

        g2D.drawImage(bg, 0, 0, 800,600, this);
        g2D.drawImage(ball, xPos, yPos,50,50, this);
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>                        
    // Variables declaration - do not modify                     
    // End of variables declaration                   

    @Override
    public void run() {

        while(runner == runner){



                    if(xPos >= (width))
                        {
                           xMov   *= -1;   
                        }



                           xPos   += xMov;

                    if(xPos < 1)
                        {
                           xMov   *= -1;   
                        }                

                    if(yPos >= (height-ball_h))
                        {
                            yMov    *= -1 ;
                        }



                            yPos    += yMov;

                     if(yPos < 1)
                        {
                            yMov    *= -1 ;
                        }

                    repaint();



                    try {
                        if(play == 1){
                            Thread.sleep(pause);
                        }else{
                            synchronized(this){
                                while(play == 0){
                                wait();
                              }
                            }
                        }

                    } catch (InterruptedException ex) {
                        Logger.getLogger(tennis.class.getName()).log(Level.SEVERE, null, ex);
                    }

        }  
    }

}

Tennis3D.java 文件(启动游戏和定义线程的框架):

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * Tennis3D.java
 *
 * Created on Nov 15, 2011, 3:42:42 PM
 */
package io;

import io.tennis;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Tennis3D extends javax.swing.JFrame implements MouseListener{

    tennis tennis;

    /** Creates new form Tennis3D */
    public Tennis3D() {
        super("Tennis3D");
        setSize(800,600);


        try {
            tennis = new tennis();
            add(tennis);
            tennis.addMouseListener(this);
        } catch (IOException ex) {
            Logger.getLogger(Tennis3D.class.getName()).log(Level.SEVERE, null, ex);
        }


        setVisible(true);

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
       Tennis3D tennis = new Tennis3D();
    }
    // Variables declaration - do not modify                     
    // End of variables declaration                   

    @Override
    public void mouseClicked(MouseEvent e) {
       tennis.start();
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

感谢您的帮助:)

【问题讨论】:

  • 一种方法是使用 update() 方法,该方法根据自上次调用以来经过的时间移动游戏对象。然后在更新方法的顶部,检查用于指示游戏暂停的标志。如果游戏暂停,直接返回,不要进行任何更新。
  • >while(runner == runner)??你的意思是while(true)?
  • int play = 1 - 你为什么不为此使用boolean?并且请将您的显示代码与您的“模型”(网球)代码分开,这将使以后的工作更容易。

标签: java multithreading actionlistener java-3d


【解决方案1】:

这是对 Nerdtron 在上述评论中所写内容的支持。通常一个游戏循环是这样的

 while (!game.isOver())
 {
      if (!game.isPaused())
           game.update()  // this moves your ball, players, etc
 }

【讨论】:

    【解决方案2】:

    你的方法很奇怪。大多数游戏都有一个主循环,其中方法 update(deltaTime) 和 draw() 被顺序调用。

    典型的主循环:

    initGame();
    while(!gameOver)
    {
        readInput();
        update(deltaTime);
        draw();
    }
    

    update(dt) 类似于

    for(GameObject go : myObjectList)
    {
        go.update(deltaTime);
    }
    

    如果你想跳过一些对象,你可以使用类似的东西:

    for(GameObject go : myObjectList)
    {
        if(go.isActive())
        {
            go.update(deltaTime);
        }
    }
    

    因此,如果您使用这样的游戏循环结构,您的任务将是微不足道的。

    【讨论】:

      【解决方案3】:

      要停止线程等待(),您需要在同一个对象上调用 notifyAll()。

      来自 Object.wait() 的 Javadoc

      使当前线程等待,直到另一个线程为此对象调用 notify() 方法或 notifyAll() 方法。

      我建议您在设置 play = 1; 时在同步块中调用 notifyAll()

      【讨论】:

        【解决方案4】:

        实现此目的的常用方法是使用不同的状态。因此,当您暂停游戏时,它会进入PAUSE 状态。恢复后,它将返回RUNNING 状态或其他(更具体的)状态。
        这是通过将状态保存在变量中来完成的。 C-方式是定义整数如下:

        final int PAUSE = 1;
        final int RUNNING = 2;
        

        Java-方式更像这样:(使用enums)

        public enum State {
            RUNNING,
            PAUSE
        }
        

        然后,在您的主循环(run 方法)中检查游戏当时的状态,并执行相应的操作。

        switch(state){
            case PAUSE:
                Thread.sleep(100);
                break;
            case RUNNING:
                // do something entertaining
                break;
        }
        

        【讨论】:

          【解决方案5】:

          因此,如果您的游戏循环包含一个刻度方法或更新所有游戏对象值的特定方法,您可以创建一个名为 aused 的布尔值,并且仅在 !paused 时才更新游戏值。

          您还可以使用扩展鼠标适配器的类并将鼠标侦听器添加到您的主类。因此,每当鼠标单击时,它都会检查它是否已暂停。如果暂停则取消暂停,如果取消暂停则暂停

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-01
            • 2011-03-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多