忽然想写个贪吃蛇小游戏。
实现起来很简单,用队列保存小蛇的身体坐标。在位置坐标中小蛇头部的下一步位置激活,尾部位置取消激活实现小蛇移动,实现捕食效果则尾部不取消激活小蛇长度增加。
import java.util.Scanner;
public class SnakeTest {
private Scanner sc;
private int r;// 随机数值
private int d;// 输入的数字
private int[][] dir = { { 1, 0 }, { 0, -1 }, { -1, 0 }, { 0, 1 } };// 方向数组,下,左,上,右
private final int width = 5;// 宽
private final int height = 5;// 高
private int[][] pos;// 位置数组
private int head_x, head_y;// 头部坐标
private int snake_length = 2;// 初始场长度
private int cur_dir;// 当前方向
private int food_x, food_y;// 食物坐标
MyLink link;// 队列对象
public static void main(String[] args) {
System.out.println("【贪吃蛇】");
SnakeTest st = new SnakeTest();
st.initGame();
st.runGame();
}
private void initGame() {
sc = new Scanner(System.in);// 实例化输入类
// 随机初始化起源点及方向
r = (int) (Math.random() * (width * height));
head_x = r % width;
head_y = r / width;
cur_dir = (int) (Math.random() * 4);
// 初始化坐标数组以及实例化自定义的队列类
pos = new int[width][height];
link = new MyLink(width, height);
// 将第一个坐标放进队列并激活位置坐标
link.in(head_y, head_x);
pos[head_y][head_x] = 1;
// 根据起源坐标直线延伸至设定长度,因此最大长度为width或height
for (int i = 1; i < snake_length; i++) {
head_x += dir[cur_dir][1];
head_y += dir[cur_dir][0];
// 检查并处理数组以及游戏边界
check();
link.in(head_y, head_x);
pos[head_y][head_x] = 1;// 激活
}
// 初始化食物坐标
randomFood();
}
private void runGame() {
while (true) {
draw();// 打印在控制台
d = sc.nextInt();
// 0 1 2 3 下 上 右 左
control(d);
head_x += dir[cur_dir][1];
head_y += dir[cur_dir][0];
// 检查并处理数组以及游戏边界
check();
// 如果咬到自己游戏失败
if (pos[head_y][head_x] == 8) {// 吃到东西 长度+1
snake_length++;
link.in(head_y, head_x);// 把头部坐标塞进队列
pos[head_y][head_x] = 1;// 将头部坐标激活
// 是否大满贯
if (snake_length == width * height) {
draw();
System.out.println("胜利!");
return;
}
randomFood();// 随机生成食物坐标
} else {// 否则队列操作,实现小蛇移动
int[] tail = link.out();// 队列将尾部坐标移除;
pos[tail[0]][tail[1]] = 0;// 取消激活尾部坐标
if (pos[head_y][head_x] == 1) {
System.out.println("咬到自己啦!\n小蛇长度:"+snake_length);
return;
}
link.in(head_y, head_x);// 把头部坐标塞进队列
pos[head_y][head_x] = 1;// 将头部坐标激活
}
}
}
private void control(int d) {
if (cur_dir != 2 && d == 0)// 当前方向不允许为向上情况允许向下转弯,下同
cur_dir = 0;
else if (cur_dir != 3 && d == 1)
cur_dir = 1;
else if (cur_dir != 0 && d == 2)
cur_dir = 2;
else if (cur_dir != 1 && d == 3)
cur_dir = 3;
}
private void check() {
if (head_x < 0)
head_x = width - 1;
else if (head_x == width)
head_x = 0;
if (head_y < 0)
head_y = height - 1;
else if (head_y == height)
head_y = 0;
}
private void draw() {
System.out.println("数字: [0]下,[1]左,[2]上,[3]右");
System.out.printf("头部坐标:第%d行,第%d列\n", head_y + 1, head_x + 1);
System.out.print("当前方向为:");
switch (cur_dir) {
case 0:
System.out.println("下");
break;
case 1:
System.out.println("左");
break;
case 2:
System.out.println("上");
break;
case 3:
System.out.println("右");
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
System.out.printf("%-2s", pos[i][j]);
}
System.out.println();
}
}
private void randomFood() {
while (pos[food_y][food_x] != 0) {
r = (int) (Math.random() * (width * height));
food_y = r / width;
food_x = r % width;
}
pos[food_y][food_x] = 8;
}
}
class MyLink {
private int[][] link;
private int head_index;
private int tail_index;
public MyLink(int x, int y) {
link = new int[x * y][2];
}
public void in(int x, int y) {
link[head_index][0] = x;
link[head_index][1] = y;
head_index++;
head_index %= link.length;
}
public int[] out() {
int[] index = { link[tail_index][0], link[tail_index][1] };
tail_index++;
tail_index %= link.length;
return index;
}
}