游戏开发中的暂停的设计

今天给大家分享一下,我们做微小抖小采用的游戏暂停方案的设计。

游戏暂停需求分析

1: 当角色升级的时候,需要弹出升级的选项,此时游戏需要暂停,包括子弹飞行,人物动画等。

图片

2: 开宝箱/获得游戏道具时,需要暂停游戏,然后查看当前你获得哪个道具。此时游戏也是暂停的状态,游戏中的动画,技能,粒子都暂停。

对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀

图片

3: 游戏暂停/结算时,也需要暂停游戏,不再计算与迭代;

图片

游戏引擎的暂停API能否使用?

大部分的游戏引擎都提供了暂停的API,如Cocos Creator 3.8提供的暂停API为: game.pause/game.resume; Unity提供的暂停API为: Time.timeScale = 0,暂停游戏,Time.timeScale = 1则恢复游戏。

这类API最大的问题就是让整个游戏迭代全部暂停了,包括逻辑,动画,粒子等。但是这里会出现一个问题,如果我的UI上面要带动画,比如我获得一个宝箱,要开一个宝箱,要播放一个动画特效,这时使用系统的暂停接口就无法满足需求了。所以做商业项目时,我们大概率都不会采用系统的API来直接进行暂停。

商业项目中如何针对暂停来做架构与设计

思考1:规范化业务逻辑脚本的Update调用。

通常情况下,目前主流的引擎Unity/Cocos/Laya都有脚本代码的Update,理论上来说每个Update,在设置暂停的时候都可能要停止迭代。所以写Update代码的时候要相对慎重。如果为每个Update来做暂停机制,会比较麻烦。

思考2: 游戏暂停,我们是针对战斗逻辑暂停,其它的部分可以不用暂停,这样开宝箱等动画需求时,都不会受到影响,我们只是暂停游戏的逻辑迭代+游戏角色的动画暂停,游戏世界中的粒子暂停。

针对以上的思考,我们给出的解决方案如下:

针对"游戏逻辑的迭代",我们把"暂停机制"做到战斗管理迭代的Update中。基于战斗管理的Update迭代,我们来迭代战斗中所需要的各战斗单元的逻辑迭代。每个"战斗单元的逻辑"迭代我们不写道传统组件的Update里面,而是单独的函数LogicUpdate来进行实现,在战斗管理里面统一来迭代。

    protected update(dt: number): void {        if(this.state !== FightState.Playing) { // 游戏暂停中,不做迭代计算            return;        }        // 处理上一帧的碰撞引擎的碰撞对        BulletCalcSystem.Instance.Update(dt);        // 军团策略决策        LegionCtrlSystem.Instance.Update(dt);        // 怪物策略策略        MonsterCtrlSystem.Instance.Update(dt);        // 本地导航的迭代;        this.NavSystemUpdate(dt);        // 技能与Buff迭代        this.OnSelectSkillUpdate(dt);        this.OnSkillAndBuffUpdate(dt);        // 子弹迭代        this.OnBulletsUpdate(dt);        // 同类物体的互斥控制        EntityMutexSystem.Instance.update(dt);        // 复活需要复活的军团        this.OnReviveLegionUpdate(dt);        // 角色动画同步迭代        this.CharactorAnimStatusUpdate();        // 角色血条同步        UpdateBloodSystem.update(dt);        // 子弹,角色删除回收        this.OnDeleteEntitiesUpdate();        // end        // 传送门传送Hero        if(this.isShowTransfer) {            this.OnTransferHeroUpdate();        }        // end    }

如此一来,当游戏战斗世界要暂停的时候,只要针对"游戏管理"来暂停不迭代,从而导致游戏管理的update不再迭代其它的战斗单元的"Logic Update",这样导致整个的游戏世界+游戏战斗单元全部暂停。而UI等都不会受"游戏暂停"的印象。

游戏暂停时,我们只暂停"战斗世界里面的战斗单元"的动画,特效,粒子,遍历每个战斗单元的角色上的相关组件,对这些动画组件暂停即可,不影响其它地方的动画播放。

    public FightPause() {        this.state = FightState.Paused;        // 获取所有的Spine动画组件,然后暂停动画组件        var spSkeAnimArray: sp.Skeleton[]= this.entityRoot.getComponentsInChildren(sp.Skeleton);        if(spSkeAnimArray && spSkeAnimArray.length > 0) {            for(var i = 0; i < spSkeAnimArray.length; i ++) {                spSkeAnimArray[i].paused = true;            }        }        // end        // 获取所有的Animation动画组件,然后暂停动画组件        var spAnimArray: Animation[]= this.entityRoot.getComponentsInChildren(Animation);        if(spAnimArray && spAnimArray.length > 0) {            for(var i = 0; i < spAnimArray.length; i ++) {                spAnimArray[i].pause();            }        }        // end    }
    public FightResume() {        this.state = FightState.Playing;         // 获取所有的Spine动画组件,然后暂停动画组件        var spSkeAnimArray: sp.Skeleton[]= this.entityRoot.getComponentsInChildren(sp.Skeleton);        if(spSkeAnimArray && spSkeAnimArray.length > 0) {            for(var i = 0; i < spSkeAnimArray.length; i ++) {                spSkeAnimArray[i].paused = false;            }        }        // end        // 获取所有的Animation动画组件,然后暂停动画组件        var spAnimArray: Animation[]= this.entityRoot.getComponentsInChildren(Animation);        if(spAnimArray && spAnimArray.length > 0) {            for(var i = 0; i < spAnimArray.length; i ++) {                spAnimArray[i].resume();            }        }        // end    }

总结:

游戏暂停: 

(一)针对游戏战斗世界暂停,游戏逻辑管理负责做好游戏战斗单元的暂停与恢复即可:暂停战斗单元迭代,暂停战斗单元动画,特效。

(二)战斗单元的逻辑更新迭代,不要写到传统组件的Update里面,而是新增加一个Update函数,由游戏世界管理来进行统一的迭代,这样就可以统一在游戏世界暂停的逻辑下来进行管理了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值