使用场景
在游戏逻辑的开发中,经常需要用到某一个脚本的运行实例,典型的例如:在游戏中设置了一个分数属性,写在GamePlay脚本中,在其他脚本中需要用到这个分数属性,这时就要用到GamePlay的脚本运行实例。这里给出单例模式来获取。
使用方法
以cocos-creator为例,假设有A/B两个脚本,目标是在B中获取A的运行实例,代码如下所示:
// A.ts
export class A {
static ins: A;
score: number = 10
onLoad() {
A.ins = this
}
}
// B.ts
import { A } from "./A"
export class B {
start() {
cc.log(A.ins.score)
}
}
原理浅析
在A脚本中,使用静态变量A.ins
来存储脚本运行实例,在脚本onLoad()
过程中将脚本运行实例this
赋值给A.ins
,完成了对脚本运行实例的存储。
在B脚本中,使用对应的import
语句,调用A.ins
即可获取A脚本的运行实例了。
最佳实践
(注意:游戏开发需要不断进步和调整,这里给出的只是我个人水平下认为的最佳实践,抛砖引玉)
- 单例单例,顾名思义,仅适用于场景中只有单个脚本激活,例如GamePlay,Player等等。如果有多个相同类型的脚本同时激活,激活时会覆盖掉前1次的赋值,虽然也可以使用,但是在逻辑上会给开发者造成误解,应该是需要尽量避免的。
- 常见天坑:未赋值即调用。这是我作为游戏开发新手经常遇到的坑。注意我在粒子中写的,B在调用时是在
start()
方法中调用,如果在onLoad()
方法中调用并且B脚本在场景中挂载位置在A脚本之前的话,就会碰到这个坑。这个坑的本质上是由于脚本调用顺序导致的,虽然不是bug,但是在游戏开发新手阶段时,比较容易忽略。我会在一篇文章中单独介绍脚本的onLoad()/start()/constructor()
的调用顺序,个人给出2种处理方案:- 规范编程,在
onLoad()
中进行初始化,在start()
中进行调用。 - 避免使用
onLoad()/start()
隐式初始化,改用init()/create()
等自建函数进行显式初始化。 - 以上2种方案可以综合使用。
- 规范编程,在
- 统一命名。依照个人习惯,可以命名为
ins/instance/INS/Ins
等等,尽量使其保持一致。