今天详细讲解写贪吃蛇的遇到的问题
代码:
Main类
GrameStart类
GamePanel类
启动main方法
在写贪吃蛇的时候,我接触到了两个新东西:
1.定时器Timer类。
2.paint()绘图方法。第一次出现在java.awt.Component类中,当我们的类继承JFrame(容器)或者JPanel(轻量级容器)时,我们可以通过重写paint()方法,去进行绘图。
关于paint()方法可以参考文章:https://blog.csdn.net/gydjsz/article/details/88924447
但是网上讲解的都比较简单,想系统学习还是要参考书籍《Java从入门到精通》。
通过paint()方法,我们解决了绘图问题,可以通过paint()方法,实现小蛇,以及小蛇移动区域、计分器的绘制。
首先,我们创建一个游戏界面。
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
这两行代码是为了获取系统屏幕分辨率,从而来调整窗口位置居中。
然后,我们用画笔填充两个矩形,分别表示游戏区域和小蛇运动的区域,以及计分器
这样,我们的游戏基本界面就设置完毕。
然后,进行对小蛇移动、游戏机制的实现.
那么,我们接下来的问题就是,如何表示小蛇的位置?如何实现小蛇的不间断移动?小蛇的转向?以及死亡判定,得分判定?
关于小蛇的位置,我们可以通过坐标来进行表示,并通过坐标的改变来改变小蛇的位置。
数组空间设置为500,这样小蛇的最大长度为500。
同时在游戏开始之前,我们要进行游戏的初始化操作。
游戏开始之前,小蛇有头部和两节身子,长度为3,以及初始位置.游戏开始状态为false,死亡状态为false,分数为0,初始方向为向右.
接下来,我们可以通过键盘监听,改变小蛇的移动方向,以及暂停、开始游戏。
我们GamePanel类里面添加一个键盘监听器,这里要注意的是,当一个类继承JPanel的时候,这个类就是一个面板,可以直接用this调用.
并通过匿名内部类的方式来实现KeyAdapter的接口,并重写Keypressed()方法,并通过多级if的形式,进行键盘操作判断.
当不是死亡状态的时候,按下空格会改变游戏状态为暂停或者开始,并赋值方向为\" \"(空格),至于为什么要让方向等于空格,后面会讲.
如果是死亡状态,那么调用初始化方法和游戏状态,并进行重绘.
W,S,A,D分别表示上下左右,对方向进行赋值.
这样,我们的键盘监听结束.
然后,我们迎来了第一个难点. 如何让小蛇向前移动?
我们是否要不断地改变小蛇头部以及每节身体地坐标去实现它地移动?但是我们不可能对小蛇所有身体进行方向判断并改变,这样显得繁杂很多.
于是,有了一个方案.我们是否可以只改变小蛇的头部的方向,让小蛇的头部去引导身体去移动?
以游戏状态为开始状态,并且小蛇存活为前提.
刚开始,我在想如何让蛇头一直向前跑,我直接在定时器里面的事件监听器里面,不通过if条件语句,写下这样一行代码:
snakeX[0]+=20;
这样,不就实现了小蛇一直在往前走吗?
结果,出现来搞笑的一幕,小蛇一旦转弯就会斜着走,当时我死活想不通,那天晚上,被窝里都是小蛇在斜着乱飞,哭死了.
后来,我发现了这个问题,我设定一直往右走, 所以一旦转弯,就会斜着跑.
我进行了改良,但由于时间问题,效果还并不是很满意.很多代码想法都是自己敲的,所以经常不尽如人意.
我是这样解决这个问题的:
只有当我们开始游戏的时候,我们会按下空格,这个时候方向direction就被赋值为空格.用if语言判断direction是否为空格,如果是空格说明游戏开始,小蛇可以开始向右移动了,如果direction不是空格,即进行了转向,并按照转向后的方向跑,那么我们的自动向右跑的条件就不会符合,也就不会自动向右跑了.
通过for循环,让蛇的后一节身体去继承上一节身体的坐标.
接下来,是我们的第二个难点.如何让小蛇不间断的移动,并且时刻监测到我们是否进行了转向、吃到食物、是否撞到自己死亡? 我们可以通过定时器和事件监听器的组合使用,实现对定时器内线程任务的不断检测,进而是实现小蛇的不间断移动以及各种判定. 我们要明确监听器和定时器它们各自的作用.
通过for循环进行绘制,记得把小蛇的头部换个颜色,看起来更棒!