移动吃豆子

时间:2013-07-23 11:03:49

标签: java swing animation pacman

这是我为创建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);
    }

}

2 个答案:

答案 0 :(得分:1)

问题

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

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

第二个动画负责将吃豆子从一个地方移动到另一个地方。

解决方案 - 精灵类

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

你会扩展Sprite以获得一个Pacman类,以及一个包含4个实例的Chaser类。

Pacman类

Pacman班负责口腔动画。

追逐者类

追逐者类将负责决定是否追捕吃豆子,或逃离吃豆子。

挥杆提示

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

您应该始终在事件调度线程(EDT)上启动Swing GUI。您可以通过执行SwingUtilities的invokeLater方法来完成此操作。

您应该拥有一个与GUI组件分开的GUI模型。我定义的三个类将是GUI模型的一部分。你还需要摆出一个迷宫。

祝你的项目好运。

答案 1 :(得分:1)

Pacman类中,您需要再创建2个值来存储起点和终点。您已经声明了private Point pacManPosition;,因此我也将其声明为Point。您最初要将pacManPosition设置为起点。

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

现在你要确定你希望Pacman移动的速度,比方说每帧2个像素。

int speed = 2;

为了确定每帧移动吃豆子的数量,我们需要做一些计算。首先,获取线的距离 -

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

相关问题