【muzzik教程】3.x 暂停游戏解决方案

# 前言

众所周知,我们想要全局暂停游戏的话只能调用 cc.director.pause 或者 cc.game.pause, 但这两个方法都有局限性,首先是不能排除部分节点不暂停,其次是新增节点也会随之暂停,适用性很窄

# 讲解

由于本人工作中需要用到游戏暂停效果,所以花了一上午写了个比较全面的游戏暂停方法
首先在3.x中,之前的各种管理器全部都变成了 system,而我们只需要分类管理即可,下面是运行时system
VAMT5$NL1CS1EY6B3QWF07

可以看到上图中 system 一共有5个,分别是

  • Scheduler:定时器
  • AnimationManager:动画管理器
  • TweenSystem:缓动
  • PhysicsSystem:3d物理
  • PhysicsSystem2D:2d物理

其实如果项目中用到了龙骨,还有个

  • ArmatureSystem:骨骼系统

现在开始挨个暂停…


Scheduler 定时器:

// 暂停所有对象的定时器
cc.director.getScheduler().pauseAllTargets()

AnimationManager 动画管理器:

// creator只提供了系统获取接口,并没有直接的暂停所有动画的接口,
// 但是动画系统内的 _anims 保存了当前所有动画信息,所以直接挨个pause就好
let anim_system = cc.director.getSystem(cc.AnimationManager.ID);
pause_data.anim_as.splice(0, pause_data.anim_as.length, ...anim_system["_anims"].array);
pause_data.anim_as.forEach(v1 => {
    v1.pause();
});

ArmatureSystem 骨骼系统:

// 同样也没有提供接口,不过可以另辟蹊径
pause_data.dragon_bones_as = cc.director
	.getScene()
	.getComponentsInChildren(cc.dragonBones.ArmatureDisplay);
pause_data.dragon_bones_as.forEach(v1 => {
	v1.timeScale = 0;
});

TweenSystem 缓动:

cc.TweenSystem.instance.ActionManager.pauseAllRunningActions();

PhysicsSystem2D 2d物理:

cc.PhysicsSystem2D.instance.enable = false;

PhysicsSystem 3d物理:

cc.PhysicsSystem.instance.enable = false;

按照上面的方式就可以暂停所有当前系统内运行的对象,但不会对新增的节点暂停,如果需要排除暂停节点,就需要手动恢复了

# 代码(福音书)

内部除了游戏全局的暂停和恢复,还提供了排除暂停节点,以及单个节点的暂停和恢复
game.zip (1.5 KB)

18赞

复杂了吧,对于特定对象,应该都有特定全局暂停api

1赞

那么请问你的游戏有多少个特定呢?特定又是指什么场景下使用呢?

类似cc.director.getScheduler().pauseAllTargets()这种,暂停animation用cc.ActionManager. pauseAllRunningActions()这个不行吗

cocos内置了很多控制器,应该不至于你这么麻烦

此外,你还可以通过安卓层面来解决,例如暂停activity

你看过这个帖子吗,还是只看过标题?

请你看看帖子第一句话

另外 3.x 没有 cc.ActionManager,何来的 cc.ActionManager?

请各位评论之前看完帖子,也请各位不要做云代码家!已经有人身先士卒了 :upside_down_face:

总结得挺好的,不过我设计暂停一般不喜欢彻底stop the world,一般做逻辑层面的暂停,因为更多的情景其实是,游戏主体暂停了但某些UI和互动还在可用状态。

代码里面处理了排除暂停节点,可以直接使用,而且也不会对后续实例化节点暂停,易用程度和复用程度很大

很实用,点赞

pause/resume spine animation:

import * as cc from "cc";
import * as env from "cc/env";

/**游戏 */
module gameX {
	/*---------enum_private */
	/*---------enum_public */
	/*---------var_private */
	const pause_data = new (class {
		/**暂停状态 */
		state_b = false;
		/**2d物理系统状态 */
		physics_2d_b: boolean;
		/**3d物理系统状态 */
		physics_3d_b: boolean;
		/**定时器对象列表 */
		scheduler_as: any[];
		/**动画列表 */
		anim_as: cc.AnimationState[] = [];
		/**缓动对象列表 */
		tween_target_as: any[];
		/**龙骨组件列表 */
		dragon_bones_as: cc.dragonBones.ArmatureDisplay[];
		spine_as: cc.sp.Skeleton[];

	})();
	// const pause_scene_config: project_config.scene_config_base = Object.create(null);
	/*---------var_public */
	/*---------class_private */
	/*---------class_public */
	/**暂停游戏配置 */
	export class pause_config {
		/**排除节点 */
		exclude_as?: cc.Node[];
		/**递归排除节点 */
		recu_exclude_as?: cc.Node[];
	}
	/*---------function_private */
	function recu_node_list(node_: cc.Node, result_as: cc.Node[] = []): cc.Node[] {
		if (!node_) {
			return result_as;
		}
		result_as.push(node_);
		node_.children.forEach(v1 => {
			result_as.push(v1);
			recu_node_list(v1);
		});
		return result_as;
	}
	/*---------function_public */
	/**暂停游戏 */
	export function pause(config_?: pause_config): void {
		if (pause_data.state_b) {
			return;
		}
		// 暂停定时器
		pause_data.scheduler_as = cc.director.getScheduler().pauseAllTargets();
		// 暂停当前动画
		{
			let anim_system = cc.director.getSystem(cc.AnimationManager.ID);
			pause_data.anim_as.splice(0, pause_data.anim_as.length, ...anim_system["_anims"].array);
			pause_data.anim_as.forEach(v1 => {
				v1.pause();
			});
		}
		// 暂停龙骨动画
		{
			pause_data.spine_as = cc.director
				.getScene()
				.getComponentsInChildren(cc.sp.Skeleton);
			pause_data.spine_as.forEach(v1 => {
				v1.timeScale = 0;
			});
		}

		{
			pause_data.dragon_bones_as = cc.director
				.getScene()
				.getComponentsInChildren(cc.dragonBones.ArmatureDisplay);
			pause_data.dragon_bones_as.forEach(v1 => {
				v1.timeScale = 0;
			});
		}
		// 暂停当前缓动
		pause_data.tween_target_as = cc.TweenSystem.instance.ActionManager.pauseAllRunningActions();
		// 暂停物理系统
		{
			if (cc.PhysicsSystem2D && cc.PhysicsSystem2D.instance.enable) {
				pause_data.physics_2d_b = cc.PhysicsSystem2D.instance.enable;
				cc.PhysicsSystem2D.instance.enable = false;
			}
			if (cc.PhysicsSystem && cc.PhysicsSystem.instance.enable) {
				pause_data.physics_3d_b = cc.PhysicsSystem.instance.enable;
				cc.PhysicsSystem.instance.enable = false;
			}
		}
		// 恢复排除节点
		if (config_) {
			let exclude_as: cc.Node[] = [];
			exclude_as.push(...config_.exclude_as);
			config_.recu_exclude_as?.forEach(v1 => {
				exclude_as.push(...recu_node_list(v1));
			});
			exclude_as.forEach(v1 => {
				resume_node(v1);
			});
		}
		pause_data.state_b = true;
	}
	/**恢复游戏 */
	export function resume(): void {
		// 恢复定时器
		cc.director.getScheduler().resumeTargets(pause_data.scheduler_as);
		// 恢复动画
		pause_data.anim_as.forEach(v1 => {
			if (v1.isPlaying && v1.isPaused) {
				v1.play();
			}
		});
		// 恢复龙骨动画
		pause_data.dragon_bones_as.forEach(v1 => {
			v1.timeScale = 1;
		});

		pause_data.spine_as.forEach(v1 => {
			v1.timeScale = 1;
		});

		// 恢复缓动
		cc.TweenSystem.instance.ActionManager.resumeTargets(pause_data.tween_target_as);
		// 恢复物理系统
		{
			if (pause_data.physics_2d_b) {
				cc.PhysicsSystem2D.instance.enable = pause_data.physics_2d_b;
			}
			if (pause_data.physics_3d_b) {
				cc.PhysicsSystem.instance.enable = pause_data.physics_3d_b;
			}
		}
		pause_data.state_b = false;
	}
	/**暂停节点
	 * - 物理系统需手动启用/禁用
	 */
	export function pause_node(node_: cc.Node): void;
	export function pause_node(node_as_: cc.Node[]): void;
	export function pause_node(args1_: cc.Node | cc.Node[]): void {
		let node_as: cc.Node[];
		if (Array.isArray(args1_)) {
			node_as = args1_;
		} else {
			node_as = [args1_];
		}
		node_as.forEach(v1 => {
			// 暂停定时器
			cc.director.getScheduler().pauseTarget(v1);
			// 暂停动画
			v1.getComponent(cc.Animation)?.pause();
			// 暂停龙骨
			if (v1.getComponent(cc.dragonBones.ArmatureDisplay)) {
				v1.getComponent(cc.dragonBones.ArmatureDisplay).timeScale = 0;
			}
			// 暂停缓动
			cc.TweenSystem.instance.ActionManager.pauseTarget(v1);
		});
	}
	/**恢复节点 */
	export function resume_node(node_: cc.Node): void;
	export function resume_node(node_as_: cc.Node[]): void;
	export function resume_node(args1_: cc.Node | cc.Node[]): void {
		let node_as: cc.Node[];
		if (Array.isArray(args1_)) {
			node_as = args1_;
		} else {
			node_as = [args1_];
		}
		node_as.forEach(v1 => {
			// 恢复定时器
			cc.director.getScheduler().resumeTarget(v1);
			// 恢复动画
			v1.getComponent(cc.Animation)?.resume();
			// 恢复龙骨
			if (v1.getComponent(cc.dragonBones.ArmatureDisplay)) {
				v1.getComponent(cc.dragonBones.ArmatureDisplay).timeScale = 1;
			}
			// 恢复缓动
			cc.TweenSystem.instance.ActionManager.resumeTarget(v1);
		});
	}
	/*---------logic */
}

export default gameX;

4赞

已使用,牛掰

你好吗,3.8.6 打包提示
Cannot read properties of undefined (reading ‘array’)
大概是这一段出了问题:
pause_data.anim_as.splice(0, pause_data.anim_as.length, …anim_system["_anims"].array);
请问有遇到过吗

那就是这个属性不存在,引擎改了

我看了源码发现还在的,而且在编辑器状态下和浏览器是正常。打包出来就报错。。

因为你打包开了压缩内部属性的选项

1赞

还真是这个问题,谢谢大佬