查看原文
其他

全套源码丨超实用的双人联机对战游戏开发分享,拒绝踩坑!

老王 COCOS 2022-06-10

在手游市场高度同质化的趋势下,随着各家手机厂商纷纷布局智慧大屏、平板、PC 等不同形态的设备,强调系统与生态侧的场景协同就成为了发展刚需,多终端协同游戏针对游戏体验本身,带来玩法上的更多可能性。


Cocos 官方 Demo Team 推出双人实时联机对战类游戏《别动我的金币》,项目完整开源,含工程源码、美术资源、策划文档(核心逻辑、技能设定、UI 说明),支持 Cocos Creator 3.3.2点击文末【阅读原文】即可跳转下载地址。



在游戏中,玩家通过虚拟摇杆控制角色移动并吃掉金币,所获金币越多,角色体积越大,移动速度也就越缓慢。玩家还可以捡起随机掉落在场上的锤子,攻击对手让其失去一半金币。


官方出品,项目结构与代码质量自然不必多说,手握《幽灵射手》的小伙伴们应该有所了解。而本次《别动我的金币》的工程源码从结构上分为了逻辑层和表现层,相信能为大家在进行游戏项目结构管理时提供一些思路参考。


  • 逻辑层:管理房间创建、接受房间信息、模型相交检测、道具生成删除、玩家移动、玩家使用锤子攻击、游戏开始结束等。

  • 表现层:管理实际看到的玩家、道具、箱子、UI 界面等, 并根据接收到的最新的逻辑层数据进行刷新状态。


联机游戏一向是游戏市场的热门品类之一,去年老王也写过一个联机对战棋牌游戏《开心鼠吃象》,但由于项目初期没有考虑到玩家掉线以及断线重连、时间同步等需求,走了不少弯路……所以这一次,我们就从联机同步的实现说起,看看《别动我的金币》中都有哪些可以参考的技术方案。


联机同步


游戏的服务端选用了腾讯云游戏联机对战引擎(MGOBE),开发者无需关注底层网络架构、网络通信、服务器扩缩容、运维等,即可获得就近接入、低延迟、实时扩容的高性能联机对战服务。


游戏联机对战引擎-腾讯云:

https://cloud.tencent.com/document/product/1038


在工程中,我们也封装了一个名为 mgobeUtil.ts 的文件。调用相关接口,即可快速实现加入房间、房间管理和帧同步的相关功能。



接着谈谈游戏的同步逻辑。研究源码后我惊讶地发现,这个游戏只通过 MgobeUtil.instance.sendFrame 方法派发了三种事件:移动、停止、攻击,而移动时也只传了一个参数:前进方向。



这样真能保证多方同步么?


Demo Team 的设计思路是:


  1. 游戏开始时,地图上的障碍、角色和道具数量、所在位置是固定的,而在游戏过程中,道具的刷新时间和位置等计算,统一使用服务端提供的随机数种子,可以保证所有玩家设备上的道具刷新时间和位置一致。

  2. 游戏中角色的移动速度,通过与角色当前身上的金币数计算而成,所以在移动时仅需要传递角色的方向。而角色是否因碰撞影响移动,将由本地做碰撞检测等计算而成。而网络波动、断线重连等情况可以通过补帧处理


于是,游戏就在仅派发极少量信息的情况下,做到了多设备的实时同步。


补帧问题


作为帧同步游戏,玩家网络波动和断线重连带来的补帧问题也需要重视。MGOBE 提供了自动补帧方法,但也存在失败的可能,此时 Room 对象在 onAutoRequestFrameError 接口中提供回调,那么我们就需要调用到补帧方法了。



在实际使用中,我们发现还是使用手动补帧更为安全。方法中我们需要传入两个参数:


  • beginFrameId:本地已收到的最后一帧的 ID。

  • endFrameId:此时理论上的当前帧 ID,我们通过当前的设备时间与游戏开始时间之差除以帧率进行推算。


收到服务端提供的这段补帧信息后,游戏就可以继续进行了。


另外,断线重连后的同步也可以通过补帧完成。在调用手动补帧方法时,将 beginFrameId 设置为1,获取从第一帧到最近一帧的帧同步数据,就可以快速恢复游戏最新的状态了。而开发者也可以选取最后的的一些帧数据快进展示,让玩家重连后能快速回到游戏状态中。


生成道具


游戏共有2种道具:金币和锤子。游戏开始时,执行 initProps 方法,在固定位置生成初始道具。



游戏进行中还需要随机生成道具。以锤子为例,我们希望在玩家捡起锤子的3秒后,有一把新的锤子生成在地图上。这要如何实现呢?


首先,我们在 MGOBE 的 RoomInfo 房间属性中,提供了startGameTime 开始帧同步时的时间戳和 frameRate 帧率,我们可以通过它们推算出当前第 n 帧的帧时间 frameTime,以避免网络延迟造成的时间不准确。



帧时间 frameTime 大于需要创建锤子的时间 createHammerTime,则调用 generateProp 函数生成锤子道具数据,保存到 currentGameState.props 道具信息数组中,同时生成用来检测碰撞的对应虚拟锤子节点。



currentGameState.props 数据有更新的时候,通过 updateState 更新场景状态方法,在地图上对应位置生成道具。



相交检测


再来看看游戏在不使用物理引擎的情况下,如何判断角色是否与场景中的障碍或道具发生碰撞。


首先是角色与障碍的碰撞判断。地图障碍由16个 Cube 组成,如图,勾选图中的 showMesh,可以看到障碍的 MeshComponent。



角色移动时会调用 _intersectWithObstacle 函数判断是否会碰到地图上的障碍,_intersectWithObstacle 的核心逻辑是检测两个节点的 modelComponent 组件是否相交。通过传入角色节点,获得 modelComponent,然后遍历场景里的障碍获取 modelComponent 并和玩家的 modelComponent 进行相交检测。若不相交,角色才能继续移动。



第二是角色与道具的碰撞判断。角色移动时将调用 handleProp 函数,遍历地图中的道具,检测与角色是否相交。若角色与金币相交则分数加1,若角色与锤子相交则获得锤子,地图上锤子道具消失并刷新锤子的创建时间。



角色拿起锤子后,就可以向其他玩家角色发起攻击了。玩家在设备上点击攻击按键时,会通过帧同步方法,派发角色攻击动作事件。而逻辑层收到攻击动作事件后,将执行 checkAttack 方法。当满足攻击条件,该角色播放攻击动画,角色拥有的锤子数量减1;而被击打的角色将播放受击打动画,扣去分数,且调用 dropCoins 方法在角色附近掉落金币。






除了上述提到的几点,游戏还实现了摇杆控制玩家移动、微信平台玩家通过分享链接接入游戏等等,有需求的小伙伴可以去查阅源码,应该能有不少收获。


Cocos 官方 Demo Team 现已推出了多款游戏源码,同时更邀请各路大神陆续输出配套文字/视频教程。大家可以在公众号后台回复游戏名(如:幽灵射手),获取相关游戏的全套资源链接。


自研源码 list

3D 射击《幽灵射手》

io 类 3D《奔跑吧小仙女》

3D 冒险《奔跑吧巨人》

3D 推金币《金币推推推》

经典 2D 消除《天天消一消》:

https://store.cocos.com/app/detail/2905




📢📢《别动我的金币》¥9.9 限时一折秒杀中,扫描下方二维码进入 Cocos 官方微店或点击文末【阅读原文】前往 Cocos Store 下载吧!



前往 Cocos Store 下载源码

https://store.cocos.com/app/detail/3359


双十二年终大促来啦!




>> 点击查看嘉宾及演讲主题


12月18日下午14:00Cocos 开发者沙龙「厦门站」将在厦门香格里拉酒店举办。Cocos 引擎、亚马逊云科技、网易易盾、青瓷游戏、风领科技围绕引擎技术与生态、游戏开发与发行等内容,为各位开发者准备了一场干货盛宴。


报名来到现场的小伙伴,还将获得「Cocos 最新定制周边大礼包」,人手一份哦!扫描下方二维码免费报名吧↓


>> 开发者报名通道


往期精彩

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存