【问题标题】:Moving a Pacman移动吃豆子
【发布时间】:2013-07-22 09:57:34
【问题描述】:

这是我为创建吃豆人而编写的程序。我现在希望吃豆人从一个随机起点直线移动到一个随机目标点。 你能建议怎么做吗?

import javax.swing.JFrame;

/**
 * Main class for pacman example. All it does is create a frame and put
 * the pacman panel in it. 
 */


    public class PacmanGUI extends JFrame{
    private Pacman pc;
        public PacmanGUI(){
        super("Pacman");
        pc = new Pacman();
        this.getContentPane().add(pc);  
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setVisible(true);
    }
        public static void main(String[] args) {
        new PacmanGUI();
    }

}

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * Pacman class that extends JPanel and paints a pacman animation.
 * It uses Timers and Actionlistener to do the Animation.
 *
 */

    public class Pacman extends JPanel implements ActionListener{
        private int figureSize = 50;
        private static final int DELAY = 200;
        private double mouthOpenPercentages[] = {.1,.5};
        private Timer animationTimer;
        private int mouthState = 0;
        private Point pacManPosition;

    /**
     * No args constructor that starts the animation.
     */
        public Pacman(){
        startAnimation();
        }

    /**
     * Overriden paintComponent method that paints pacman.
     */
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
        pacManPosition = new Point(this.getWidth()/2 - figureSize/2,
                                    this.getHeight()/2 - figureSize/2);
        g.fillRect(0,0,this.getWidth(), this.getHeight());

    drawPacMan(g);
        mouthState = (++mouthState) % mouthOpenPercentages.length;
    }
    /**
     * Stops the animation by stopping the animation timer.     
     */
    public void stopAnimation(){ animationTimer.stop(); }

    /**
     * Method do deal with actionevents that are triggered. In this
     * case we only have actionevents being triggered from our timer 
     * and by the more usual case of a button click.
     */
    public void actionPerformed(ActionEvent e){ repaint(); }

    /**
     * Gets the size that this component would like to be.
     */
    public Dimension getPreferredSize(){ return new Dimension(400,400); }

    /**
     * Gets the minimum size for this component. 
     */
    public Dimension getMinimumSize(){ return new Dimension(200,200); }

    /**
     * Starts the animation by setting a timer. When this timer goes 
     * off the actionPerformed method will be triggered, which in 
     * turn triggers the painting.
     */
    private void startAnimation(){
        if (animationTimer == null){
            mouthState = 0;
            animationTimer = new Timer(DELAY, this);
            animationTimer.start();
        } else {  //continue animating..
            if (!animationTimer.isRunning())
            animationTimer.restart();
        }
    }
    /**
     * Draws our little pacman on the given graphics canvas.
     * @param g
     */
    private void drawPacMan(Graphics g){
        Color c = g.getColor();
        g.setColor(Color.yellow);
        g.fillOval(pacManPosition.x, pacManPosition.y, figureSize, figureSize);
        //Change color back to original and draw pacman's mouth
        g.setColor(c);
        //calculate mouth offsets
        int yOffset = (int)((figureSize/2)*mouthOpenPercentages[mouthState]);
        //draw the mouth cutout.
        int x[] = {pacManPosition.x + figureSize/2, pacManPosition.x + figureSize, pacManPosition.x + figureSize};
        int y[] = {pacManPosition.y + figureSize/2, 
                   pacManPosition.y + figureSize/2 + yOffset,
                   pacManPosition.y + figureSize/2 - yOffset};
        g.fillPolygon(x, y, x.length);
    }

}

【问题讨论】:

    标签: java swing animation pacman


    【解决方案1】:

    问题

    你必须同时管理两个动画。

    第一个,你已经编码,打开和关闭吃豆人的嘴。

    第二个动画负责将吃豆人从一个位置移动到另一个位置。

    解决方案 - Sprite 类

    我建议你创建一个 Sprite 类。 Sprite 类将负责保存精灵的当前位置、精灵的下一个位置以及精灵移动的速度。

    您可以扩展 Sprite 以获得一个 Pacman 类和一个具有 4 个实例的 Chaser 类。

    吃豆人类

    Pacman 类将负责嘴部动画。

    追逐者类

    Chaser 类将负责确定是追逐 Pacman,还是逃离 Pacman。

    挥杆技巧

    您不应扩展 Java Swing 组件,除非您要覆盖一个或多个组件类。您应该使用 Swing 组件。

    您应该始终在事件调度线程 (EDT) 上启动 Swing GUI。您可以通过执行 SwingUtilities 的 invokeLater 方法来做到这一点。

    您应该有一个 GUI 模型,与您的 GUI 组件分开。我定义的三个类将成为您的 GUI 模型的一部分。你还需要布置一个迷宫。

    【讨论】:

    • 事件调度线程 (EDT) 上的 Swing GUI 如果您使用 GUI 构建器,Java 将为您提供。没有它,课程将运行良好。您能否解释一下这将如何使课程安全,或者是否有必要将您的所有代码放在 EDT 中。
    • @user3376708:Sun(现在是 Oracle)说要把你的 Swing 组件放在 Event Dispatch thread (EDT) 上。您的所有 Swing 组件都应在 EDT 上创建和更新。否则,您可能会遇到一些难以调试的竞争条件。如果我无视 Oracle 专家的建议,我很难让自己的代码正常工作,而不会试图制造其他问题。
    • 所以每次你创建一个swing组件时,你必须创建一个Runnable()线程还是main方法中的一个多线程。实际上,如果您可以提供几个代码示例会有所帮助。如果可以的话,通过小提琴网站将它们链接起来。
    • @user3376708:选择Java Articles 中的任何Java Swing 文章。
    【解决方案2】:

    Pacman 类中,您需要再创建 2 个值来存储起点和终点。你已经声明了private Point pacManPosition;,所以我也将它们声明为Points。您需要将 pacManPosition 初始设置为起点。

    Point start = // random start point
    Point end = // random end point
    Point pacManPoint = new Point(start);
    

    现在您需要确定 Pacman 的移动速度,假设为每帧 2 个像素。

    int speed = 2;
    

    要确定 Pacman 每帧移动多少,我们需要进行一些计算。一、获取直线的距离——

    double distance = Math.sqrt(Math.pow(end.x - start.x, 2) + 
                                Math.pow(end.y - start.y, 2));
    

    然后我们计算以我们想要的速度走那个距离需要多少帧。

    int totalFrames= (int)Math.round(distance / speed);
    

    并添加一个帧计数器 -

    int frame = 0;
    

    现在,看看你的 paintComponent 方法。现在,您每次绘制时都将pacManPosition 设置为同一点(面板的中心)。你想要在这里做的是更新pacManPosition 每帧直到它到达结束位置。你在paintComponent 中做类似的事情,你每次都在更新mouthState 以使嘴巴有动画。对于动画位置,它看起来像 -

    if (frame < totalFrames) {
        pacManPosition.x = start.x + frame * (end.x - start.x) / totalFrames;
        pacManPosition.y = start.y + frame * (end.y - start.y) / totalFrames;
        frame++;
    }
    

    这只是做运动动画的一种方式,它假设了几件事——恒定的速度,不需要避开障碍物,没有玩家控制。 totalFrames 中的计算并不准确 - 它会将 pacMan 移动到接近终点,但不能保证它会准确地结束。它还与帧速率有关,这有缺点。根据具体情况,还有很多很多其他方法可以做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-13
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2022-08-15
      • 2019-08-16
      • 2013-01-03
      相关资源
      最近更新 更多