# snakeBot **Repository Path**: xwj2024/snake-bot ## Basic Information - **Project Name**: snakeBot - **Description**: 基于Springboot+Vue 的游戏对战平台 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: https://gitee.com/xwj2024 - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2023-02-19 - **Last Updated**: 2024-07-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: Java, SpringBoot, Vue, JWT, SpringSecurity ## README # Snake Of Bots ## 1 介绍 **仿北京大学Botzone棋盘游戏博弈平台中的Snake** [Botzone](https://www.botzone.org.cn/) **基于SpringBoot+Vue的游戏对战平台,主要通过控制键盘或按键来控制蛇(Snake)的移动方向,若一方撞墙或碰到对方或自己的蛇身,则游戏结束,支持人人对战、人机对战,AI对战,SnakeAI可由用户自己输入代码生成** ## 2 项目地址 [项目地址](https://xwjsnakebot.com.cn/) ## 3 技术栈 ### 3.1 前端 - **Vue3** - **VueRouter** - **VueX** - **Bootstrap** - **jQuery** ### 3.2 后端 - **Spring Boot** - **Spring Security** - **Spring Cloud** - **Mybatis-Plus** - **JWT** - **WebSocket** ### 3.3 项目部署 - **Docker** - **Nginx** ## 4 实现模块 ### 4.1 登录注册 - **登录** `SpringSecurity`+`Jwt`实现登录认证,登录认证成功后,服务端会生成token返回给客户端,客户端以后的每个请求通过携带有效期内的token来获取用户信息 - **注册** 注册的用户名和密码符合后,通过SpringSecurity的PasswordEncoder加密后存入数据库 ### 4.2 PK界面(难点) - **实现简单的匹配系统** 使用 `WebSocket`实现用户之间的匹配,用户A点击开始匹配,客户端会向服务端发送请求与信息,并携带token,WebSocketServer会先建立连接,并通过token解析出用户ID,获取该用户A的信息并存入一个线程安全的集合(**ConcurrentHashMap**:用于维护每个客户端的WebSocketServer对象),根据客户端传过来的信息,实现逻辑,将用户A存入匹配池(**CopyOnWriteArraySet**集合),等待另一个用户进入,当用户B点击开始匹配时,也会同样将用户B存入匹配池,当匹配池的用户数量大于等于2时,用户A和用户B匹配成功,服务端分别向用户A和用户B发送对手的信息 - **实现地图同步、游戏同步与多个对局同时进行** 1. **地图同步** 当两名玩家匹配成功后,在服务端生成地图,再传给两个客户端实现地图同步 2. **游戏同步** 两名玩家只知道自己的操作和蛇的移动信息,但不能看到对手的操作,所以需要每名玩家每移动一步就向服务端发送信息,服务端接收到两名玩家的移动信息后再返回给两名玩家的对手操作 3. **多个对局同时进行** 当多个对局同时进行时的处理,如果是单线程,在Game1在执行时,Game2需要等待Game1执行完后才能执行,就如下图所示,会影响用户体验,所有Game不能作为单线程处理,我们需要使用多线程来实现多名玩家同时匹配,同时进行游戏对局 ![image1](images/readme-image1-1676808375227.png) - **实现匹配系统的微服务** 使用微服务(`SpringCloud`)来处理一段独立的功能(匹配系统) ![image2](images/readme-image2.png) 匹配系统单独作为一个服务端,当客户端点击开始匹配时,先通过websocket向server端发送请求,然后server端通过**RestTemplate**向匹配系统发送HTTP请求,匹配系统接收到server端的匹配请求后,会匹配所有正在匹配的玩家,将正在匹配的玩家放入匹配池(数组),多名玩家同时匹配,所以需要开辟一个新线程,每隔一秒扫描一遍数组,判断数组中的哪两名玩家满足匹配的要求,就可以匹配成功,并移除匹配池,知道全部玩家匹配成功 - **Bot代码的执行** ![](images/readme-image5.png) 1. **** **获取两名玩家BotID,判断是否为Bot** 前面都是针对人的键盘输入来控制蛇的方向和移动,要实现AI对战,人机对战,我们不需要人的输入,而是通过代码来控制蛇的移动。将Bot代码的执行单独作为一个服务端(Bot Running System),用户可以选择亲自对战还是用Bot进行对战,匹配时,会把BotId通过**RestTemplate**传到匹配系统,匹配成功后,匹配系统返回两名玩家的ID和Bot的Id,根据BotId来判断是人操作还是AI操作, 然后接收两个玩家的下一步操作。 2. **执行Bot代码,获取下一步移动方向** 如果玩家是Bot出战,就会通过**RestTemplate**向Bot代码执行系统发送执行Bot的代码,用户ID,还有地图,两条蛇的位置,移动等信息,因为是Bot,获取下一步操作都需要向Bot Running System发送请求,我们需要让BotPool单独作为一个线程, 每一次请求都会传入Bot代码,然后在Bot Running System将Bot代码执行,返回移动方向。 3. **生产者-消费者模式** 系统需要接收每一步操作传入的Bot代码,然后执行,这里使用 **生产者-消费者模式**, 我们将每次传入的Bot代码放入一个**Queue**队列中,如果队列为空,就使用condition.await()阻塞,如果不为空就取出队头任务,消费任务,消费任务即为每一次Bot代码的执行。 4. **JOOR动态编译和执行Bot代码** 使用**Joor**动态编译和执行Java代码,执行结果为0~3的数字,表示蛇的这一步的移动方向,通过**RestTemplate**返回给主服务器,传给浏览器,执行蛇的移动,实现Bot代码操作蛇的移动 5. **Bot代码的思路** 可以通过主服务器传递过来的地图,两条蛇的身体,位置等信息,将地图信息取出来,两条蛇身体的全部坐标设为 1(障碍物),来判断上下左右四个方向哪个方向没有障碍物,从而获取到可移动的方向 ### 4.3 对局列表 **对局信息的查看** 可以查看全部的对局信息,也可以查看个人的对局信息,对局信息包括两名玩家的头像,名称,对战的结果,对战的时间,对局记录一个页面存不下,需要实现分页,使用`MybatisPlus`的**分页**实现 **录像回放功能实现** 玩家可以查看对局列表里的对战录像回放。不管是对战界面还是录像页面,都是执行相同的逻辑,只需要标记是录像还是对战,如果是录像,玩家则不需要每次移动向后端发送socket请求,只需要在每次对局时,要先把当前对战所有信息存下,包括地图信息,玩家信息,玩家位置信息,玩家操作和蛇的移动方向的集合,查看录像回放时,就是向数据库的对局记录表查询所有信息,再根据信息,恢复地图,玩家位置,执行一遍蛇的移动 ### 4.4 排行榜 每局对局结束,会计算天梯积分,排行榜会展示玩家的Bot数量,对局次数,天梯积分 ### 4.5个人中心 - **个人信息** - **我的Bot** 1. 对用户Bot信息的增删查改 2. Bot代码的输入通过引入`vue3-ace-editor`代码编辑器实现 ## 5 项目展示 ### 5.1 PC端 ![image-20230508140541584](images/image-20230508140541584.png) ![image-20230508143415680](images/image-20230508143415680.png) ![image-20230508143551308](images/image-20230508143551308.png) ![image-20230508143607095](images/image-20230508143607095.png) ![image-20230508143618064](images/image-20230508143618064.png) ![image-20230508143703852](images/image-20230508143703852.png) ![image-20230508143653291](images/image-20230508143653291.png) ### 5.2 手机端
## 6 BUG日志 > **1、Bot代码的执行** ![image-20230301225529710](images/image-20230301225529710.png) 如果两名玩家都是AI出战,那么都会执行Bot代码,都会马上拿到下一步操作(拿到锁),执行下一步操作,起初设置匹配成功后的等待时间为1000ms,对于人人对战和人机对战没有问题,蛇的移动需要两名玩家都拿到下一步操作,才能执行下一步操作,但对于两方都是AI就出现了问题,会出现蛇穿墙(下图)等问题,这是因为匹配成功后等待时间过长,两边Bot代码都执行很快,都已经拿到下一步操作,向浏览器发送下一步的移动方向,这时候蛇已经移动几步,但我们还在等待,最后就会看不到蛇的前几步移动,导致看到蛇穿墙问题 **解决:把匹配成功后的等待时间设置更短(100ms-400ms)** ![image-20230301225931520](images/image-20230301225931520.png)