当前位置: 首页 > news >正文

无swing,高级javaSE毕业之贪吃蛇游戏(含模块构建,多线程监听服务)

JavaSE,无框架实现贪吃蛇

文章目录

  • JavaSE,无框架实现贪吃蛇
    • 1.整体思考
    • 2.可能的难点思考
      • 2.1 如何表示游戏界面
      • 2.2 如何渲染游戏界面
      • 2.3 如何让游戏动起来
      • 2.4 蛇如何移动
    • 3.流程图制作
    • 4.模块划分
    • 5.模块完善
      • 5.0常量优化
      • 5.1监听键盘服务
        • i.输入存储
        • ii.键盘监听
      • 5.2棋盘类方法(地图)
        • i.节点渲染
        • ii.边界判断
        • iii.地图显示
        • iV.食物生成
        • V.地图初始化
      • 5.3蛇类方法
        • i.蛇体初始化
        • ii.自定义异常
        • iii.食物监测
        • iV.自我碰撞监测
        • V.移动
    • 6.业务流程编写

本篇文章没有使用任何框架,纯JavaSE编写的贪吃蛇。主要探讨点为程序设计,比如流程绘制,模块划分。

如果需要源代码,公众号’一只学Java的飞哥呀’,回复贪吃蛇,即可获取源码和讲义。此外附赠1年前用GUI写的贪吃蛇

JavaSE无框架实现贪吃蛇效果

贪吃蛇JavaSE无框架


JavaGUI实现贪吃蛇效果,但文章内容并无涉及GUI代码编写,仅仅在公众号上提供相应代码

贪吃蛇GUI

1.整体思考

  • 游戏明面上组成部分有2。蛇、地图。在JavaSE的知识体系内。地图可以使用二维数组表示,蛇可以用一维数组表示
  • 通过在控制台打印数组的形式,来静态展示贪吃蛇游戏
  • 游戏本质上是一组连续的图片,每一秒打印一次数组,以此让游戏动起来
  • 游戏需要通过用户敲击键盘,实现方向移动。程序需要监听键盘输入,并将输入结果传递给蛇,以此操作蛇的移动

2.可能的难点思考

2.1 如何表示游戏界面

public class GameMap{private static int row = 20;private static int col = 20;// String的二维数组, 用来表示地图public static String[][] gameMap = new String[row][col];    // 初始化地图public GameMap() {// o 为地图, * 为蛇, @ 为食物for (int i = 0; i < gameMap.length; ++i) {for (int j = 0; j < gameMap[0].length; ++j) {gameMap[i][j] = "o";}}}//...
}// Node的一维列表, 用来表示蛇的坐标
public class Node{int x;int y;public Node() {}public Node(int x, int y) {this.x = x;this.y = y;}
}public class Snake{Deque<Node> snakeLoc = new ArrayDeque<>(); // ...
}

2.2 如何渲染游戏界面

打印地图,相当于渲染游戏界面

void printMap() {// 循环打印map   
}

2.3 如何让游戏动起来

用循环,持续不断的打印界面,就可以形成动起来的效果

while(true) {// ...printMap(map, snake);// ...
}

2.4 蛇如何移动

蛇的移动属于蛇对象的行为,因此我们可以在Snake类中封装move方法,移动的本质是:蛇尾移动到蛇头.

public class Snake{// 返回尾坐标,头坐标public void move(int[] direction) {// 获取蛇尾坐标Node lastNode = snakeLoc.removeLast();// 移动Node newNode = moveTo(direction);// 添加到蛇头snakeLoc.addFirst(newNode);}private Node moveTo(Node node, int[] direction) {// 获取头节点Node firstNode = snakeLoc.getFirst();// 执行移动逻辑int x = firstNode.getX();int y = firstNode.getY();x += direction[0];y += direction[1];firstNode.setX(x);firstNode.setY(y);return firstNode;}
}

3.流程图制作

在这里插入图片描述

4.模块划分

在这里插入图片描述

5.模块完善

5.0常量优化

public interface Constants {/*** 蛇的标记*/String SNAKE_FLAG = "o";/*** 地图的标记*/String MAP_FLAG = "*";/*** 食物的标记*/String FOOD_FLAG = "@";/*** 地图行数*/int row = 10;/*** 地图列数*/int col = 10;
}

5.1监听键盘服务

考虑到还在JavaSE的范畴,swing的键盘监听功能我们不会去使用,而网上有没有找到合适的代替方案。因此,我们采用最原始的方法,Scanner输入,来代替监听功能。但scanner会有阻塞现象,一旦把主游戏进程阻塞,那么后续的流程都将无法进行。因此,我们需要开启子线程来监听用户输入

i.输入存储

/*** 存储用户的输入*/
public class StoreInput{private static String input = "a";/**    w* a  s  d*/private static List<String> validDir = Arrays.asList("w", "a", "s", "d");public static void set(String in) {if (validDir.contains(in)) {input = in;    }}public static int[] get() {if ("w".equals(input)) {int[] dir = {0, 1};return dir;}else if ("a".equals(input)) {int[] dir = {-1, 0};return dir;    }else if ("s".equals(input)) {int[] dir = {0, -1};return dir;}else {int[] dir = {1, 0};return dir;}}
}

ii.键盘监听

/*** 监听器, 监听输入*/
public class ScanerListener{public void start() {// 创建线程new Thread(new Runnable() {Scanner scanner = new Scanner(System.in);@Overridepublic void run() {while(true) {if (scanner.hasNext()) {// 存储最后一个字符int length = scanner.next().length();char inputChar = scanner.next().charAt(length - 1);StoreInput.set(String.valueOf(inputChar));}}}}).start();}
}

5.2棋盘类方法(地图)

  • 地图节点渲染(蛇/食物 坐标渲染)
  • 地图边界判断

i.节点渲染

// 地图坐标更新
public static void updateMap(Node node, String type) {gameMap[node.getX()][node.getY()] = type;
}

ii.边界判断

// 判断是否到达地图边缘
public static boolean isValid(Node node) {if (node.getX() < 0 || node.getX() >= Constants.row || node.getY() < 0 || node.getY() >= Constants.col) {// 非法return false;         }// 合法return true;
}

iii.地图显示

循环打印地图数组

public void show() {	for (int i = 0; i < gameMap.length; ++i) {for (int j = 0; j < gameMap[0].length; ++j) {System.out.print(gameMap[i][j]);System.out.print(" ");}System.out.println();}
}

iV.食物生成

private static Random random = new Random();private static Node food = new Node(1, 1);/*** 生成食物, 且保证不是在蛇的身体上*/ 
public static void generateFood() {// 循环生成成对坐标, 并且坐标不能落在蛇体上int x = 0;int y = 0;do {x = random.nextInt(Constants.row);y = random.nextInt(Constants.col);}while( isSnake(x, y) );food = new Node(x, y);updateMap(food, Constants.SNAKE_FLAG);
}/*** 返回食物节点*/
public static Node getFood() {return food;
}private static boolean isSnake(int x, int y) {return gameMap[x][y].equals(Constants.SNAKE_FLAG);
}

V.地图初始化

1.初始化食物,地图,蛇

// 初始化地图
public GameMap() {// o 为地图, * 为蛇, @ 为食物for (int i = 0; i < gameMap.length; ++i) {for (int j = 0; j < gameMap[0].length; ++j) {gameMap[i][j] = Constants.MAP_FLAG;}}generateFood();
}

5.3蛇类方法

初步完善如下功能:

  • 位置移动
  • 自我碰撞监测
  • 食物监测

i.蛇体初始化

public class Snake{// 初始化贪吃蛇public Snake() {Node node = new Node(Constants.row / 2, Constants.col / 2);snakeLoc.addFirst(node);GameMap.updateMap(node, Constants.SNAKE_FLAG);Node node1 = new Node(node.getX() + 1, node.getY());snakeLoc.addLast(node1);GameMap.updateMap(node1, Constants.SNAKE_FLAG);}
}

ii.自定义异常

public SnakeException extends RuntimeException{public SnakeException(String msg) {super(msg);}
}

iii.食物监测

/*** 监测食物*/
public void detectFood(Node firstNode) {boolean flag = isFood(firstNode);if (flag) {System.out.println("吃掉!");// 长度增加longgerSelf();// 随机生成食物GameMap.generateFood();}
}/*** 增长自己*/ 
private void longgerSelf(){// 获取当前方向int[] dir = StoreInput.get();// 方向取反, 获得尾巴需要添加的方向int x = -1 * dir[0];int y = -1 * dir[1];// 在尾部添加节点Node lastNode = snakeLoc.getLast();Node newNode = new Node(lastNode.getX() + x, lastNode.getY() + y);// 添加节点到尾部snakeLoc.addLast(newNode);// 更新节点GameMap.updateMap(newNode, Constants.SNAKE_FLAG);
}/*** 判断节点是否是食物* @param firstNode*/
private boolean isFood(Node firstNode) {Node foodNode = GameMap.getFood();return firstNode.getX() == foodNode.getX() && firstNode.getY() == foodNode.getY();
}

iV.自我碰撞监测

/*** 传入新的头节点, 判断是否和身体节点冲突*/
public boolean detectSelf(Node firstNode) {// 判断是否和余下的节点冲突for (Node node : snakeLoc) {if (node.getX() == firstNode.getX() && node.getY() == firstNode.getY()) {return true;}}return false;
}

V.移动

因为我们已经有输入存储模块,我们可以直接从中获取

// 返回尾坐标,头坐标
public void move() {// 获取蛇尾坐标Node lastNode = snakeLoc.removeLast();// 获取方向int[] direction = StoreInput.get();// 移动Node newNode = moveTo(direction);// 墙体监测if (!GameMap.isValid(newNode)) {throw new SnakeException("撞墙!游戏结束");}// 自我碰撞监测if (detectSelf(newNode)) {throw new SnakeException("撞到自己!游戏结束");}// 返回更改坐标GameMap.updateMap(lastNode, Constants.MAP_FLAG);GameMap.updateMap(newNode, Constants.SNAKE_FLAG);// 食物探测detectFood(newNode);// 添加到蛇头snakeLoc.addFirst(newNode);
}private Node moveTo(int[] direction) {// 获取头节点Node firstNode = snakeLoc.getFirst();// 执行移动逻辑int x = firstNode.getX();int y = firstNode.getY();x += direction[0];y += direction[1];// 创建新节点return new Node(x, y);
}

6.业务流程编写

游戏类,主要控制全局的游戏流程

public class SnakeGame {// 创建地图private static GameMap map = new GameMap();// 创建蛇对象private static Snake snake = new Snake();// 创建监听服务private static ScanerListener listener = new ScanerListener();public static void main(String[] args) {// 开启游戏// 启动键盘监听服务listener.start();try {while(true) {// 绘图map.show();// 睡眠1秒try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 移动蛇snake.move();// 清空控制台cls();}} catch(SnakeException e) {e.printStackTrace();}}private static void cls() {
//        System.out.print("Everything on the console will cleared");System.out.print("\033[H\033[2J");System.out.flush();}
}

相关文章:

无swing,高级javaSE毕业之贪吃蛇游戏(含模块构建,多线程监听服务)

JavaSE&#xff0c;无框架实现贪吃蛇 文章目录 JavaSE&#xff0c;无框架实现贪吃蛇1.整体思考2.可能的难点思考2.1 如何表示游戏界面2.2 如何渲染游戏界面2.3 如何让游戏动起来2.4 蛇如何移动 3.流程图制作4.模块划分5.模块完善5.0常量优化5.1监听键盘服务i.输入存储ii.键盘监…...

HDD-FAT32 ZIP-FAT32 HDD-FAT16 ZIP-FAT16 HDD-NTFS

FAT32、FAT16指的是分区格式&#xff0c; FAT16单个文件最大2G FAT32单个文件最大4G NTFS单个文件大于4G HDD是硬盘启动 ZIP是软盘启动 U盘选HDD HDD-NTFS...

王道数据结构编程题 二叉树

二叉树定义 以下为本文解题代码的二叉树定义。 struct TreeNode {int val;TreeNode* left, *right;TreeNode(int val 0, TreeNode* left nullptr, TreeNode* right nullptr): val(val), left(left), right(right) {} };非递归后序遍历 题目描述 编写后序遍历二叉树的非递…...

登录怎么实现的,密码加密了嘛?使用明文还是暗文,知道怎么加密嘛?

在Java中登录功能的实现通常包括以下步骤&#xff0c;其中密码应该以加密形式存储在数据库中&#xff0c;而不以明文形式存储&#xff0c;以增强安全性&#xff1a; 登录功能的实现步骤&#xff1a; 用户输入&#xff1a; 用户在登录页面上输入用户名和密码。 传输到服务器&a…...

Nginx和Tomcat负载均衡实现session共享

以前的项目使用Nginx作为反向代理实现了多个Tomcat的负载均衡&#xff0c;为了实现多个Tomcat之间的session共享&#xff0c;使用了开源的Memcached-Session-Manager框架。 此框架的优势&#xff1a; 1、支持Tomcat6和Tomcat7 2、操作粘性或不黏性Session 3、没有单点故障 4、T…...

【算法题】210. 课程表 II

题目&#xff1a; 现在你总共有 numCourses 门课需要选&#xff0c;记为 0 到 numCourses - 1。给你一个数组 prerequisites &#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示在选修课程 ai 前 必须 先选修 bi 。 例如&#xff0c;想要学习课程 0 &#xff0c;…...

“数据类型不一致”会走索引吗?

分析&回答 字符串类型的索引 id_1 varchar(20) NOT NULL这样下面两条语句的结果是一样的&#xff1a; SELECT * FROM ix_test WHERE id_11; SELECT * FROM ix_test WHERE id_11;执行计划是不同的&#xff1a; mysql> explain select * from ix_test where id_11; | 1 …...

Leetcode 1572.矩阵对角线元素之和

给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&#xff1a; 输入&#xff1a;mat [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;25 解释&#xff1a;对角线的和为&#xff…...

[PG]将一行数据打散成多行数据

原始数据 比如有如此表结构定义: 假如查询数据如下&#xff1a; select dt as "日期",bj_count as "北京", sh_count as "上海",gz_count as "广州", sz_count as "深圳" from city_stats order by dt--------------------…...

二蛋赠书一期:《快捷学习Spring》

文章目录 前言活动规则参与方式本期赠书《快捷学习Spring》关于本书作者介绍内容简介读者对象 结语 前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c…...

Threejs汽车展厅

2023-09-06-16-29-40 预览&#xff1a;https://9kt8fy-1234.csb.app/ 源码链接...

LeetCode:207. 课程表、210. 课程表 II(拓扑排序 C++)

目录 207. 课程表 题目描述&#xff1a; 实现代码与解析&#xff1a; 拓扑排序 210. 课程表 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 拓扑排序 原理思路&#xff1a; 207. 课程表 题目描述&#xff1a; 你这个学期必须选修 numCourses 门课程&#xff0…...

如何使用组件

可以复用的代码写到组件里面&#xff0c;比如左侧的导航栏 1.写好一个组件 记得结构写在template标签里面&#xff0c;当然div也可以 2.在需要使用的地方&#xff0c;用标签使用组件 3.在使用的文件内import此组件 import CommonAside from /components/CommonAside.vue; …...

Android 13.0 Launcher3定制之双层改单层(去掉抽屉式二)

1.概述 在13.0的系统产品开发中,对于在Launcher3中的抽屉模式也就是双层模式,在系统原生的Launcher3中就是双层抽屉模式的, 但是在通过抽屉上滑的模式拉出app列表页,但是在一些产品开发中,对于单层模式的Launcher3的产品模式也是常用的功能, 所以需要了解抽屉模式,然后修…...

对卷积的一点具象化理解

前言 卷积的公式一般被表示为下式&#xff1a; 对新手来说完全看不懂这是干什么&#xff0c;这个问题需要结合卷积的应用场景来说。 原理 卷积比较广泛的应用是在信号与系统中&#xff0c;所以有些公式的定义会按照信息流的习惯。假设存在一串信号g(x)经过一个响应h(x)时他的响…...

NV12数据格式转H265编码格式实现过程

一、需求 在视频处理和传输应用中&#xff0c;将视频数据编码为高效的格式是非常重要的。H.265&#xff08;也称为HEVC&#xff09;是一种先进的视频编码标准&#xff0c;具有更好的压缩性能和图像质量&#xff0c;相比于传统的编码标准&#xff08;如H.264&#xff09;&#…...

ubuntu 22.04 深度学习环境配置

第一步 安装驱动 网址&#xff1a;https://www.nvidia.com/download/index.aspx 根据硬件选择&#xff0c;我这里是 ubuntu 服务器,显卡是v100 sudo su root chmod ax NVIDIA //按 TAB 即可 加运行权限 # 禁用原显卡驱动 vim /etc/modprobe.d/blacklist.conf # 在最后一行…...

支付宝小程序集成mqtt兼容IOS和安卓

1. 前言 ​ 去年就想做支付宝小程序接入mqtt协议。但最终多方咨询&#xff0c;问客服问社区得到的答案都是支付宝小程序不能直接支持mqtt协议。偶然间发现徐宏大神的佳作&#xff0c;终于发现了xmqtt.js这个好东西。它实现了支付宝小程序完美接入mqtt协议&#xff0c;设备可以…...

在Qt5中SQLite3的使用

一、SQLite简要介绍 什么是SQLite SQLite是一个进程内的库&#xff0c;实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库&#xff0c;这意味着与其他数据库不一样&#xff0c;您不需要在系统中配置。 就像其他数据库&#xff0c;S…...

使用Docker部署debezium来监控 MySQL 数据库

使用Docker部署debezium来监控 MySQL 数据库 Debezium是一个分布式平台,它将来自现有数据库的信息转换为事件流,使应用程序能够检测并立即响应数据库中的行级更改。 Debezium构建在Apache Kafka之上,并提供了一组Kafka Connect兼容的连接器。每个连接器都与特定的数据库管…...

百度低质量站点怎么办?解决百度低质量站点的方法和工具

百度低质量站点怎么恢复&#xff1f;这是许多网站主和运营人员在SEO优化过程中经常面临的一个问题。百度作为中国最大的搜索引擎&#xff0c;对于网站收录和排名具有至关重要的影响。然而&#xff0c;由于各种原因&#xff0c;有些网站可能面临被百度降权或收录减少的情况。那么…...

MSOS604A是德科技keysight MSOS604A示波器

181/2461/8938Infiniium S系列示波器融合了创新技术&#xff0c;旨在提供卓越的测量。新的10位ADC和低噪声前端技术协同工作&#xff0c;提供高达8 GHz的性能和业界最佳的信号完整性。一个高级框架&#xff0c;配有可快速启动的固态硬盘、可轻松触摸的15英寸电容式显示屏和可快…...

春秋云镜 CVE-2016-0785

春秋云镜 CVE-2016-0785 S2-029 靶标介绍 2.3.28 之前的 Apache Struts 2.x 允许远程攻击者通过标签属性中的“%{}”序列执行任意代码。 启动场景 漏洞利用 工具利用 得到flag flag{a4c7fc9a-8e2d-49b8-9b09-22790fb2bfb6}...

入门ElasticSearch :为什么选择ES作为搜索引擎?

介绍 随着数据量的不断增长&#xff0c;搜索和分析大规模数据集变得越来越重要。传统数据库在面对这种需求时往往表现不佳&#xff0c;这时候就需要一种专门用于搜索和分析的引擎。ElasticSearch &#xff08;简称ES&#xff09;就是这样一款强大的搜索引擎&#xff0c;它具有许…...

汽车安全及标准

汽车安全及标准 我们的测试系统如何处理整个标准&#xff1f; 您是否需要处理汽车行业的一系列标准&#xff1f; 不同的标准侧重于驱动逆变器的安全性和功能性&#xff1a; 功能安全&#xff08;ISO 26262&#xff09;信号和低压车载网络&#xff08;LV 124、LV 148 和 VDA …...

APP备案流程详细解读

背景介绍 2023年8月4日&#xff0c;工信部发布《工业和信息化部关于开展移动互联网应用程序备案工作的通知》。 在中华人民共和国境内从事互联网信息服务的APP主办者&#xff0c;应当依照《中华人民共和国反电信网络诈骗法》《互联网信息服务管理办法》&#xff08;国务院令第…...

ES 集群常用排查命令

说明&#xff1a;集群使用非默认端口9200&#xff0c;使用的是7116端口举例 一、常用命令 #1.集群健康状态 [wlsadminelastic-01~]$ curl -XGET "http://10.219.27.00:7116/_cluster/health?pretty" { cluster name":"cluster" "status"…...

Nougat 深度剖析

Nougat 深度剖析 项目地址&#xff1a;https://github.com/facebookresearch/nougat 论文地址&#xff1a;Nougat: Neural Optical Understanding for Academic Documents 0 背景 近日&#xff0c;MetaAI又放了大招&#xff0c;他们提出了一种全新的端到端的OCR模型&#x…...

ffmpeg的使用

本文章记录ffmpeg 源码下载&#xff0c;编译&#xff0c;及使用。 一、FFMPEG 源码下载解压 源码官网地址&#xff1a;http://ffmpeg.org/download.html#releases 下载最新版本ffmpeg6.0。 使用命令tar xvJf ffmpeg-6.0.tar.xz 解压。 二、了解FFMPEG源码 &#xff08;一&am…...

深度强化学习算法的参数更新时机

深度强化学习算法的参数更新时机 深度强化学习中往往涉及到多个神经网络来拟合策略函数、值函数等&#xff0c;什么时候更新参数因算法而异&#xff0c;与具体算法架构/算法思想紧密相关。 算法参数更新时机架构DQN先收集一定经验&#xff0c;然后每步更新Off Policy Value-B…...

网站服务器租赁需要什么手续/白帽seo

#131. 【NOI2015】品酒大会 统计 描述 提交 自定义测试一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战两个环节&#xff0c;分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项&#xff0c;吸引了众多品酒师参加。 在大会的晚餐上&#xff0c;调酒师…...

装修网站php源码/网站建设的公司

体验实验室简介阿里云开发者实验室&#xff0c;提供免费阿里云资源&#xff0c;丰富的云计算应用场景&#xff0c; Step by Step 完成云产品的体验阿里云体验实验室地址&#xff1a;https://developer.aliyun.com/adc/labs/教程介绍本教程将介绍如何搭建个人Leanote云笔记本。场…...

水果网站系统的建设与实现/河南品牌网络推广外包

PCB学习心得&#xff1a; (1)EJC然后输入元件的名字&#xff0c;比如R1&#xff0c;立马跳到元件的位置; (2)选择模块电路然后依次按TS&#xff0c;切换到PCB布板区域后按IL&#xff0c;用鼠标画一个矩形区域即可&#xff1b;...

做网站 对方传销/网站搜索优化官网

MVC 的思想 MVC全名是Model View Controller&#xff0c;是模型(model)&#xff0d;视图(view)&#xff0d;控制器(controller)的缩写&#xff0c;一种软件设计典范&#xff0c;用一种业务逻辑、数据、界面显示分离的方法组织代码&#xff0c;将业务逻辑聚集到一个部件里面&…...

手机网站建设技术/网络推广都需要做什么

一、打开输入法窗口:InputMethodManager inputMethodManager (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);// 接受软键盘输入的编辑文本或其它视图imm.showSoftInput(this,InputMethodManager.SHOW_FORCED);二、关闭输入法窗口InputMethodManager in…...

成都智能建站模板/优化大师app

##前言 通信&#xff0c;是指人与人、人与物、物与物之间通过某种媒介和行为进行的信息传递与交流。 网络通信&#xff0c;是指终端设备之间通过计算机网络进行的通信。 两台计算机通过一根网线相连&#xff0c;就组成了一个最简单的网络。 由一台路由器&#xff08;或交换机…...