贪吃蛇:从零开始搭建一个完整的小游戏

目录

导语:

一、游戏框架

二、蛇的实现

三、绘制游戏界面

四、食物

五、移动蛇

六.得分系统,是否吃到食物

七、检查碰撞

八、处理按键事件

九、得分系统

十、游戏状态管理


导语:

    贪吃蛇这个经典的小游戏,我上学的时候就曾经写过一个,参加校内竞赛还拿了个参与奖。想找以前代码,结果发现没有保存。今天有空就再次整理编写一个。理一理思路。

一、游戏框架

首先,我们需要一个游戏框架,用来处理游戏的逻辑、绘制游戏界面等。

游戏框架是贪吃蛇游戏的基础结构,负责处理游戏的逻辑、绘制游戏界面以及处理用户输入等任务。在Java中,我们可以使用Swing库或JavaFX库来创建游戏窗口和图形界面。

Swing库:Swing是Java提供的一套用于创建图形用户界面(GUI)的工具包。通过Swing,你可以创建窗口、按钮、标签等GUI组件,并通过监听器来响应用户的输入事件。Swing适合于简单的2D游戏,对于贪吃蛇游戏来说,它是一个不错的选择。

下面是创建游戏框架的基本步骤:

使用Swing库创建游戏框架

  • 导入Swing库:在Java项目中,确保你已经导入了Swing库。

  • 创建游戏窗口:使用JFrame类创建游戏窗口,并设置窗口标题、大小等属性。

import javax.swing.*;/*** 微澜贪吃蛇游戏窗口*/
public class SnakeGame extends JFrame {public SnakeGame() {add(new GamePanel(this));setTitle("微澜贪吃蛇");setSize(800, 600); // 设置窗口大小setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭行为setLocationRelativeTo(null); // 将窗口置于屏幕中央setVisible(true); // 显示窗口}public static void main(String[] args) {// 创建游戏实例SwingUtilities.invokeLater(() -> new SnakeGame());}
}

代码运行如下图所示:

图片

二、蛇的实现

蛇是游戏中的核心角色。我们需要实现以下功能:

蛇的移动:蛇可以朝四个方向之一移动,每次移动一个单位长度。

蛇身的增长:当蛇吃到食物时,蛇身长度增加一个单位。

碰撞检测:检测蛇头是否与墙壁、自己的身体或食物发生碰撞,如果碰撞则游戏结束。

创建一个游戏面板类:GamePanel.java

编写完之后需要将类添加到窗口中。

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 GamePanel extends JPanel implements ActionListener, KeyListener {private static final int WIDTH = 600;private static final int HEIGHT = 600;private static final int UNIT_SIZE = 20;private static final int GAME_UNITS = (WIDTH * HEIGHT) / UNIT_SIZE;private static final int DELAY = 100;private final int[] x = new int[GAME_UNITS];private final int[] y = new int[GAME_UNITS];private int bodyParts = 6;private int foodX;private int foodY;private char direction = 'R';private boolean running = false;private Timer timer;private SnakeGame game; // 添加 SnakeGame 实例变量public GamePanel() {this.game = game; // 初始化 game 对象setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);addKeyListener(this);startGame();}public void startGame() {newFood();running = true;timer = new Timer(DELAY, this);timer.start();}public void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {// 绘制游戏界面}public void newFood() {// 生成新的食物的位置}public void move() {// 移动蛇}public void checkFood() {// 检查是否吃到食物}public void checkCollision() {// 检查碰撞}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {move();checkFood();checkCollision();repaint();}}@Overridepublic void keyPressed(KeyEvent e) {// 处理按键事件}@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyReleased(KeyEvent e) {}
}

(具体代码过程,不完全展示)

    这个类继承自JPanel,用于绘制游戏界面和处理游戏逻辑。在这个类中,我们定义了蛇的移动、食物生成、碰撞检测等方法,并实现了ActionListenerKeyListener接口来处理游戏逻辑和键盘输入。

    可以根据自己的一些设计需要填充drawnewFoodmovecheckFoodcheckCollision等方法的具体实现逻辑。

三、绘制游戏界面

用于绘制蛇、食物和游戏边界等元素。

public void draw(Graphics g) {if (running) {// 绘制食物g.setColor(Color.RED);g.fillRect(foodX, foodY, UNIT_SIZE, UNIT_SIZE);// 绘制蛇头和蛇身for (int i = 0; i < bodyParts; i++) {if (i == 0) {g.setColor(Color.GREEN); // 蛇头颜色g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);} else {g.setColor(new Color(45, 180, 0)); // 蛇身颜色g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);}}// 绘制游戏边界g.setColor(Color.YELLOW);g.drawLine(0, 0, WIDTH, 0);g.drawLine(0, 0, 0, HEIGHT);g.drawLine(WIDTH - 1, 0, WIDTH - 1, HEIGHT);g.drawLine(0, HEIGHT - 1, WIDTH, HEIGHT - 1);}
}

    这段代码将会在游戏面板上绘制食物、蛇头、蛇身和游戏边界。食物使用红色填充,蛇头使用绿色填充,蛇身使用深绿色填充,游戏边界使用黄色线条绘制。

四、食物

生成新食物的位置

public void newFood() {foodX = (int) (Math.random() * (WIDTH / UNIT_SIZE)) * UNIT_SIZE;foodY = (int) (Math.random() * (HEIGHT / UNIT_SIZE)) * UNIT_SIZE;
}

    这段代码将随机生成食物的位置。食物的横坐标foodX和纵坐标foodY被限制在游戏窗口的网格上,每个网格的大小为UNIT_SIZE。因此,食物的位置会在游戏窗口的格子中随机选择一个位置。

五、移动蛇

游戏的重中之重就是移动了。

public void move() {// 将蛇的身体部分向前移动for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根据当前方向移动蛇头switch (direction) {case 'U':y[0] -= UNIT_SIZE;break;case 'D':y[0] += UNIT_SIZE;break;case 'L':x[0] -= UNIT_SIZE;break;case 'R':x[0] += UNIT_SIZE;break;}
}

        这段代码将会让蛇的身体部分向前移动一步,然后根据当前方向移动蛇头。如果蛇向上移动,蛇头的纵坐标会减少一个单位大小;如果蛇向下移动,蛇头的纵坐标会增加一个单位大小;如果蛇向左移动,蛇头的横坐标会减少一个单位大小;如果蛇向右移动,蛇头的横坐标会增加一个单位大小。

六.得分系统,是否吃到食物

public void checkFood() {if (x[0] == foodX && y[0] == foodY) {// 如果蛇头的位置与食物的位置重合,则吃到了食物bodyParts++; // 增加蛇身长度newFood(); // 生成新的食物}
}

    这段代码会检查蛇头的位置是否与食物的位置重合。如果重合,则表示蛇吃到了食物,蛇的身体长度会增加,并且生成新的食物位置。

七、检查碰撞

用于检查蛇是否与边界或自身发生碰撞:碰撞之后也就是结束

public void checkCollision() {// 检查是否与边界发生碰撞if (x[0] < 0 || x[0] >= WIDTH || y[0] < 0 || y[0] >= HEIGHT) {running = false; // 游戏结束return;}// 检查是否与自身发生碰撞for (int i = bodyParts; i > 0; i--) {if (x[0] == x[i] && y[0] == y[i]) {running = false; // 游戏结束return;}}
}

    首先检查蛇头是否撞到了游戏边界,如果是,则游戏结束。然后,它检查蛇头是否与自身的任何部分重合,如果是,则游戏也会结束。

八、处理按键事件

补充keyPressed(KeyEvent e)方法的代码,用于处理按键事件,改变蛇的移动方向。

@Override
public void keyPressed(KeyEvent e) {switch (e.getKeyCode()) {case KeyEvent.VK_UP:if (direction != 'D') // 禁止向下移动direction = 'U';break;case KeyEvent.VK_DOWN:if (direction != 'U') // 禁止向上移动direction = 'D';break;case KeyEvent.VK_LEFT:if (direction != 'R') // 禁止向右移动direction = 'L';break;case KeyEvent.VK_RIGHT:if (direction != 'L') // 禁止向左移动direction = 'R';break;}
}

       根据用户按下的方向键来改变蛇的移动方向。如果用户按下上箭头键,则蛇向上移动;如果按下下箭头键,则蛇向下移动;如果按下左箭头键,则蛇向左移动;如果按下右箭头键,则蛇向右移动。同时,还加入了一些限制条件,例如禁止蛇直接反向移动(比如,当蛇向上移动时,不允许按下下箭头键使其立即向下移动)。

九、得分系统

玩游戏还有很重要就是自己有多厉害。那么得分展示那就是必不可少的了。

首先,在SnakeGame类中添加得分变量和相应的方法:

public class SnakeGame extends JFrame {// 其他代码...private int score = 0;public int getScore() {return score;}public void increaseScore() {score += 10; // 每次吃到食物增加10分}
}

GamePanel类的draw(Graphics g)方法中添加绘制得分的逻辑:

public void draw(Graphics g) {// 绘制游戏界面的其他内容...// 绘制得分g.setColor(Color.WHITE);g.setFont(new Font("Arial", Font.BOLD, 20));g.drawString("Score: " + game.getScore(), 20, 30);
}

    这样,每次游戏界面重新绘制时,都会显示当前的得分。接下来,在checkFood()方法中调用increaseScore()方法,以便在蛇吃到食物时增加得分:

public void checkFood() {if (x[0] == foodX && y[0] == foodY) {game.increaseScore(); // 增加得分bodyParts++; // 增加蛇身长度newFood(); // 生成新的食物}
}

现在,游戏界面会显示当前的得分,并且每次蛇吃到食物时,得分都会增加。

十、游戏状态管理

    要添加游戏状态管理,我们需要在 SnakeGame 类中添加游戏状态的枚举,并在 GamePanel 类中根据不同的游戏状态来控制游戏逻辑的执行。让我们一步步完成这个任务。

首先,在 SnakeGame 类中添加游戏状态的枚举:

public enum GameState {RUNNING,PAUSED,GAME_OVER
}public class SnakeGame extends JFrame {// 其他代码...private GameState gameState = GameState.RUNNING;public GameState getGameState() {return gameState;}public void setGameState(GameState gameState) {this.gameState = gameState;}// 其他代码...
}

    在这里,我们定义了一个 GameState 枚举,表示游戏的不同状态。我们还添加了一个 gameState 实例变量来保存当前的游戏状态,并提供了相应的访问方法。

    接下来,在 GamePanel 类中根据不同的游戏状态来控制游戏逻辑的执行。在 actionPerformed 方法中,我们只在游戏运行中(RUNNING 状态)执行游戏逻辑:

public void actionPerformed(ActionEvent e) {if (game.getGameState() == GameState.RUNNING) {move();checkFood();checkCollision();repaint();}
}

    然后,在 paintComponent 方法中,我们根据游戏状态来绘制相应的内容,比如游戏进行中绘制游戏界面,游戏暂停时绘制暂停提示,游戏结束时绘制游戏结束提示:

public void paintComponent(Graphics g) {super.paintComponent(g);switch (game.getGameState()) {case RUNNING:draw(g);break;case PAUSED:// 绘制暂停提示g.setColor(Color.WHITE);g.setFont(new Font("Arial", Font.BOLD, 30));g.drawString("PAUSE!!!", WIDTH / 2 - 100, HEIGHT / 2);break;case GAME_OVER:// 绘制游戏结束提示g.setColor(Color.WHITE);g.setFont(new Font("Arial", Font.BOLD, 30));g.drawString("Game Over!!!", WIDTH / 2 - 100, HEIGHT / 2);break;}}

按键操作部分需要补充逻辑:

@Override
public void keyPressed(KeyEvent e) {switch (e.getKeyCode()) {//其他代码case KeyEvent.VK_SPACE:if (game.getGameState() == GameState.RUNNING) {game.setGameState(GameState.PAUSED); // 暂停游戏} else if (game.getGameState() == GameState.PAUSED) {game.setGameState(GameState.RUNNING); // 恢复游戏}break;}
}

    在这个更新后的 keyPressed 方法中,我们添加了对空格键的监听。如果游戏正在运行,按下空格键会将游戏状态设为暂停;如果游戏已经暂停,再次按下空格键会将游戏状态设为运行。这样就实现了按空格键暂停和恢复游戏的功能。

到这一步一个简单的贪吃蛇小游戏就搭建成功了。

图片

代码地址:https://gitee.com/zhangyang214/snake.git

欢迎讨论!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/784428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT记事本

QT记事本 1.概述 2.界面  2.1 界面布局  2.2 UI美化stylesheet   2.2.1 准备   2.2.2 stylesheet   2.2.3 效果 2.3 窗口大小调整与子控件自适应 3.信号与槽  3.1 简述  3.2 信号与槽设置   3.2.1 UI控件设置   3.2.2 UI转到槽&#xff08;自动连接&am…

Jamba LLM模型:破解大型上下文窗口挑战的AI新星

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

JBPM学习(三):管理流程定义,java集合面试题

Test public void findAll() { // 查询 List list processEngine.getRepositoryService()// .createProcessDefinitionQuery()// .orderAsc(ProcessDefinitionQuery.PROPERTY_KEY)//排序条件 //.count()查询出总数量 //.page(0, 100)分页&#xff0c;取出前100条记录 …

【漏洞复现】WordPress Plugin LearnDash LMS 敏感信息暴漏

漏洞描述 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 WordPress Plugin LearnDash LMS 4.10.2及之前版本存在安全漏洞&#x…

遥感动态监测技术

很多人对动态监测和动态检测两个名词有疑惑。我们可以这样理解&#xff0c;动态监测是一个广义的名词&#xff0c;泛指数据预处理、变化信息发现与提取、变化信息挖掘与应用等&#xff0c;以对整个流程的叙述。动态检测是一个狭义的名词&#xff0c;主要指部分数据预处理、变化…

C++list的模拟实现

为了实现list&#xff0c;我们需要实现三个类 一、List的节点类 template<class T> struct ListNode {ListNode(const T& val T()):_pPre(nullptr),_pNext(nullptr),_val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val; }; 二、List的迭代器…

JAVAEE之CSS

1.CSS 是什么&#xff1f; 层叠样式表 (Cascading Style Sheets). CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离. 1.1 CSS和HTML的区别 CSS&#xff0c;全称为层叠样式表(Cascading Style Sheets)&#xff0c;是…

RocketMQ(版本4.9.4)+RocketMQ_Dashbord环境搭建(生产者、消费者的前置环境搭建)

一、官方网站下载 RocketMQ源码包 https://rocketmq.apache.org/zh/docs/4.x/introduction/02quickstart 二、把rocketMQ上传到Linux环境下解压&#xff0c;编译&#xff0c;执行以下命令&#xff08;需要提前装jdk和maven并配置好环境变量&#xff09; unzip rocketmq-all-4…

AtCoder Beginner Contest 347 (ABCDEF题)视频讲解

A - Divisible Problem Statement You are given positive integers N N N and K K K, and a sequence of length N N N, A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\ldots,A_N) A(A1​,A2​,…,AN​). Extract all elements of A A A that are multiples of K K K, divi…

计算机的组成原理

1.简单常识介绍 1.1认识一下计算机的真实相貌 1.2怎么通过电信号传二进制 工作原理 cpu的针脚也就跟我们的手指一样用来接收高低电频&#xff0c;来判断2进制数据 cpu和数据交互的原理 2.计算机系统 软件介绍 硬件的发展历史 电子管时代 晶体管时代 中小规模集成电路 大规模…

C#(winform) 调用MATLAB函数

测试环境 VisualStudio2022 / .NET Framework 4.7.2 Matlab2021b 参考&#xff1a;C# Matlab 相互调用 Matlab 1、编写Matlab函数 可以没有任何参数单纯定义matlab处理的函数&#xff0c;输出的数据都存在TXT中用以后期读取数据 function [result,m,n] TEST(list) % 计算…

Uibot6.0 (RPA财务机器人师资培训第6天 )发票验真机器人案例实战

类似于小北的这篇博客&#xff1a;Uibot (RPA设计软件&#xff09;Mage AI智能识别&#xff08;发票识别&#xff09;———课前材料五_uibot 添加mageai-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/135591297?spm1001.2014.3001.5501训练网站&#xff1a;泓江…

电流镜恒流源简介

目录 工作原理 设计要点 应用场景 初步想法&#xff0c;为参加活动先占贴&#xff08;带家人出去玩没时间搞~~&#xff09;&#xff0c;后面优化 电流镜恒流源是一种利用电流镜原理设计的电路&#xff0c;它可以提供恒定的电流输出&#xff0c;不受负载变化或电源电压波动的…

Linux:ip协议

文章目录 ip协议基本认识ip协议的报头 ip协议基本认识 前面对于TCP的内容已经基本结束了&#xff0c;那么这也就意味着在传输层也已经结束了&#xff0c;那么下一步要进入的是的是网络层&#xff0c;网络层中也有很多种协议&#xff0c;这里主要进行解析的是ip协议 前面的TCP…

迅饶科技 X2Modbus 网关 GetUser 信息泄露漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…

政安晨:【Keras机器学习实践要点】(十二)—— 迁移学习和微调

目录 设置 介绍 冻结层&#xff1a;了解可训练属性 可训练属性的递归设置 典型的迁移学习工作流程 微调 关于compile()和trainable的重要说明 BatchNormalization层的重要注意事项 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: T…

前端对数据进行分组和计数处理

js对数组数据的处理&#xff0c;添加属性&#xff0c;合并表格数据。 let data[{id:1,group_id:111},{id:2,group_id:111},{id:3,group_id:111},{id:4,group_id:222},{id:5,group_id:222} ]let tempDatadata; tempDatatempData.reduce((arr,item)>{let findarr.find(i>i…

this.$route.back()时的组件缓存

1.this.$route.back()回到上一个路径会重新加载 跳转时,前一个路由的内容会被销毁,当回来时,重新创建树,组件内有保存了距离,没有一开始是0. 2.keep-alive写在router-view上面,这个地方所代表的路由会被保存,因此可以写在上面,保存,当返回时,如果是这个路由,里面的内容是一样…

CommunityToolkit.Mvvm----配置

一、介绍&#xff1a; CommunityToolkit.Mvvm 包&#xff08;又名 MVVM 工具包&#xff0c;以前称为 Microsoft.Toolkit.Mvvm&#xff09;是一个现代、快速和模块化的 MVVM 库。 它是 .NET 社区工具包的一部分&#xff0c;围绕以下原则生成&#xff1a; 独立于平台和运行时 - …

Android进阶学习:移动端开发重点学习的十点,不能再得过且过的写业务代码了

最近有朋友问我&#xff1a;“安卓开发是不是没人要了&#xff0c;除了画 UI 别的都不会怎么办&#xff1f;” 考虑到这可能是很多人共同的疑问&#xff0c;决定简单写一下。 说了很多遍了&#xff0c;**不是安卓开发没人要了&#xff0c;是初级安卓没人要了。**现在还在大量…