首页 > 解决方案 > JAVA 贪吃蛇游戏错误。蛇在 3 步后停止

问题描述

这是我在这里的第一个查询。我正在构建一个运行完美但身体仅移动三步并暂停的蛇游戏。以下是游戏的代码,我有 main 方法,但它绝对没问题。图片:按右箭头之前。.......... 图片:按右箭头后

主要方法:

public class Snake {

public static void main(String[] args){

    Gameplay gplay = new Gameplay();
    JFrame obj = new JFrame();
    obj.setTitle("Super SNake");
    obj.setBounds(10, 10, 905, 700);
    obj.setBackground(Color.getHSBColor(192, 68, 66));
    obj.setResizable(false);
    obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    obj.add(gplay);
    obj.setVisible(true);
}

}

游戏代码:

public class Gameplay extends JPanel implements KeyListener, ActionListener{

private int[] snakeXlength = new int[750];
private int[] snakeYlength = new int[750];
private int lengthsnake = 3;
private int moves = 0;

private boolean left = false;
private boolean right = false;
private boolean up = false;
private boolean down = false;

private ImageIcon umouth;
private ImageIcon lmouth;
private ImageIcon rmouth;
private ImageIcon dmouth;

private ImageIcon body;
private ImageIcon imagetitle;

private Timer t;
private int delay = 100;

public Gameplay(){

    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
    t = new Timer(delay,this);
    t.start();

}

public void paint(Graphics g){
    if(moves==0){

        snakeXlength[2] = 50;
        snakeXlength[1] = 75;
        snakeXlength[0] = 100;

        snakeYlength[2] = 100;
        snakeYlength[1] = 100;
        snakeYlength[0] = 100;
    }


    //title border
    g.setColor(Color.black);
    g.drawRect(24, 10, 851, 55);
    //title
    imagetitle = new ImageIcon( getClass().getResource("title.jpg"));
    imagetitle.paintIcon(this, g, 25, 11);
    //play area
    g.setColor(Color.black);
    g.drawRect(24, 74, 851, 577);
    //bg for play area
    g.setColor(Color.black);
    g.fillRect(25, 75, 850, 575);
    rmouth = new ImageIcon( getClass().getResource("rmouth.png") );
    //rmouth = new ImageIcon("game/rmouth.png");
    rmouth.paintIcon(this, g, snakeXlength[0], snakeYlength[0]);

    for(int a=0; a<lengthsnake; a++){
        if(a==0 && right){
        rmouth = new ImageIcon( getClass().getResource("rmouth.png") );
        //rmouth = new ImageIcon("rmouth.png");
        rmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
        }
        if(a==0 && left){
        lmouth = new ImageIcon( getClass().getResource("lmouth.png") );
        //lmouth = new ImageIcon("lmouth.png");
        lmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
        }
        if(a==0 && up){
        umouth = new ImageIcon( getClass().getResource("umouth.png") );
        //umouth = new ImageIcon("umouth.png");
        umouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
        }
        if(a==0 && down){
        dmouth = new ImageIcon( getClass().getResource("dmouth.png") );
        //dmouth = new ImageIcon("dmouth.png");
        dmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
        }
        if(a!=0){
        body = new ImageIcon( getClass().getResource("body.png") );
        //body = new ImageIcon("body.png");
        body.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
        }
        }
        g.dispose();
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
     if(e.getKeyCode()== KeyEvent.VK_RIGHT){
    moves++;
    right= true;
    if(!left){
     right=true;
    }
    else{
    right= false;
    left= true;
    }
}

if(e.getKeyCode()== KeyEvent.VK_LEFT){
 moves++;
left= true;
if(!right){
left=true;
}
else{
 left= false;
 right= true;
}
up=false;
down=false;
}
if(e.getKeyCode()== KeyEvent.VK_UP){
moves++;
up= true;
if(!down){
up=true;
}
else{
up= false;
down= true;
}

left=false;
right=false;
}

if(e.getKeyCode()== KeyEvent.VK_DOWN){
moves++;
down= true;
if(!up){
down=true;
}
else{
down= false;
up= true;
}

left=false;
right=false;
}

}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void actionPerformed(ActionEvent e) {
    t.start();

if(right){

for(int r= lengthsnake-1; r>=0; r--){
snakeYlength[r+1]= snakeYlength[r];
}
for(int r=lengthsnake; r>0; r--){
if(r==0){
 snakeXlength[r]= snakeXlength[r]+25;
}
else{
 snakeXlength[r]= snakeXlength[r-1];
}

if(snakeXlength[r]> 850){
 snakeXlength[r]= 25;
}
}

repaint();
}

    if(left){

    for(int r= lengthsnake-1; r>=0; r--){
snakeYlength[r+1]= snakeYlength[r];
}
for(int r=lengthsnake; r>0; r--){
if(r==0){
 snakeXlength[r]= snakeXlength[r] -25;
}
else{
 snakeXlength[r]= snakeXlength[r-1];
}

if(snakeXlength[r]< 25){
 snakeXlength[r]= 850;
}
}

repaint();
    }
    if(up){

    for(int r= lengthsnake-1; r>=0; r--){
snakeXlength[r+1]= snakeXlength[r];
}
for(int r=lengthsnake; r>0; r--){
if(r==0){
 snakeYlength[r]= snakeYlength[r]+25;
}
else{
 snakeYlength[r]= snakeYlength[r-1];
}

if(snakeYlength[r]< 625){
 snakeYlength[r]= 75;
}
}

repaint();
}
    if(down){

    for(int r= lengthsnake-1; r>=0; r--){
snakeXlength[r+1]= snakeXlength[r];
}
for(int r=lengthsnake; r>0; r--){
if(r==0){
 snakeYlength[r]= snakeYlength[r] +25;
}
else{
 snakeYlength[r]= snakeYlength[r-1];
}

if(snakeYlength[r] > 625){
 snakeYlength[r]= 75;
}
}

repaint();
    }

    }

}

我希望你能帮助我解决我的问题。我不知道我错在哪里。蛇移动但在 3 步后停止,它仍然在改变头部方向,但只是在那个位置。这是我在堆栈溢出中的第一个查询。我希望以上数据有助于理解问题。请帮助我找到解决方案。

标签: javaswingjframejpanelawt

解决方案


所以,有很多事情是“错误的”,但我将从最明显的问题开始。

只看right方向处理程序......

for (int r = lengthsnake; r > 0; r--) {
    if (r == 0) {
        snakeXlength[r] = snakeXlength[r] + 25;
    } else {
        snakeXlength[r] = snakeXlength[r - 1];
    }

    if (snakeXlength[r] > 850) {
        snakeXlength[r] = 25;
    }
}

在这个循环中没有办法r等于0,这意味着0元素永远不会改变。

应该更像...

for (int r = lengthsnake; r > 0; r--) {
    snakeXlength[r] = snakeXlength[r - 1];

    if (snakeXlength[r] > 850) {
        snakeXlength[r] = 25;
    }
}
snakeXlength[0] = snakeXlength[0] + 25;
if (snakeXlength[0] > 850) {
    snakeXlength[0] = 25;
}

我怀疑所有其他“方向”处理程序都有同样的问题。

下一个...

@Override
public void actionPerformed(ActionEvent e) {
    t.start();
    //...

自己启动计时器ActionListener可能不是最好的主意。SwingTimer会自动重复。

下一个...

public void paint(Graphics g) {
    if (moves == 0) {
    //...
    g.dispose();
}

是一袋坏主意。

首先,作为一般建议,您应该避免覆盖paint. 相反,您应该专注于覆盖paintComponent.

您还应该调用该paint方法的super, 来维护绘制链。

您永远不应该处理Graphics不是您自己创建的上下文,它可能会对需要在组件之后绘制的其他内容产生不利影响。

相反,更像...

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (moves == 0) {
    //...
}

下一个...

我什至放弃了讨论KeyListener-相反,您应该使用如何使用键绑定

下一个...

你永远不会释放任何关键状态,这将是非常有问题的,并且头部的方向实际上应该与关键状态和绘制过程分开管理

建议...

使用不同的数据结构来管理你的蛇。如果您只需要线性访问(或者如果您需要随机访问),LinkedList就会找到类似 a 的东西。ArrayList关键是,您可以轻松地在 的“头部”插入一个新元素,而不List必将所有旧元素“复制”到一个地方。

我会再创造两个元素。一种管理元素的“类型”,一种管理元素的位置。

public enum SnakePartType {
    LEFT_HEAD, RIGHT_HEAD, DOWN_HEAD, UP_HEAD, BODY
}

public class SnakePart {
    private SnakePartType type;
    private Point location; // You could use separate x/y properties, but Point already does it

    public SnakePart(SnakePartType type, Point location) {
        this.type = type;
        this.location = location;
    }

    // Getters for type and location
}

这样,您的paint流程不需要知道关键状态,它会在绘制过程之间发生变化,并且可以依赖模型中的信息


推荐阅读