1

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

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);
    }

}
4

2 回答 2

1

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 移动到接近终点,但不能保证它会准确地在那里结束。它还与帧速率有关,这有缺点。根据具体情况,还有很多很多其他方法可以做到这一点。

于 2013-07-23T13:52:36.007 回答
1

问题

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

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

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

解决方案 - Sprite 类

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

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

吃豆子类

Pacman 类将负责嘴部动画。

追逐者类

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

摇摆技巧

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

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

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

于 2013-07-23T13:45:48.110 回答