Java swing 中的动画问题 - Pacman

Problem with animation in Java swing - Pacman

我试图复制 Pacman 游戏,我想出了玩家动画,然后根据需要转身并循环打开和关闭嘴巴。我写了代码,它按要求正常工作。只是当我按住键(W、A、S、D)时它会张开和闭上嘴巴,但并不总是这样。我不明白错误在哪里..这是我现在的代码:

package playerAnimation;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Animation extends JPanel implements ActionListener, KeyListener  {
    
    Timer tm = new Timer(1,this);

    private String playerDirection="Right";
    private int playerX;
    private int playerY;
    private int playerSpeedX;
    private int playerSpeedY;
    
    private int spriteCounter = 0;
    private int spriteNum = 1;
    
    public BufferedImage playerUp, playerDown, playerLeft, playerRight, playerClosedMouth;
    public BufferedImage imagePlayer = null;
    
    public void getPlayerImage() {
        try {
            playerUp = ImageIO.read(getClass().getResourceAsStream("/player/imageUp.png"));
            playerDown = ImageIO.read(getClass().getResourceAsStream("/player/imageDown.png"));
            playerLeft = ImageIO.read(getClass().getResourceAsStream("/player/imageLeft.png"));
            playerRight = ImageIO.read(getClass().getResourceAsStream("/player/imageRight.png"));
            playerClosedMouth = ImageIO.read(getClass().getResourceAsStream("/player/closed.png"));
        }catch(IOException e ) {
            e.printStackTrace();
        }
    }

    Timer timer = new Timer(1,this);
    
    
    public Animation() {
        getPlayerImage();
        tm.start();
        addKeyListener(this);
        setFocusable(true);
    }
    
    
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(imagePlayer,playerX,playerY,null);
    }
    
    public void actionPerformed(ActionEvent e) {
        playerX=playerX+playerSpeedX;
        playerY=playerY+playerSpeedY;
        repaint();
    }
    

    
        public void keyPressed(KeyEvent e) {
            
            if(e.getKeyCode() == KeyEvent.VK_W) {
                
                if(spriteNum==1) {
                    imagePlayer=playerUp;
                }
                if(spriteNum==2) {
                    imagePlayer=playerClosedMouth;
                }
                
                playerSpeedX=0;
                playerSpeedY=-1;
            }
            
            if(e.getKeyCode() == KeyEvent.VK_D) {
                
                if(spriteNum==1) {
                    imagePlayer=playerRight;
                }
                if(spriteNum==2) {
                    imagePlayer=playerClosedMouth;
                }
                
                playerSpeedX=1;
                playerSpeedY=0;
            }
            
            if(e.getKeyCode() == KeyEvent.VK_A) {
                
                if(spriteNum==1) {
                    imagePlayer=playerLeft;
                }
                if(spriteNum==2) {
                    imagePlayer=playerClosedMouth;
                }
                
                playerSpeedX=-1;
                playerSpeedY=0;
            }
            
            if(e.getKeyCode() == KeyEvent.VK_S) {
                
                if(spriteNum==1) {
                    imagePlayer=playerDown;
                }
                if(spriteNum==2) {
                    imagePlayer=playerClosedMouth;
                }
                
                playerSpeedX=0;
                playerSpeedY=1;
            }
            
            spriteCounter++;
            if(spriteCounter>10) {
                if(spriteNum==1) {
                    spriteNum=2;
                }
                else if(spriteNum==2) {
                    spriteNum=1;
                }
                spriteCounter=0;
            }
            
        }

    
    public void keyTyped(KeyEvent e) {
        

    }



    public void keyReleased(KeyEvent e) {
        
    }

}

主要的:

package playerAnimation;

import javax.swing.JFrame;

public class Main {

    public static void main(String[] args) {
        
        Animation player = new Animation();
        JFrame Window = new JFrame();
        
        Window.setTitle("playerAnimation");
        Window.setSize(600,400);
        Window.setVisible(true);
        Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Window.add(player);
    
    }

}

照片如下:

playerClosedMouth

playerDown

playerLeft

playerRight

playerUp

The mouth animation only takes place when I hold down the keys

如果您希望动画在不按住键的情况下发生,则切换图像的逻辑需要移至 Timer ActionListener,以便它在您更改图像位置的同时发生变化。

(未经测试的)逻辑可能类似于:

if(e.getKeyCode() == KeyEvent.VK_W) {
    playerOpenMouth = playerUp;
    playerSpeedX=0;
    playerSpeedY=-1;
}

...

在 ActionListener 中切换 open/closed 嘴巴图像的逻辑可能类似于:

if (openMouth)
    imagePlayer = playerOpenMouth;
else
    imagePlayer = playerClosedMouth;

openMouth = !openMouth;

playerX = playerX + playerSpeedX; // use white space to improve readability
playerY = playerY + playerSpeedY;
repaint();

欢迎来到 SO。请阅读代码中的注释,了解为显示基本 packman 播放器动画所做的更改。
有关更多增强建议,请参阅待办事项评论:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class Animation extends JPanel implements ActionListener, KeyListener  {

    private int playerX , playerY, playerSpeedX, playerSpeedY;

    private boolean isMouthOpen; //flag to toggle mouth open / closed

    private static final Dimension P_SIZE = new Dimension(600,400);

    public BufferedImage playerUp, playerDown, playerLeft, playerRight, playerClosedMouth, imagePlayer;

    //publicly available images for the MRE
    private static final String IMAGE_UP ="https://i.stack.imgur.com/wD64A.png",
                                IMAGE_DOWN ="https://i.stack.imgur.com/am6PQ.png",
                                IMAGE_LEFT ="https://i.stack.imgur.com/5Pjqm.png",
                                IMAGE_RIGHT = "https://i.stack.imgur.com/sVD6m.png",
                                IMAGE_CLOSED = "https://i.stack.imgur.com/Kkw83.png"
                                ;

    public void getPlayerImage() {
        try {
            playerUp = ImageIO.read(new URL(IMAGE_UP));
            playerDown = ImageIO.read(new URL(IMAGE_DOWN));
            playerLeft = ImageIO.read(new URL(IMAGE_LEFT));
            playerRight = ImageIO.read(new URL(IMAGE_RIGHT));
            playerClosedMouth = ImageIO.read(new URL(IMAGE_CLOSED));
        }catch(IOException e ) {
            e.printStackTrace();
        }
    }

    public Animation() {
        getPlayerImage();

        //initialize player image, location and speed
        imagePlayer = playerRight;
        playerX = 100; playerY = 100; playerSpeedX = 1; playerSpeedY = 0;
        isMouthOpen = true;
        addKeyListener(this);
        setFocusable(true);
        Timer tm = new Timer(100,this);
        tm.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //if mouth is open - draw mouth closed and vice versa
        BufferedImage  image = isMouthOpen ? playerClosedMouth : imagePlayer;
        g.drawImage(image, playerX, playerY, this);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        checkBounds();
        playerX=playerX+playerSpeedX;
        playerY=playerY+playerSpeedY;
        isMouthOpen = ! isMouthOpen; //toggle mouth flag 
        //todo add control parameters to allow toggling mouth at a different rate 
        repaint();
    }

    //use key presses to change direction and player image 
    //todo: use key binding instead of KeyListener
    @Override
    public void keyPressed(KeyEvent e) {

        if(e.getKeyCode() == KeyEvent.VK_W) {
            playerSpeedX=0;
            playerSpeedY=-1;
            imagePlayer=playerUp;
        }

        if(e.getKeyCode() == KeyEvent.VK_D) {
            playerSpeedX=1;
            playerSpeedY=0;
             imagePlayer=playerRight;
        }

        if(e.getKeyCode() == KeyEvent.VK_A) {
            playerSpeedX=-1;
            playerSpeedY=0;
            imagePlayer=playerLeft;
        }

        if(e.getKeyCode() == KeyEvent.VK_S) {
            playerSpeedX=0;
            playerSpeedY=1;
            imagePlayer=playerDown;
        }
    }

    private void checkBounds(){
        //todo change direction when player hits bounds 
    }
    
    @Override
    public void keyTyped(KeyEvent e) { }
    @Override
    public void keyReleased(KeyEvent e) { }

    @Override
    public Dimension getPreferredSize() {
        return P_SIZE;
    }

    public static void main(String[] args) {

        Animation player = new Animation();
        JFrame window = new JFrame();
        window.setTitle("Player Animation");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.add(player);
        window.pack();
        window.setVisible(true);
    }
}