目录
本文用于自己参考,不参与商业用途,学习于来自动力节点课程,如有侵权联系删除。
成品
一:贪吃蛇游戏的实现步骤
1. 画出窗口
窗口大小
实现700*900
①宽度值为700像素,每个格子为25像素,共计有28个格子。
②高度值为800像素,每个格子为25像素,共计有36 个格子。
package demo;
import javax.swing.*;
public class MySnake {
public static void main(String[] args) {
// 创建一个窗口
JFrame frame = new JFrame();
// 指定窗口x和y的相对位置及窗口的宽度和高度值
frame.setBounds(500,25,700,800);
// 不允许拖拽改变大小
frame.setResizable(false);
// 当点击窗口关闭按钮,执行操作是退出
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 当前窗口显示出来
frame.setVisible(true);
}
}
2. 在窗口上添加画布
package demo;
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel {
public MyPanel() {
}
// 重写画组件的方法
@Override
protected void paintComponent(Graphics g) {
// 调用父类值的方法做一些基本工作
super.paintComponent(g);
// 设置背景颜色
this.setBackground(Color.red);
}
}
3. 在画布上添加一个黑色游戏区
package demo;
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel {
public MyPanel() {
}
// 重写画组件的方法
@Override
protected void paintComponent(Graphics g) {
// 调用父类值的方法做一些基本工作
super.paintComponent(g);
// 设置背景颜色
this.setBackground(Color.red);
// 在画布中添加游戏区域(这里就和框一样大小)
g.fillRect(0,0,700,900);
}
}
4. 放静态蛇、
package demo;
import javax.swing.*;
import java.awt.*;
import java.lang.invoke.VarHandle;
public class MyPanel extends JPanel {
// 声明右侧蛇头和身体
ImageIcon right = new ImageIcon("images/right.png");
ImageIcon body = new ImageIcon("images/body.png");
public MyPanel() {
}
// 重写画组件的方法
@Override
protected void paintComponent(Graphics g) {
// 调用父类值的方法做一些基本工作
super.paintComponent(g);
// 设置背景颜色
this.setBackground(Color.red);
// 在画布中添加游戏区域
g.fillRect(0,0,700,800);
// 在画布中添加右侧蛇头和身体
right.paintIcon(this,g,100,100);
body.paintIcon(this,g,75,100);
body.paintIcon(this,g,50,100);
}
}
5. 定义蛇的数据结构
//声明右侧蛇头和身体
ImageIcon right = new ImageIcon("D:\\破解工具\\images\\right.png");
ImageIcon body =new ImageIcon("D:\\破解工具\\images\\body.png");
//设定蛇头和身体的初始位置
snakeX[0]=100;
snakeY[0]=100;
snakeX[1]=75;
snakeY[1]=100;
snakeX[2]=50;
snakeY[2]=100;
//添加的身体
body.paintIcon(this,g,75,100);
body.paintIcon(this,g,50,100)
//两个数组分别存放X和Y坐标
int[] snakeX = new int[1008];//数组最大值是宽乘高
int[] snakeY = new int[1008];//数组最大值是宽乘高
6. 控制蛇头方向
//定义枚举来实现,创建枚举类Direction
package Demo;
public enum Direction {//定义枚举方向,四个取值,向上,向下,向左,向右
top,bottom,Left,right;
}
7. 放上开始提示信息
使用提供的画笔g
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,50));
g.drawString("请按空格键表示游戏开始!",50,500);
8. 按空格键开始游戏
创建Boolean类isStart判断是否开始游戏,isStart若是为false显示开始文字,然后再构造方法中,设置焦点,通过获得键盘事件来控制,重写keyTyped()、keyPressed()、keyReleased(),在keyPressed()方法中判断是否为空格所对应的ASCII码
//Boolean的标记
boolean isStart = false;
//获取键盘事件
this.setFocusable(true);
//添加键盘监听
this.addKeyListener(this);
timer.start();
foodX=25+25*random.nextInt(20);
foodY=25+25*random.nextInt(20);
//重写的方法中可以多次按下空格进行开始或者暂停,!isStart是精髓
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
if(keyCode==32){
//标记游戏状态值取反
isStart=!isStart;
//重新画组件
repaint();
9. 让蛇动起来
创建定时器Timer来进行移动,第一个参数表示多长时间运行一次,第二个参数当时间到了以后找谁-this,this需要实现ActionListener接口,重写actionPerformed()方法,也就是当时间到了调用actionPerformed()方法。
在构造方法中启动定时器,当到100毫秒就调用重写actionPerformed()方法。
在重写actionPerformed()方法体中,实现蛇移动;移动蛇的思路:
假如蛇水平向右移动,最后一个身体移动到前面一个身体的位置,也就是x坐标更改,y坐标不动;假如蛇的头部也水平向右移动,蛇的头部x坐标应该在当前位置+25。
Timer timer=new Timer(100,this);
//下面是重写的actionPerformed()方法
if(isStart){//如果开始则移动
// 移动身体
for(int i =len-1;i>0;i--){
snakeX[i]=snakeX[i-1];
snakeY[i]=snakeY[i-1];
}
//通过方向值direction进行判断
switch (direction){
case top:
snakeY[0]-=25;
if(snakeY[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
// snakeY[0]=900;
}
break;
case bottom:
snakeY[0]+=25;
if(snakeY[0]>=900){
num++;
isStart=!isStart;
// System.exit(0);
// snakeY[0]=0;
}
break;
case right:
//假如蛇向右,蛇头加25
snakeX[0]+=25;
if(snakeX[0]>=700){
num++;
isStart=!isStart;
//System.exit(0);
// snakeX[0]=0;
}
break;
case Left:
//假如蛇向左,蛇头减25
snakeX[0]-=25;
if(snakeX[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
//snakeX[0]=700;
}
break;
}
其中我添加了个num来进行死亡代码的判断标记,当蛇头碰到“墙壁”isStart里面的if判断在下面代码。注释中的第一个System,exit相当于碰到墙壁,程序就死去,第二个snakeX[0]和snakeY[0]是设置蛇头碰到坐标0,0时从另一头出来。
10. 实现暂停
if(!isStart){
if(num%2==0){
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,50));
g.drawString("请按空格键表示游戏开始!",50,500);
}else {
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,40));
g.drawString("你死了游戏分数是"+fenshu,50,450);
}
}
11. 实现转向功能
}else if (keyCode==KeyEvent.VK_UP){
direction=Direction.top;
} else if (keyCode==KeyEvent.VK_DOWN) {
direction=Direction.bottom;
} else if (keyCode==KeyEvent.VK_LEFT) {
direction=Direction.Left;
} else if (keyCode==KeyEvent.VK_RIGHT) {
direction=Direction.right;
}
//通过方向值direction进行判断
switch (direction){
case top:
snakeY[0]-=25;
if(snakeY[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
// snakeY[0]=900;
}
break;
case bottom:
snakeY[0]+=25;
if(snakeY[0]>=900){
num++;
isStart=!isStart;
// System.exit(0);
// snakeY[0]=0;
}
break;
case right:
//假如蛇向右,蛇头加25
snakeX[0]+=25;
if(snakeX[0]>=700){
num++;
isStart=!isStart;
//System.exit(0);
// snakeX[0]=0;
}
break;
case Left:
//假如蛇向左,蛇头减25
snakeX[0]-=25;
if(snakeX[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
//snakeX[0]=700;
}
break;
}
12. 添加食物
//声明两个食物变量
int foodX;
int foodY;
//随机生成食物
Random random=new Random();
//食物重新生成
foodX=25+25*random.nextInt(20);
foodY=25+25*random.nextInt(20);
13. 吃掉食物
声明分数变量吃到食物身体长度加1,分数加10.
int fenshu=0;
if(snakeX[0]==foodX&&snakeY[0]==foodY){
//蛇长度加1
len++;
fenshu+=10;
二:核心源码
1. MySnake类
package Demo;
import javax.swing.*;
public class MySnake {
public static void main(String[] args) {
//创建一个窗口
JFrame frame = new JFrame();
//给窗口设置长宽高
frame.setBounds(600,100,700,900);
//不允许拖拽改变大小
frame.setResizable(false);
//点击关闭按钮,是退出
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MyPanel());
//显示出来
frame.setVisible(true);
}
}
2. MyPanel类
package Demo;
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;
import java.util.Random;
public class MyPanel extends JPanel implements KeyListener, ActionListener {
//声明右侧蛇头和身体
ImageIcon right = new ImageIcon("D:\\破解工具\\images\\right.png");
ImageIcon body =new ImageIcon("D:\\破解工具\\images\\body.png");
//声明上下左的图片
ImageIcon top=new ImageIcon("D:\\破解工具\\images\\top.png");
ImageIcon bottom=new ImageIcon("D:\\破解工具\\images\\bottom.png");
ImageIcon left=new ImageIcon("D:\\破解工具\\images\\left.png");
//声明蛇的长度
int len = 3;
int num=2;
int fenshu=0;
//两个数组分别存放X和Y坐标
int[] snakeX = new int[1008];//数组最大值是宽乘高
int[] snakeY = new int[1008];//数组最大值是宽乘高
//声明一个枚举型变量,标识蛇头方向
//声明1个变量标记游戏开始True 表示游戏开始,否则没有开始游戏
boolean isStart = false;
Timer timer=new Timer(100,this);
Direction direction = Direction.right;
//声明两个食物变量
int foodX;
int foodY;
Random random=new Random();
ImageIcon food=new ImageIcon("D:\\破解工具\\images\\food.png");
public MyPanel() {
//设定蛇头和身体的初始位置
snakeX[0]=100;
snakeY[0]=100;
snakeX[1]=75;
snakeY[1]=100;
snakeX[2]=50;
snakeY[2]=100;
//获取键盘事件
this.setFocusable(true);
//添加键盘监听
this.addKeyListener(this);
timer.start();
foodX=25+25*random.nextInt(20);
foodY=25+25*random.nextInt(20);
}
//重写画组件方法
@Override
protected void paintComponent(Graphics g) {
//调用父类方法做一些基本工作
super.paintComponent(g);
this.setBackground(Color.green);
g.fillRect(0,0,700,900);
//添加头
/* right.paintIcon(this,g,snakeX[0],snakeY[0]);*/
//根据枚举型变量判断,显示蛇头位置
switch (direction){
case top:
top.paintIcon(this,g,snakeX[0],snakeY[0]);
break;
case bottom:
bottom.paintIcon(this,g,snakeX[0],snakeY[0]);
break;
case Left:
left.paintIcon(this,g,snakeX[0],snakeY[0]);
break;
case right:
right.paintIcon(this,g,snakeX[0],snakeY[0]);
break;
}
//添加两个身体
/* body.paintIcon(this,g,75,100);
body.paintIcon(this,g,50,100);*/
for(int i = 1;i<len;i++){
body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//放上开始提示信息,设置字体和颜色
if(!isStart){
if(num%2==0){
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,50));
g.drawString("请按空格键表示游戏开始!",50,500);
}else {
g.setColor(Color.white);
g.setFont(new Font("宋体",Font.BOLD,40));
g.drawString("你死了游戏分数是"+fenshu,50,450);
}
}
food.paintIcon(this,g,foodX,foodY);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
if(keyCode==32){
//标记游戏状态值取反
isStart=!isStart;
//重新画组件
repaint();
}else if (keyCode==KeyEvent.VK_UP){
direction=Direction.top;
} else if (keyCode==KeyEvent.VK_DOWN) {
direction=Direction.bottom;
} else if (keyCode==KeyEvent.VK_LEFT) {
direction=Direction.Left;
} else if (keyCode==KeyEvent.VK_RIGHT) {
direction=Direction.right;
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if(isStart){//如果开始则移动
// 移动身体
for(int i =len-1;i>0;i--){
snakeX[i]=snakeX[i-1];
snakeY[i]=snakeY[i-1];
}
//通过方向值direction进行判断
switch (direction){
case top:
snakeY[0]-=25;
if(snakeY[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
// snakeY[0]=900;
}
break;
case bottom:
snakeY[0]+=25;
if(snakeY[0]>=900){
num++;
isStart=!isStart;
// System.exit(0);
// snakeY[0]=0;
}
break;
case right:
//假如蛇向右,蛇头加25
snakeX[0]+=25;
if(snakeX[0]>=700){
num++;
isStart=!isStart;
//System.exit(0);
// snakeX[0]=0;
}
break;
case Left:
//假如蛇向左,蛇头减25
snakeX[0]-=25;
if(snakeX[0]<=0){
num++;
isStart=!isStart;
//System.exit(0);
//snakeX[0]=700;
}
break;
}
if(snakeX[0]==foodX&&snakeY[0]==foodY){
//蛇长度加1
len++;
fenshu+=10;
//食物重新生成
foodX=25+25*random.nextInt(20);
foodY=25+25*random.nextInt(20);
}
//重写画组件方法
repaint();
//重启定时器
timer.start();
}
}
}
3. Direction类
package Demo;
public enum Direction {//定义枚举方向,四个取值,向上,向下,向左,向右
top,bottom,Left,right;
}