Java游戏编程系列之一:流畅移动

3
我是一个计算机课程中三人小组的一份子(高中新生)。我们决定用Java制作一个类似于吃豆人的游戏。由于我们没有太多经验,所以到目前为止,我们基本上一直在自学。我们取得了相当大的进展,但现在似乎已经到了停滞不前的地步。以下是我们的主要问题:
  1. 我们如何使我们的Pacman(Fatman)平稳地移动到每个方块上?他一次只能移动一个方块,但那看起来不够专业。此外,当你按住箭头键时,他会在屏幕上飞快移动。我们该怎么防止这种情况发生?

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

感谢您的帮助!

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

Maze Class:

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

}

任何想法吗?

1
使用线程 - elyashiv
这是一个比较宽泛的问题。你应该尝试将其分解成更具体的问题。 - Charles Forsythe
2
不要在键监听器中移动你的吃豆人。设置一个标志,以便知道按键已按下,并在线程中相应地移动,同时检查这些标志。还有一种叫做KeyBinding的东西,我看到很多人谈论它,但我对它们不太了解。不过据说它更好。 - Cruncher
4个回答

1
对于你的第一个问题,需要意识到在移动方法中只是增加了图块编号,稍后在该位置重新绘制玩家(增加了32像素)。你需要更细致的粒度,即不是按照图块本身进行增量,而是按照图块的一部分进行增量(例如2个像素)。这样FatMan的形象将需要更多步骤才能从一个图块移动到另一个图块。显然,如果FatMan的形象在此期间播放行走/奔跑动画,将使移动看起来更自然更好。

所以……我毫不掩饰地推荐您查看我的旧教程: https://sites.google.com/site/javagamescorner/home/animated-sprites


我知道你可能有更重要的事情要做,而不是帮助一个15岁的孩子,但考虑到我的Java知识非常基础,你能否再解释一下?我该如何让我们的角色像素级移动,而不是瓷砖级移动?我唯一能想到的就是想出一个变量来表示图像的中心,并在每个y毫秒添加x,只要没有按下另一个按钮...不过我不确定这是否有效。非常感谢您的帮助!非常感激! - leo882

0

有两个问题:

首先,你需要在每次更新之间添加一些睡眠/暂停来模拟时间,否则如果你一直按住键,玩家将立即跳到地图的末尾。因为你想让玩家在每走一步后经过一些时间。

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

其次,你需要将玩家的移动与你的瓷砖坐标系统分离开来。如果你希望玩家能够“在瓷砖之间移动”,他应该使用自己的坐标系统,使他能够移动更小的步骤。


0
为了避免你的角色在左右滑动时出现滑动不稳定的情况,你可以参考这个问题:Java KeyListener keyPressed method fires too fast
对于你的动画效果,你需要编写代码来实现将一个方块移动到另一个方块的功能。

0
我已经阅读了你的代码,我建议你进行以下修改:
  • 当你按键时,你设置一个方向,可以是上、下、左或右作为下一个方向(因为方向必须保持到移动完成)。你可以用两个类变量实现:方向和下一个方向。你还设置另一个类变量,其值为你的图块边缘大小(例如,32)。这个变量被称为animationFrame。
  • 在这个例子中,你将定时器频率设置为大约32 Hz(1000/32毫秒)。你可以通过调整定时器来适应动画。
  • 每次调用定时器时,你按照方向(读取方向变量)将你的胖人图像移动1个像素,并减小animationFrame。当你达到0时,胖人就放置在下一个图块中。你可以通过设置direction=nextDirection来重复操作。现在你必须在这一点上应用游戏逻辑(碰撞等)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接