Java 游戏编程第 1 部分:平滑运动



我是计算机课(高中新生)中三个成员小组的三分之一。对于我们的项目,我们决定用Java制作一个吃豆人风格的游戏。我们都没有太多的经验,所以到目前为止,我们基本上一直在自学。我们已经取得了相当大的进展,但在这一点上我们似乎已经停滞不前。以下是我们的主要问题:

  1. 我们如何让我们的吃豆人(胖子)在瓷砖上平稳移动?他逐块移动,但这看起来不专业。此外,当你按住箭头键时,他在屏幕上拉动。我们如何防止这种情况发生?

(我还有其他需要帮助的事情,但它们有不同的问题)

感谢您的帮助!

以下是我们到目前为止的代码:

迷宫类:

package Fatman;
import javax.swing.*;
public class Maze {
    public static void main(String[] args){
        new Maze();
    }
    public Maze(){
        JFrame f = new JFrame();
        f.setTitle("Fatman!");
        f.add(new Board());
        f.setSize(816, 838);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

地图类

    package Fatman;
import java.awt.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
public class Map {
    private Scanner m;
    private String Map[] = new String[25]; 
    private Image spaceregcandy,
                  srcb,
                  safehouse,
                  spacebigcandy,
                  blackspace,
                  space,
                  portal1,
                  portal2,
                  wall;
    public Map(){
        ImageIcon img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\spaceregcandy.png");
        spaceregcandy = img.getImage();
        //image icon has already been initiated, so it doesn't have to be written again
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\spaceregcandyblue.png");
        srcb = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\safehouse.png");
        safehouse = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\wall232x.png");
        wall = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\spacebigcandy.png");
        spacebigcandy = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\blackspace.png");
        blackspace = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\space.png");
        space = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\portal1.png");
        portal1 = img.getImage();
        img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\portal2.png");
        portal2 = img.getImage();
        openFile();
        readFile();
        closeFile();
        }
    public Image getSpaceregcandy(){
        return spaceregcandy;
    }
    public Image getSrcb(){
        return srcb;
    }
    public Image getSafehouse(){
        return safehouse;
    }
    public Image getWall(){
        return wall;
    }
    public Image getSpacebigcandy(){
        return spacebigcandy;
    }
    public Image getBlackspace(){
        return blackspace;
    }
    public Image getSpace(){
        return space;
    }
    public Image getPortal1(){
        return portal1;
    }
    public Image getPortal2(){
        return portal2;
    }
    public String getMap(int x, int y){
        String index = Map[y].substring(x, x + 1);
        return index;
        //in y position, if y = 2, goes to second row (substring gets x position)
    }
    public void openFile(){
        try{
        m = new Scanner(new File("C:\Users\Martin\Desktop\Fatman Project\map3.txt"));
        }catch(Exception e){
            System.out.println("error loading map");
        }
    }
    public void readFile(){
        while(m.hasNext()){
            for(int i = 0; i < 25; i++){
                Map[i] = m.next();
            }
        }
    }
    public void closeFile(){
        m.close();
    }
}

董事会类

package Fatman;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.*;
public class Board extends JPanel implements ActionListener{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Timer timer;
    private Image player;
    private Map m;
    private Player p;
    public Board(){
        m = new Map();
        p = new Player();
        addKeyListener(new Al());
        setFocusable(true);
        timer = new Timer(1, this);
        timer.start();
    }
    public void actionPerformed(ActionEvent e){
        repaint();
    }
    public void paint(Graphics g){
        super.paint(g);
        for(int y = 0; y < 25; y++){
            for(int x = 0; x <25; x++){
                if(m.getMap(x, y).equals("o")){
                    g.drawImage(m.getSpaceregcandy(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("O")){
                    g.drawImage(m.getSrcb(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("x")){
                    g.drawImage(m.getWall(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("H")){
                    g.drawImage(m.getSafehouse(), x *32, y *32, null);
                }   
                if(m.getMap(x, y).equals("C")){
                    g.drawImage(m.getSpacebigcandy(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("b")){
                    g.drawImage(m.getBlackspace(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("s")){
                    g.drawImage(m.getSpace(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("p")){
                    g.drawImage(m.getPortal1(), x *32, y *32, null);
                }
                if(m.getMap(x, y).equals("P")){
                    g.drawImage(m.getPortal2(), x *32, y *32, null);
                }
        }

    }

        g.drawImage(p.getPlayer(), p.getTileX() * 32, p.getTileY() * 32, null);
}
    public class Al extends KeyAdapter{
        public void keyPressed(KeyEvent e){
            int keycode = e.getKeyCode();
            if(keycode == KeyEvent.VK_UP){
                if(!m.getMap(p.getTileX(), p.getTileY() -1).equals("x")){
                    if(!m.getMap(p.getTileX(), p.getTileY() -1).equals("b")){                       
                        }
                        p.move(0, -1);                  
                        System.out.println(m.getMap(p.getTileX(), p.getTileY()));
            }
                }
            if(keycode == KeyEvent.VK_DOWN){
                if(!m.getMap(p.getTileX(), p.getTileY() +1).equals("x")){
                    if(!m.getMap(p.getTileX(), p.getTileY() +1).equals("b")){
                        p.move(0, 1);
                        System.out.println(m.getMap(p.getTileX(), p.getTileY()));
            }
                }
            }
            if(keycode == KeyEvent.VK_LEFT){
                if(!m.getMap(p.getTileX() - 1, p.getTileY()).equals("x")){
                    if(!m.getMap(p.getTileX() - 1, p.getTileY()).equals("b")){
                        p.move(-1, 0);
                        System.out.println(m.getMap(p.getTileX(), p.getTileY()));
            }
                }
            }
            if(keycode == KeyEvent.VK_RIGHT){
                if(!m.getMap(p.getTileX() + 1, p.getTileY()).equals("x")){
                    if(!m.getMap(p.getTileX() + 1, p.getTileY()).equals("b")){
                        p.move(1, 0);
                        System.out.println(m.getMap(p.getTileX(), p.getTileY()));
            }
            }
            }
            }

        public void keyReleased(KeyEvent e){
        }
        public void keyTyped(KeyEvent e){
}
}
}

玩家类

package Fatman;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Player {
    private int tileX, tileY;
    private int dx, dy;
    private Image player; 
    public Player(){
        ImageIcon img = new ImageIcon("C:\Users\Martin\Desktop\Fatman Project\FATMANsimplified32xbrown.png");
        player = img.getImage();
        tileX = 12;
        tileY = 18;
    }
    public Image getPlayer(){
        return player;
    }
    public int getTileX(){
        return tileX;
    }
    public int getTileY(){
        return tileY;
    }
    public void move(int dx, int dy){
        tileX += dx;
        tileY += dy;
    }
}

有什么想法吗?

对于您的第一个问题,请注意您只是在移动方法中增加图块数,然后在该位置重新绘制玩家(增量为 32 像素)。您需要比这更精细的粒度级别,即不是按磁贴本身递增,而是按磁贴的一部分递增(例如增加 2 个像素)。这样胖子的形象就会采取更多的步骤从一块图块移动到另一块图块。显然,如果FatMan的图像播放器在这段时间内播放行走/跑步动画,使运动看起来更自然,看起来会更好。

所以......在无耻的自我推销中,我邀请你看看我的旧教程:https://sites.google.com/site/javagamescorner/home/animated-sprites

有两个问题:

首先,你需要在每次更新之间进行某种睡眠/暂停来模拟时间,否则如果你按住键,玩家会立即跳到地图的尽头。因为您希望在玩家采取每一步后经过一些时间。

一种可能性是在每次调用后添加 Thread.sleep。

其次,您需要将玩家移动与图块坐标系分离。如果您希望玩家能够"在瓷砖之间移动"。他应该使用自己的坐标系,允许他移动较小的步骤。

为了避免你的胖子从右向左滑倒,反之亦然,你可以参考这个问题: Java KeyListener keyPress方法触发太快

对于动画,您必须编写一些代码才能将 1 个磁贴移动到另一个磁贴。

我已经阅读了您的代码,并建议您进行以下修改:

  • 当您按下一个键时,您将一个方向设置为向上,向下,向左或向右作为下一个方向(因为方向必须保持直到移动完成)。您可以使用两个类变量实现:direction 和 nextDirection。您还可以使用磁贴边缘大小的值设置另一个类变量(例如,32)。此变量称为 animationFrame。
  • 在此示例中,您将计时器频率或多或少设置为 32 Hz(1000/32 毫秒)。您可以使用计时器来适应动画。
  • 每次调用计时器时,您都会沿方向(读取方向变量)移动胖子图像 1 个像素,然后减少 animationFrame。当你达到0时,胖子被放置在下一个瓷砖中。您可以通过设置方向 = 下一个方向来收获操作。现在你必须在这一点上应用游戏的逻辑(碰撞等)。

这只是一个粗略的方法,但我认为你可以从这个想法开始。这让我想起了我 16 岁时用 java 编写的贪吃蛇游戏。

最新更新