Java:Pacman与墙壁的碰撞检测

4

我一直在尝试解决Pacman和墙之间的碰撞检测问题,但是我的实现似乎无法正确地工作。

  • 碰撞检测是否起作用?是的
  • 它是否表现正确?否
  • 当前的行为是什么?当你撞到墙时,它会停止Pacman移动,这还好,但是任何新的按键移动只会更改图像轴(向上,向右,向下或向左,具体取决于按键),它不会将Pacman移动到撞墙后的位置之外。

如果能得到帮助,将不胜感激。提前致谢。

GamePanel.java

package pacman;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable{
    private Thread animator;
    private boolean isRunning;  
    private Map map = new Map();


    public GamePanel(){
        this.setBackground(Color.BLACK);
        this.setDoubleBuffered(true);
        addKeyListener(new TAdapter());
        setFocusable(true);
    }

    @Override
    public void run() {
        isRunning = true;
        System.out.println("Is running? "+isRunning);
        long startTime, timeDiff, sleepTime; 
        startTime = System.currentTimeMillis();

        while(isRunning){
            repaint();
            gameUpdate();


             timeDiff = System.currentTimeMillis() -  startTime;
             sleepTime = 5 - timeDiff;

            try{
                Thread.sleep(sleepTime);
            }
            catch(InterruptedException ex){
                System.exit(0);
            }
            startTime = System.currentTimeMillis();

        }   
//      gameOver(); not implemented yet, will focus on this when I have some basic animation and the game loop working to satisfaction.
    }


    @Override
    public void addNotify(){
        super.addNotify();
        startGame();
    }

    public void startGame(){        
        if(animator == null || !isRunning){
            animator = new Thread(this);
            animator.start();           
        }
    } //end of StartGame method

    public void gameUpdate(){   
        map.getPlayer().move();     
        checkCollision();
    } //implementation of ingame updates such as pacman getting killed.


    public void checkCollision(){ //this is where I officially set collision up
        for(int i = 0; i < map.tiles.length; i++){
            for(int j = 0; j < map.tiles.length; j++){
                if(map.tiles[i][j] != null){
                    if(map.getPlayer().getPlayerBox().intersects(map.tiles[i][j].getR())){
                        map.getPlayer().setColliding(true);
                        System.out.println("OWW"+map.tiles[i][j].getR().getLocation());

                    }               
                }                           
            }               
        }
    }
    public void paintComponent(Graphics g){ 
        Graphics2D g2d = (Graphics2D) g;
        super.paintComponent(g);
        if(isRunning){
            drawDot(g2d);
            drawPlayer(g2d);
            map.drawMap(g2d);
        }

        Toolkit.getDefaultToolkit().sync();
        g.dispose();

    }   

    public void drawDot(Graphics2D g){
        g.setColor(Color.GREEN);
        for(int x= 0; x < 400; x++){
            for(int y = 0; y < 400; y++){
                g.drawRect(x * 20, y * 20, 1, 1);
            }
        }

    }




    public void drawPlayer(Graphics2D g){       
        g.drawImage(map.getPlayer().getImage(), map.getPlayer().getX(),map.getPlayer().getY(), this); 
    }

private class TAdapter extends KeyAdapter{      

        @Override
        public void keyPressed(KeyEvent e) {            
            map.getPlayer().keyPressed(e);  
        }
        @Override

        public void keyReleased(KeyEvent e) {
            map.getPlayer().keyReleased(e);
        }
    }
}

Player.java

package pacman;


import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;

public class Player extends Commons{
    private int dx, dy;
    private int speed = 1;
    private static int playerWidth = 52; //these figures seem off, but that is because the image is not designed correctly or the pacman image is not obeying the logic of not going passed the frame size.
    private static int playerHeight = 82;
    private Rectangle playerBox;
    private Image playerImg  = new ImageIcon(Player.class.getResource("Pacman.png")).getImage();
    private Image playerImgUp  = new ImageIcon(Player.class.getResource("PacmanUp.png")).getImage();
    private Image playerImgLeft  = new ImageIcon(Player.class.getResource("PacmanLeft.png")).getImage();
    private Image playerImgDown  = new ImageIcon(Player.class.getResource("PacmanDown.png")).getImage();

    private boolean isColliding = false;



    public Player(){
        this.setX(320);
        this.setY(280);
        playerBox = new Rectangle(this.getX(), this.getY(),40,40);
    }

    public void setSpeed(int sp){
        speed = sp;
    }

    public Image getImage(){
        if(dy == 1){            
            return playerImgDown;
        } 
        else if(dy == -1){
            return playerImgUp;
        }
        else if(dx == -1){
            return playerImgLeft;
        }
        else 
            return playerImg;       
    }//Responsible for displaying pacman image based on direction of pacman's movement.



    void move(){
        int x = this.getX();
        int y = this.getY();
        /*
         * This is the part where I am trying to implement some degree of logic to stop it from moving
         */
        if(isColliding == false){
            this.setX(x += dx);
            playerBox.setLocation(x, y);
            this.setY(y += dy);
        }else if(isColliding == true){
            this.setColliding(false);
            this.setX(this.getX());
            this.setY(this.getY());

        }

        if (this.getX() <= 1) {
            this.setX(1);
        }
        if (this.getX() >= 400 - playerWidth) {
            this.setX(400 - playerWidth);
        }
        if (this.getY() <= 2) {
            this.setY(2);
        }
        if (this.getY() >= 400 - playerHeight ) {
            this.setY(400 - playerHeight);
        }
    }//Most simplist form of collision detection, stops pacman from leaving the JFrame

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();


        if(key == KeyEvent.VK_LEFT ){
            dx = -speed;
            dy = 0;
        }
        if(key == KeyEvent.VK_RIGHT){
            dx = speed;
            dy = 0;
        }

        if(key == KeyEvent.VK_UP){
            dx = 0;
            dy = -speed;
        }
        if(key == KeyEvent.VK_DOWN){
            dx = 0;
            dy = speed;         
        }

        if(key == KeyEvent.VK_ESCAPE){
            System.exit(0);
        }   
    }



    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_LEFT){
            dy = 0;     
        }
        if(key == KeyEvent.VK_RIGHT){
            dy = 0;         
        }
        if(key == KeyEvent.VK_UP){
            dx = 0;         
        }
        if(key == KeyEvent.VK_DOWN){
            dx = 0;         
        }       
    }//end of key release



    public Rectangle getPlayerBox() {
        return playerBox;
    }




    public void setPlayerBox(Rectangle playerBox) {
        this.playerBox = playerBox;
    }


    public boolean isColliding() {
        return isColliding;
    }


    public void setColliding(boolean isColliding) {
        this.isColliding = isColliding;
    }


}// end of class

1
阅读这篇文章,获取有关调试代码的技巧。 - Code-Apprentice
1
建议使用键绑定而不是KeyListener,这样您就不需要发布新问题来解决程序无法响应按键输入的问题。此外,请注意,Swing不是线程安全的,从事件分派线程之外更新UI状态可能会导致难以复制和诊断的不可预测行为。 - MadProgrammer
嗨@MadProgrammer,感谢您的回复,我非常感激。我以前看到过类似的关于实现键绑定的回复。我想澄清一些事情。这个游戏并没有考虑最佳实践(正如代码所示),我的目标相当简单,尝试找到自己的解决方案来创建Pacman(我意识到讽刺的是来到stackoverflow上)用我自己的知识并尽快完成它。这是我的一个宠物项目/每年的决心。无论如何,我肯定会考虑您的建议。再次感谢。 - tommy knocker
1个回答

5
看起来是玩家进入一个会导致碰撞的方块,然后 isColliding 被设为 true。游戏下一次更新迭代调用移动代码时会检查玩家的 isColliding 布尔值。这个条件是成立的,所以没有移动发生。接下来检查碰撞,我们没有移出引起碰撞的方块,所以我们被卡在了这个方块里面。 建议当发生碰撞时,将玩家移到刚好不与其碰撞的位置。 我们知道玩家朝向的方向,所以我们可以使用相反的方向(将 dxdy 乘以 -1)将玩家移出碰撞的方块。

嗨Travis,感谢您的回复。正如我在开篇所说,任何回应都受到欢迎。诚然,我仍在努力寻找自己头脑中最佳移动玩家的方法,是x +1,x -1,y +1还是y -1。我会接受您的答案。再次感谢 :) - tommy knocker
我在我的回答中添加了一些更详细的内容。 - Travis

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