贪吃蛇
学习了半年的算法,多少有点凌乱了,所以最近痴迷于java做一些小的项目,做一些小的项目,这种节奏还是很舒服的
本次文章是我看麦叔编程学习的贪吃蛇,代码很简洁,本文也是基础篇,可能会有点啰嗦,如果基础稍微好一点的可以直接去文章最后拿源码看,也有详细的注释,一共也就二百来行代码,我会一步一步往下走,每一步的运行截图也会放上,在文章的中间也会放一次当前的源码给予对照,文章最后也会把完整的代码放上
做好以后就是这样,然后开始吧
首先在IDEA上创建一个java项目,我是用的IDEA,eclipse也一样,都是工具,按照自己的工具来就行,还有就是我的用的JDK16版本,因为我胆子比较大(其实是我懵懂无知),大家最好还是用JDK1.8
起名Msnake,因为我们要用的图形界面,这里选择的是JFrame
,然后导入import javax.swing.*;
这个包,然后创建一些我们窗口最基本的信息,都写在代码注释里了
import javax.swing.*;
public class Msnake {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setBounds(10,10,900,720);
//设置窗口左上角x,y的坐标,和长、宽
jFrame.setResizable(false);
//设置窗口大小不可拖动改变
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口的关闭,如果括号里什么都不写,那么点关闭只会隐藏窗口
jFrame.setTitle("贪吃蛇");
//设置我们窗口的名称,也可以说是标题
jFrame.setVisible(true);
//设置窗口显,让我们的窗口展现出来
}
}
运行一下应该是这种情况,当然,自己改数据也是可以的,最好先按照我的弄一边,再自己拓展
窗口创建完了,我们给窗口加一下东西,新建一个类Mpanel,用来存放我们给窗口加的东西
import javax.swing.*;//现在需要用的包,后面还会慢慢加
import java.awt.*;
public class Mpanel extends JPanel {//继承于Jpanel,Jpanel是比较常用的swing中的一个容器
public void paintComponent(Graphics g){//创建一个画布类,Graphics可以相当于一个画笔对象
super.paintComponent(g);
//可以认为是一个重绘,后面我们会用到repaint()方法来调用paintComponent来绘图,每次先用画笔重新绘一次窗口,我是这么理解的
this.setBackground(Color.WHITE);//设置背景为WHITE(白色)
g.fillRect(25, 75, 850, 600);//用画笔填满一个方格,左上角x、y坐标和长、宽
}
}
为了让我们的这些东西展示到窗口上,我们需要在主类里面加上
jFrame.add(new Mpanel());
然后运行就是这样
接下来我们来放一些到我们的项目目录下去,后面游戏的图片都是我一个个放上去的
百度网盘: https://pan.baidu.com/s/1EFrLU0MWUwoUdxSCEEl1dQ
提取码:0309
这里面有需要用到的所有图片
下面我都用截图放代码,也更直观一点
大家按照自己图片下载放的地址先在我们的类中加载进来,这里用的是ImageIcon来加载图片
首先我们先用到我们的标题和蛇放到画布上
这里用到paintIcon方法,把下面这些写入paintComponent类中
参数可以理解成用我们的画笔,在我们的画布上画这个对象,后面两个参数图片左上角x、y的坐标
这样我们一个静态的界面和蛇就做好了
接下来我们要放一串字符串在画布上告诉别人按下空格启动,用我们的画笔画
g.drawString("Press Space to Start", 250, 400);
这个方法也很好理解,不过我们直接加进去运行的话,应该是看不到字符串的,并不是我们写错了,而是我们的画笔画出来的是黑色的,我们的画布也是黑色的,理解了吧
g.setColor(Color.WHITE);//设置画笔颜色为白色
这也太小了,我们再设置一下字体,直接看图吧,上面都有注释
既然说按下空格要开始,那按下空格要有反应,我们先设置一下按下空格,让这一串字符串消失,再次按下,再出现
先构造一个无参的Mpanel方法
写完以后应该就报错了,因为我们要用的这两个方法,在另一个接口处,我们没指出来,他不乐意了
我们只需要implement一个KeyListener,然后带入一下包
import java.awt.event.KeyEvent;//要导的包
import java.awt.event.KeyListener;
这个时候他又不乐意了,因为我们时候我们要响应键盘,但是我们却没有响应键盘的方法,将鼠标放上去看一下提示,我用的IDEA可以直接创造子类,eclipse也是有的
直接创建就可以了
系统生成三个方法,注释我已经写上去了,我们随便选一个进行编写就行,我们选按中键盘时的吧
先定义一个Boolean
变量isStarted==false
表示我们还没下去键盘
字符串这里自然而然就是这样的
然后填一下KeyPressed,注释都是代码里了
运行一下应该就是按下空格字符串消失,再按,就出来,再按就消失,自己演示一下,如果有问题再看一下是不是哪一步出错了
接下来我们要让蛇动起来了,蛇肯定是会不断变长的,我们如果一个一个body给写出来,那肯定不行
我们换成循环来写
先定义一个变量lenSnake为蛇的初始长度,和两个数组来记录每一节身体的x、y
写一个方法初始化一下我们的数据
实现一下
调用我们的数组来初始化蛇
做到这里其实运行一下和刚刚是没有区别的,但是我们代码从死板的一个一个打印蛇,换成的循环来打印,对我们后面的进展有很大帮助
为了实现我们动态的蛇,定义一个Timer变量,用来当时钟
同时他也需要一个接口和包
这里加一下,其实还要加一个包import java.awt.event.ActionEvent;
图片上没有显示
这里又报错了,原因应该很清楚了,既然说要运行本项目指定的方法,那么方法呢?所以我们创建一个
得到一个actionPerformed方法,所以我们时钟过100毫秒后就会执行它,那我们让蛇动起来
根据规律我们知道,蛇的每一节身体每次会移动到下一节身体上,最开始的身体,移动到头的位置,头向前一个位置
首先启动时钟
然后在我们的actionPerformed方法这样实现因为在我们的蛇头或者蛇的身体都是25 * 25的图片,所以每次加25
现在蛇应该动起来了吧,我下面放一下写到这里该有的代码,如果有问题,对照一下我的代码
//Msnake类
import javax.swing.*;
public class Msnake {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setBounds(10,10,900,720);
jFrame.setResizable(false);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setTitle("贪吃蛇");
jFrame.add(new Mpanel());
jFrame.setVisible(true);
}
}
//Mpanel类
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Mpanel extends JPanel implements KeyListener, ActionListener {
//先加载图片
ImageIcon title = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/title.jpg");
ImageIcon body = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/body.png");
ImageIcon up = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/up.png");
ImageIcon down = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/down.png");
ImageIcon left = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/left.png");
ImageIcon right = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/right.png");
ImageIcon food = new ImageIcon("E:/JAVA01/idea_project/Msnakex/src/resources/picture/food.png");
boolean isStarted = false;//按下空格的标志
int lenSnake = 3;//蛇的长度
int[] snakex = new int[800];//x坐标
int[] snakey = new int[800];//y坐标
Timer timer = new Timer(100, this);//100毫秒后运行本项目指定的方法
public Mpanel() {
this.setFocusable(true);//允许响应
this.addKeyListener(this);//添加一个KeyListener用来响应我们的键盘
timer.start();//启动时钟
initSnake();//初始化
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
//可以认为是一个重绘,后面我们会用到pain()方法来调用paintComponent来绘图,每次先用画笔重新绘一次窗口,我是这么理解的
this.setBackground(Color.WHITE);
g.fillRect(25, 75, 850, 600);
title.paintIcon(this, g, 25, 11);//可以理解成用我们的画笔,在我们的画布上画这个对象,后面两个参数图片左上角x、y的坐标
// body.paintIcon(this, g, 75, 100);
// body.paintIcon(this, g, 50, 100);
right.paintIcon(this, g, snakex[0], snakey[0]);//蛇头
for (int i = lenSnake - 1; i >= 1; i--) {//蛇身
body.paintIcon(this, g, snakex[i], snakey[i]);
}
if (!isStarted) {
g.setColor(Color.WHITE);//画笔为白色
g.setFont(new Font("arial", Font.BOLD, 40));//设置字体类型、加粗、字体大小
g.drawString("Press Space to Start", 250, 400);//画一串字符串出来
}
}
public void initSnake() {//初始化
lenSnake = 3;
snakex[0] = 100;
snakey[0] = 100;
snakex[1] = 75;
snakey[1] = 100;
snakex[2] = 50;
snakey[2] = 100;
}
@Override
public void keyTyped(KeyEvent e) {//按下键盘时
}
@Override
public void keyPressed(KeyEvent e) {//按中键盘时
int keyCode = e.getKeyCode();//读取按下的键位
if (keyCode == KeyEvent.VK_SPACE) {
//如果键位等于KeyEvent.VK_SPACE(空格的意思),我就翻转isStarted
// 并且repaint()重新画图,也就是说重新调用paintComponent
isStarted = !isStarted;
repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {//抬起键盘时
}
@Override
public void actionPerformed(ActionEvent e) {
for (int i = lenSnake - 1; i >= 1; i--) {//每个身体位置等于前一个的位置
snakex[i] = snakex[i - 1];
snakey[i] = snakey[i - 1];
}
snakex[0] += 25;//蛇头前进一格
repaint();//重新画图
timer.start();//再次启动
}
}
写到这里蛇应该已经动起来了,并且按下空格可以控制字符串的出现和消失,我也困了,先睡觉了,晚上下课继续补,(如果有人看的话)
继续继续
我们发现蛇竟然可以直接跑出界面,那我们要想办法让他不出界,或者一旦出界,立马初始化,相当于一个穿墙的过程,我们只需要加上这么一句话就可以了
现在我们的蛇还只会向右跑,定义一下方向吧
所以接下来我们画蛇头的时候就要根据fx来画了,我们用switch语句替换掉我们原先一直向右的头,现在我们会根据fx去画头,而我们的fx初始化为"R"
加一句初始化就好了
我们已经写过了按下空格会有响应,那么我们对应的蛇头是不是也该响应我们的上下左右键位
类比上文的空格响应,这四句不难看懂吧
可是我们发现,那一句字符串提示语怎么一直在啊,而且我们的蛇,一上来就开始动
我们设置一下当我们按下空格后蛇再开始动,字符串提示消失,并且再次按下可以暂停,字符串再次出现
这样的话就是当我们isStarted为true时,才会动,false时就会暂停了
刚刚说到蛇头的方向,当我们按下下键其实蛇头已经改变了但是我们的蛇并没有朝着蛇头方向走,这时,我们需要在actionPerformed中加上,当fx == R时snakex[0] += 25;其他方向类比一下就可以了
把原来的这两句注释掉就可以了
现在关于蛇的四个方向跑,暂停就已经做好了,当然蛇可以直接掉头的,大家可以试一下,因为我们还没有完善我们的代码,当然,你也可以把这个叫做游戏特色
游戏已经做了一多半了,还差一个事物的生成
好吧,写到这里头有点懵了,晚上再来补一下
最后放一下源码和资源
提取码:0309