Java Snake游戏:苹果在蛇不可见的情况下显示 [英] Java Snake Game: Apple showing while snake is invisible

查看:81
本文介绍了Java Snake游戏:苹果在蛇不可见的情况下显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在观看以下视频来设计蛇游戏: https://www.youtube.com/watch?v=91a7ceECNTc

I am following a the following video to design a snake game: https://www.youtube.com/watch?v=91a7ceECNTc

我正在逐步跟踪它,但是当我运行它时,蛇并没有显示在屏幕上,只有苹果.我认为在实现 public void paint(Graphics g); 时有人出问题吗?

I am following it step by step, but when I run it, the snake does not show on my screen, just the apple. I think I have something wrong when implementing public void paint(Graphics g); Can someone help me?

这是我的主班代码

import javax.swing.JFrame;
public class Main {

public static void main(String[] args) {
    JFrame frame = new JFrame ();
    GamePanel panel = new GamePanel();

    frame.add(panel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("Snake");

    frame.pack();
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
}
}

这是面板类:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable, KeyListener{

private static final long serialVersionUID = 1L;
public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)
private Thread thread;
private boolean running;
private boolean right = true, left = false, up = false, down = false;

private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;

private int xCoor = 100, yCoor = 100, size = 10;
private int ticks = 0;

public GamePanel() {
    setFocusable(true);
    setPreferredSize(new Dimension(WIDTH, HEIGHT));
    addKeyListener(this);
    snake = new ArrayList<BodyPart>();
    apples = new ArrayList<Apple>();
    r = new Random();
    start();

}
public void start() {
    running = true;
    thread = new Thread(this);
    thread.start();
}
public void stop() {
    running = false;
    try {
        thread.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
public void tick() {
    if (snake.size() == 0) {
        b = new BodyPart(xCoor, yCoor, 10);
        snake.add(b);
    }
    ticks++;
    if (ticks > 250000) {
        if (right) {
            xCoor++;
        }
        if (left) {
            xCoor--;
        }
        if (up) {
            yCoor--;
        }
        if (down) {
            yCoor++;
        }
        ticks = 0;
        b = new BodyPart(xCoor, yCoor, 10);
        snake.add(b);
        if (snake.size() > size) {
            snake.remove(0);
        }
    }
    if (apples.size() == 0) {
        int xCoor = r.nextInt(99);
        int yCoor = r.nextInt(99);
        apple = new Apple(xCoor, yCoor, 10);
        apples.add(apple);
    }
}
public void paint(Graphics g) {

    g.clearRect(0, 0, WIDTH, HEIGHT);
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, WIDTH, HEIGHT);

    for (int i = 0; i < WIDTH/10; i++) {
        g.drawLine(i*10, 0, i*10, HEIGHT);
    }
    for (int i = 0; i < HEIGHT/10; i++) {
        g.drawLine(0, i*10, HEIGHT, i*10);
    }
    for (int i = 0; i < snake.size(); i++) {
        snake.get(i).draw(g);
    }
    for (int i = 0; i < apples.size(); i++) {
        apples.get(i).draw(g);
    }
}

@Override
public void run() {
    while (running) {
        tick();
        repaint();
    }
}
@Override
public void keyTyped(KeyEvent e) {
    int key = e.getKeyCode();
    if (key == KeyEvent.VK_RIGHT && !left) {
        right = true;
        up = false;
        down = false;
    }
    if (key == KeyEvent.VK_LEFT && !right) {
        left = true;
        up = false;
        down = false;
    }
    if (key == KeyEvent.VK_UP && !down) {
        up = true;
        right = false;
        left = false;
    }
    if (key == KeyEvent.VK_DOWN && !up) {
        down = true;
        right = false;
        left = false;
    }

}
@Override
public void keyPressed(KeyEvent e) {
    // TODO Auto-generated method stub

}
@Override
public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub

}
}

蛇的身体部位类别:

import java.awt.Color;
import java.awt.Graphics;

public class BodyPart {
public int xCoor, yCoor, width, height;

public BodyPart(int xCoor, int yCoor, int tileSize) {
    this.xCoor = xCoor;
    this.yCoor = yCoor;
    width = tileSize;
    height = tileSize;
}
public void tick() {

}
public void draw(Graphics g) {
    g.setColor(Color.YELLOW);
    g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getCoorX() {
    return xCoor;
}
public void setCoorX (int xCoor) {
    this.xCoor = xCoor;
}
public int getCoorY() {
    return yCoor;
}
public void setCoorY(int yCoor) {
    this.yCoor = yCoor;
}
}

和苹果的班级:

import java.awt.Color;
import java.awt.Graphics;

public class Apple {
public int xCoor, yCoor, width, height;

public Apple(int xCoor, int yCoor, int tileSize) {
    this.xCoor = xCoor;
    this.yCoor = yCoor;
    width = tileSize;
    height = tileSize;
}
public void tick() {

}
public void draw(Graphics g) {
    g.setColor(Color.RED);
    g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getxCoor() {
    return xCoor;
}
public void setxCoor(int xCoor) {
    this.xCoor = xCoor;
}
public int getyCoor() {
    return yCoor;
}
public void setyCoor(int yCoor) {
    this.yCoor = yCoor;
}

}

推荐答案

好的,所以问题出在一些基本数学上……

Okay, so the issue comes down to some basic maths...

如果我们查看 BodyPart draw 方法,您会发现...

If we take a look at the draw method for BodyPart you will find...

g.fillRect(xCoor * width, yCoor * height, width, height);

好的,很基本,但是实际上也设置了所有这些值吗?

Okay, pretty basic, but are all these values actually set too?

如果我们看一下 tick 方法(在其中创建 BodyPart s的方法),我们可以找到...

If we take a look at the tick method (where BodyParts are created), we can find...

b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);

好的,所以 width height 10 ,但是 xCoor yCoor呢??

Okay, so the width and height is 10, but what about xCoor and yCoor?

它们首先与类一起初始化为实例字段...

They're first initialised as instance fields along with the class...

private int xCoor = 100, yCoor = 100, size = 10;

因此,一小段数学告诉我们 BodyPart 的初始位置是 100 * 10 ,等于 1000x1000 .

So, a quick bit of maths tells us the initial location of the BodyPart is 100 * 10 which equals 1000x1000.

如果我们还看一下...

If we also take a look at ...

public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)

setPreferredSize(new Dimension(WIDTH, HEIGHT));

我们可以看到 BodyPart 实际上最初是在屏幕上设置的.

we can see that the BodyPart is actually been set off screen initially.

因此,如果我们将初始位置更改为类似...

So, if we change the initial position to something more like...

private int xCoor = 10, yCoor = 10, size = 10;

您会找到您失踪的蛇.

您应该避免覆盖 paint .它在油漆链中很高,很容易将其拧紧.相反,请改用 paintComponent (并确保您正在调用 super.paintComponent ).然后, JPanel 将为您清除 Graphics 上下文(具有组件的背景色).

You should avoid overriding paint. It's to high in the paint chain and it's to easy to screw it up. Instead, prefer paintComponent instead (and make sure you're calling super.paintComponent). JPanel will then clear the Graphics context for you (with the background color of the component).

Swing不是线程安全的.不应从事件调度线程的上下文外部修改UI或UI依赖的任何状态.

Swing is not thread safe. You should not be modify the UI or any state the UI relies on from outside the context of the Event Dispatching Thread.

当前的主"循环存在引入脏更新的危险,该更新可能导致以后出现问题.请参见 Swing中的并发.作为一般"偏好,您应该考虑使用摆动计时器 .它不会阻止EDT,但会在EDT内部生成滴答声",从而更安全地从内部更新UI和/或其状态.

The current "main" loop is in danger of introducing dirty updates which could cause issues later. See Concurrency in Swing. As a "general" preference, you should consider using a Swing Timer instead. It won't block the EDT, but's "ticks" are generated inside the EDT, making it safer to update the UI and/or its state from within.

执行操作时应避免使用幻数" ...

You should avoid using "magic numbers" when performing your operations...

for (int i = 0; i < WIDTH/10; i++) {
    g.drawLine(i*10, 0, i*10, HEIGHT);
}

此处, WIDTH HEIGHT 可能不表示该组件的实际尺寸.而是使用 JPanel#getWidth JPanel#getHeight .

Here, WIDTH and HEIGHT may not represent that actual size of the component. Instead make use of JPanel#getWidth and JPanel#getHeight instead.

作为一般建议,您应该避免使用 setPreferred/Minimum/MaximumSize ,其他人很容易将其更改为不需要的状态.而是改写 getPreferred/Minimum/MaximumSize ,这样您就可以保持控制.

As a general recommendation, you should avoid using setPreferred/Minimum/MaximumSize, it's to easy for someone else to change these to a state you don't want. Instead, override getPreferred/Minimum/MaximumSize instead, this way you maintain control.

这篇关于Java Snake游戏:苹果在蛇不可见的情况下显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆