达芬奇大王的链表贪吃蛇(java)

*看了GUI,虽然java的GUI被淘汰了,我还是做了一个贪吃蛇练习下链表和逻辑思路,重点是面向对象的知识点。
思路:
三个对象,地图(背景),蛇,果实
三个事件,蛇碰壁,碰自身,吃到果实
一个线程,间隔固定的时间移动蛇身并刷新界面

先上效果图
游戏开始:
游戏开始
撞墙:
撞墙
撞自身:
撞自身

/**
 * 盒子类
 * 构成蛇的基本单位
 * */
public class Box {
	private int x;  //横坐标
	private int y;    //纵坐标   从上往下变大
	private Box up; //上一个box
	private Box down; //下一个box
	public Box() {	
	}
	public Box(int x,int y) {
		this.x = x;
		this.y = y;
	}
	...
}

这个box类,主要记录的是一个坐标,并没有继承GUI里的组件,只要获得坐标,再给组件上色就行了。

/**
 * 蛇类
 * */
public class Snake {
	private Box first;  //蛇头
	private Box last;  //蛇尾
	private int len;  //蛇长度
	private int direction; // 方向 0up 1down 2right 3left
	public Snake(Box b) {
		init(b);
	}
	private void init(Box b) {				
		this.first = b;
		this.last = b;
		this.len = 1;
		direction = (int)(Math.random()*4); //随机一个方向
	}
	....
}
//向上移动
	public void up() {
		Box newFirst = new Box(first.getX(),first.getY()-1);
		newSnake(newFirst);		
	}
	private void newSnake(Box newFirst) {
		newFirst.setDown(first);
		first.setUp(newFirst);
		this.first = newFirst;
		Box newLast = last.getUp();
		newLast.setDown(null);
		last.setUp(null);
		this.last = newLast;
	}
//吃食物方法
	public void eatBox(Box box) {	
		first.setUp(box);
		box.setDown(first);
		this.first = box;
		len+=1;
	}

蛇类,移动的思路是,在移动方向前面加上一个Box对象,再去掉尾部的last,就实现了移动,而不用把整条蛇的每个box都移动。吃食物也很简单,把食物加在头first的上一个box,然后食物作为新头。这个思路来自集合容器LinkedList。
因为蛇是固定间隔时间移动的,按键上下左右只是改变方向,所以这里设置了一个方向direction属性。

public class SnakeFrame extends JFrame{
	private Snake snake;   //蛇
	private Box food;  //食物
	private boolean haveFood = false;  //食物是否存在
	private JPanel panel;
	private JTextField[][] texts;
	public SnakeFrame() {
		initFrame();  // 初始化Frame
		initComponent();	// 初始化组件
		initComponentData();  // 初始化组件数据
		addComponent();    // 添加组件
		this.setVisible(true);    //frame可见
		new SnakeThread().start();   // 线程start
	}

背景类,有个haveFood属性,根据这个属性知道当前页面有没有食物food存在,没有再生成一个食物。
格子我用的文本框JTextField,创建20x20个文本框并用网格布局,根据蛇每个box和食物的坐标再给对应的JTextField上色。

//给蛇和食物上色
				//给蛇和食物上色
				for(int j = 0;j < 20;j++) {  //纵坐标
					for(int k = 0;k < 20;k++) { //横坐标
						//蛇上色
						boolean flag = true;
						Box temp = snake.getFirst();
						for(int i = 0;i < snake.getLen();i++) {
							if(j == temp.getY() && k == temp.getX()) {
								texts[temp.getY()][temp.getX()].setBackground(Color.BLACK);
								flag = false;
								break;
							}
							if(temp.getDown() != null) {
								temp = temp.getDown();
							}
						}
						//食物上色
						if(flag) {
							if(k == food.getX() && j == food.getY()) {
								texts[j][k].setBackground(Color.BLUE);
							}else {
								texts[j][k].setBackground(Color.WHITE);
							}

						}	
					}					
				}

在线程里每次遍历所有坐标,如果是当前坐标是蛇的身体的坐标,便给对应的文本框texts[][]上黑色,根据食物坐标给对应texts[][]上蓝色,其他上白色。

	//不断移动
				if(snake.getDirection() == 0) { //方向向上
					if(snake.getFirst().getX() == food.getX() && snake.getFirst().getY()-1 == food.getY()) {
						snake.eatBox(food);   //上方有食物 吃食物
						SnakeFrame.this.haveFood = false; 
					}else {
						snake.up();    //没有直接向上移动
					}
				}
this.addKeyListener(new KeyAdapter() {	
			@Override
			public void keyPressed(KeyEvent e) {
				if(e.getKeyCode() == KeyEvent.VK_UP) {   // 当按下的是向上键
					if(snake.getDirection() != 1) {  //如果方向不是向下,就把方向调整为向上
						snake.setDirection(0);
					}		
				}
				...
}

给自定义背景Frame添加按键监听并集中在frame上,当按上,如果当时方向是朝下就不能改变方向,就是不能掉头。
不断移动和食物刷新都在刷新页面的线程里,按键监听只是改变方向。
撞墙和撞自身添加在线程里,不断移动之后,撞墙我的判断方法是蛇头的坐标超出范围,撞自身是遍历蛇所有box的坐标,如果和蛇头坐标相同就是撞上了,便把蛇头上红色。

源码连接
https://pan.baidu.com/s/1eUO3LWZ9G7DIBQ95i-DuCw 提取码: 4d6n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值