贪吃蛇java实现
图形界面在搜索引擎搜了许久…看上去依然一脸懵逼,完全不知道该如何修改,无奈只好跑到某站看了一下swing相关的知识,有了大概的了解,再参考搜到的,修改成了如下的样子,还有一些问题没有解决
比如:我限制了键盘操作的间隔时间 200ms,因为我发现当蛇移动的过慢,而操作转向过快时,就会出现逆行的bug; 比如当前正在向上走,我可以在蛇一次移动中,先操作向左,然后向下,出现逆向行走的 错误逻辑;但是限制了操作时间,又会影响到体验,暂时没有想出很好的解决方案
package snake_game;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;
import java.util.Objects;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SnakeGame extends JPanel implements KeyListener {
public static int moveSpeed = 200;
int runTime = 200;
public static void main(String[] args) throws InterruptedException {
while (true) {
run();
jd.repaint();
Thread.sleep(300);
}
}
public static final int SIZE = 30;
public static final int HANG = 15;
public static final int LIE = 20;
public static boolean[][] map = new boolean[HANG][LIE];
private static LinkedList<Point> snake = Snake.snake;
private static boolean isGameOver = false;
public static void updateIsGameOver() {
isGameOver = true;
}
public static boolean getIsGameOver() {
return isGameOver;
}
static {
for (int i = 0; i < map.length; i++) {
map[i][0] = true;
map[i][map[0].length - 1] = true;
for (int j = 0; j < map[0].length; j++) {
if (i == 0) {
map[0][j] = true;
}
if (i == map.length - 1) {
map[map.length - 1][j] = true;
}
}
}
}
public static void initMap() {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = false;
}
}
for (int i = 0; i < map.length; i++) {
map[i][0] = true;
map[i][map[0].length - 1] = true;
for (int j = 0; j < map[0].length; j++) {
if (i == 0) {
map[0][j] = true;
}
if (i == map.length - 1) {
map[map.length - 1][j] = true;
}
}
}
}
static SnakeGame jd;
static {
JFrame jf = new JFrame("贪吃蛇");
jf.setBounds(300, 300, SIZE * LIE + 5, SIZE * HANG + 25);
jd = new SnakeGame();
jf.add(jd);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setResizable(false);
jf.addKeyListener(jd);
jf.setVisible(true);
}
@Override
public void paint(Graphics g) {
for (int i = 0; i < LIE; i++) {
for (int j = 0; j < HANG; j++) {
if (map[j][i]) {
g.setColor(Color.DARK_GRAY);
} else {
g.setColor(Color.GRAY);
}
g.fill3DRect(i * SIZE, j * SIZE, SIZE, SIZE, true);
}
}
g.setColor(Color.BLUE);
for (int i = 1; i < snake.size(); i++) {
g.fill3DRect(snake.get(i).y * SIZE, snake.get(i).x * SIZE, SIZE, SIZE, true);
}
g.setColor(Color.CYAN);
g.fill3DRect(snake.getFirst().y * SIZE, snake.getFirst().x * SIZE, SIZE, SIZE, true);
g.setColor(Color.black);
g.fill3DRect(Food.food.y * SIZE, Food.food.x * SIZE, SIZE, SIZE, true);
if (isGameOver) {
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, 45));
g.drawString("Game Over", (SIZE * LIE >> 1) - 100, (SIZE * HANG >> 1));
g.setFont(new Font("宋体", Font.BOLD, 35));
g.drawString("回车键重新开始", ((SIZE * LIE >> 1) - 20) - 100, ((SIZE * HANG >> 1)) + 45);
}
}
public static void run() throws InterruptedException {
for (;;) {
Thread.sleep(moveSpeed);
if (Snake.move()) {
return;
}
jd.repaint();
}
}
long time = System.currentTimeMillis();
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (System.currentTimeMillis() - time > runTime && Snake.updateDirection(-1)) {
time = System.currentTimeMillis();
}
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
if (System.currentTimeMillis() - time > runTime && Snake.updateDirection(1)) {
time = System.currentTimeMillis();
}
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
if (System.currentTimeMillis() - time > runTime && Snake.updateDirection(2)) {
time = System.currentTimeMillis();
}
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
if (System.currentTimeMillis() - time > runTime && Snake.updateDirection(-2)) {
time = System.currentTimeMillis();
}
} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (isGameOver == true) {
Snake.initSnake();
initMap();
isGameOver = false;
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
class Snake {
public static LinkedList<Point> snake = new LinkedList<>();
public volatile static int toward;
private static boolean map[][] = SnakeGame.map;
private static int hang = SnakeGame.HANG;
private static int lie = SnakeGame.LIE;
static {
snake.add(new Point(hang >> 1, (lie >> 1) - 2));
snake.add(new Point(hang >> 1, (lie >> 1) - 3));
snake.add(new Point(hang >> 1, (lie >> 1) - 4));
for (int i = 1; i < snake.size(); i++) {
Point p = snake.get(i);
map[p.x][p.y] = true;
}
toward = 2;
Food.generateFood(snake.getFirst());
}
public static void initSnake() {
for (;;) {
snake.remove();
if (snake.isEmpty()) {
break;
}
}
snake.add(new Point(hang >> 1, (lie >> 1) - 2));
snake.add(new Point(hang >> 1, (lie >> 1) - 3));
snake.add(new Point(hang >> 1, (lie >> 1) - 4));
for (int i = 1; i < snake.size(); i++) {
Point p = snake.get(i);
map[p.x][p.y] = true;
}
toward = 2;
Food.generateFood(snake.getFirst());
}
public static boolean move() {
if (SnakeGame.getIsGameOver()) {
return true;
}
if (toward == -2) {
snake.addFirst(new Point(snake.getFirst().x, snake.getFirst().y - 1));
} else if (toward == -1) {
snake.addFirst(new Point(snake.getFirst().x + 1, snake.getFirst().y));
} else if (toward == 2) {
snake.addFirst(new Point(snake.getFirst().x, snake.getFirst().y + 1));
} else if (toward == 1) {
snake.addFirst(new Point(snake.getFirst().x - 1, snake.getFirst().y));
}
Point p = snake.get(1);
map[p.x][p.y] = true;
int x = snake.getFirst().x;
int y = snake.getFirst().y;
if (map[x][y]) {
SnakeGame.updateIsGameOver();
return true;
}
if (Food.eatFood(snake.getFirst())) {
Food.generateFood(snake.getFirst());
} else {
Point removeLast = snake.removeLast();
map[removeLast.x][removeLast.y] = false;
}
return false;
}
public static boolean updateDirection(int dir) {
if (toward + dir != 0) {
toward = dir;
return true;
}
return false;
}
}
class Food {
public static Point food;
private static boolean map[][] = SnakeGame.map;
public static void generateFood(Point p) {
while (true) {
int x = (int) (Math.random() * (map.length - 2)) + 1;
int y = (int) (Math.random() * (map[0].length - 2)) + 1;
if (map[x][y] != true) {
food = new Point(x, y);
if (Objects.equals(food, p)) {
continue;
}
return;
}
}
}
public static boolean eatFood(Point p) {
if (Objects.equals(food, p)) {
return true;
}
return false;
}
}