【Java代码】贪吃蛇小游戏
少玩游戏,玩物丧志
先贴上最终的成品图↓
一、文件结构
下面来看看文件结构:greedysnake包下有四个类以及一些用到的图片(四个方向的蛇头,蛇身,banner,食物)。
本项目共创建了四个类:Food用于设置食物的随机产生、Snake用于实现蛇头蛇身的初始化以及对蛇是否吃到食物、是否撞到墙和是否撞到自己的判断、SnakePanel用于绘制图形界面、SnakeFrame为总体框架,可在其中添加监听或面板等。
可以依照以下流程完善游戏功能:编写界面面板→添加静态的蛇(蛇头和蛇身)→添加随机产生的食物→让蛇动起来→添加键盘监听让蛇可以根据按键值进行转向→让蛇可以吃食物并变长→设置规则:当蛇碰到自己身体或边界时结束游戏→添加按空格暂停或开始的功能→显示暂停/开始和游戏结束的提示文字→完成随着蛇身变长加快速度的功能→添加分数的显示。
二、实现功能的要点
①如何随机产生食物
while(flag) {
flag=false;
x=(int) (Math.random()*34);//850(界面宽度)//25(以25像素为一个单位)=34
y=(int) (Math.random()*21)+3;//
if(x==snake.head.x&&y==snake.head.y) {//判断食物是否和蛇的头重合
flag=true;
}
for(Point p:snake.body) {//判断食物是否和蛇的身体重合
if(x==p.x&&y==p.y) {
flag=true;
}
}
}
②如何构造蛇
public Snake(Point head) {//构造方法
this.head=head;
dir=4;
length=5;
size=25;
body=new ArrayList<Point>();
for(int i=0;i<length-1;i++) {//length是蛇的总长度,-1就是身体的长度
Point p=new Point(head.x,head.y+1+i);//+1表示第一个身体的位置,+i即下移i个单位,最后乘上size就能扩大
body.add(p);
}
}
③如何让蛇动起来
首先保存蛇头位置,接着对行进方向进行判断,并将头的坐标进行改变,然后在原先蛇头的位置添加一个身体,最后再去掉尾部的一个身体,即可模拟蛇的运动。
public void startMove() {
if(isStart&&!isFaild) {
Point oxy=new Point(snake.head);//将当前头所在的位置坐标赋给oxy保存
//下面对行进方向进行判断,并将头的坐标进行改变
if(snake.dir==1) {
imgName="up.png";
snake.head.y--;
}
if(snake.dir==2) {
imgName="down.png";
snake.head.y++;
}
if(snake.dir==3) {
imgName="left.png";
snake.head.x--;
}
if(snake.dir==4){
imgName="right.png";
snake.head.x++;
}
snake.body.add(0, oxy);//在原先蛇头的位置处添加一个身体(0是存放身体数组的下标,oxy是原先蛇头的坐标)
...
else { snake.body.remove(snake.length-1);}//没吃到食物则去掉尾部的身体,保持身体总长不变
...
}
}
④如何实现蛇的转向
实现接口KeyListener,利用其方法keyPressed(KeyEvent e),在其中对按键值进行判断,根据不同的按键值,给 dir变量赋对应方向值,以改变蛇头运动方向。
@Override
public void keyPressed(KeyEvent e) {// dir设置方向,1向上,2向下,3向左,4向右
// TODO 自动生成的方法存根
int key=e.getKeyCode();
if(key==KeyEvent.VK_UP&&snake.dir!=2)
snake.dir=1;
if(key==KeyEvent.VK_DOWN&&snake.dir!=1)
snake.dir=2;
if(key==KeyEvent.VK_LEFT&&snake.dir!=4)
snake.dir=3;
if(key==KeyEvent.VK_RIGHT&&snake.dir!=3)
snake.dir=4;
if(key==KeyEvent.VK_SPACE&&!isFaild) {
if(isStart) {
isStart=false;
}else isStart=true;
}
}
⑤如何让蛇吃食物并变长
设置一个返回值为布尔类型的方法isEat(),若蛇头的坐标和食物坐标相同则返回True,并令蛇在移动过程中不去掉尾部的身体,由此即可模拟吃到食物变长。
public boolean isEat(Food food) {//判断是否吃到食物
if(head.x==food.x&&head.y==food.y) {
return true;
}
else {return false;}
}
public void startMove() {
...
if(snake.isEat(food)) {//吃到食物则为true,让身体加长(即不去掉尾部的身体)
snake.length++;
flag++;
score+=100;
food=new Food(snake);//随机产生的新的食物位置
…}
⑥如何判断是否撞到自己或撞到墙
循环判断比较头部的坐标是否和每个身体坐标相同,若有相同则撞到自己;若蛇头范围超出界面范围,则可说明撞到墙。
public boolean isOut() {//判断是否碰撞边界
if(head.x<0||head.x>33||head.y<3||head.y>23) {
return true;
}else {return false;}
}
public boolean isPitch() {//判断是否撞到自己
for(Point p:body) {
if(head.x==p.x&&head.y==p.y) {
return true;
}
}
return false;
}
public void startMove() {
...
if(snake.isOut()) {//如果碰到边界,则令isFaild标志变为true,让游戏结束
isFaild=true;
}
if(snake.isPitch()) {//如果碰到自己的身体,则令isFaild标志变为true,让游戏结束
isFaild=true;
}
}
⑦如何实现暂停和开始
同样在keyPressed(KeyEvent e)方法中实现,若得到的按键值为空格键且游戏没结束,当目前状态为运行时,则让isStart标志变为false暂停;当目前状态为暂停时,则让isStart标志变为true运行。
if(!isStart) {//当游戏没开始或暂停时,显示“Press space to start/pause”
g.setColor(Color.white);
g.setFont(new Font("方正小标宋简体",Font.BOLD,28));
g.drawString("Press space to start/pause", 250, 350);
}
if(isFaild) {//游戏结束时,显示“Game Over”
g.setColor(Color.white);
g.setFont(new Font("方正小标宋简体",Font.BOLD,28));
g.drawString("Game Over!",350, 350);
}
⑧加速&分数
@Override
public void run() {
while(true) {
startMove();
try {
Thread.sleep(speed);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
public void startMove() {
...
if(flag==4&&speed>50) {//每吃到四个食物让蛇移动速度变快,当移动时间间隔减为50毫秒时不再加快
speed-=25;
flag=0;
}
...
}
g.setColor(Color.white);
g.setFont(new Font("方正小标宋简体",Font.BOLD,20));
g.drawString("Score:"+score, 700,40 );
代码文件已经上传,戳这里下载源码