在MW编辑器中,场景中脚本的执行顺序并不固定。为了更精确地控制脚本的执行顺序,可以使用以下方法:
- onAwake() 和 onStart() 方法
MWUI的脚本中有两个常用的方法,即onAwake()和onStart()。这两个方法可以用来控制脚本的初始化和启动顺序。onStart()会在所有的onAwake()被调用后再执行,通常我们会将需要前置的资源初始化等操作放在onAwake()中,以便于在onStart()时可以被正常访问。重新方法时要注意维护好父级的方法调用,否则可能会造成生产方法中的多语言适应等逻辑不能正常执行。也因为场景脚本对象没有Awake()方法,所以该方法仅适用于继承自UIBehavior的UI脚本中。
- 装饰器约束
对于场景脚本对象,可以使用如下装饰器进行调用顺序的约束。
ExecuteInOrder.ts:
type ExecutionInfo = {
order: number,
isExecuted: boolean,
isHangs: boolean,
execute: () => void
originalStart: () => void,
thisArg?: any
};
const executionQueue: ExecutionInfo[] = [];
export function executeInOrder(order: number) {
return function <T extends typeof Core.Script>(target: T) {
const originalStart = target.prototype["onStart"];
const execute = function () {
const index = executionQueue.indexOf(selfInfo);
if (index < 0) {
throw new Error("executeInOrder: selfInfo not found");
}
const prevInfo = executionQueue[index - 1];
if (prevInfo && !prevInfo.isExecuted) {
selfInfo.isHangs = true
selfInfo.thisArg = this;
return;
}
selfInfo.isExecuted = true;
selfInfo.originalStart.call(this);
let nextInfo = executionQueue[index + 1];
if (nextInfo && nextInfo.isHangs) {
nextInfo.isHangs = false;
nextInfo.isExecuted = true;
nextInfo.execute.call(nextInfo.thisArg);
}
};
const selfInfo = { order, isExecuted: false, isHangs: false, execute, originalStart } as ExecutionInfo
executionQueue.push(selfInfo);
executionQueue.sort((a, b) => a.order - b.order);
target.prototype["onStart"] = function () {
selfInfo.execute.call(this);
};
return target;
};
}
Script.ts:
import { executeInOrder } from "./ExecuteInOrder";
@executeInOrder(1)
@Core.Class
export default class Script1 extends Core.Script {
protected onStart(): void {
console.log("onStart", this.name);
}
}
executeInOrder装饰器约束了脚本的执行顺序,当脚本的onStart被执行时会检查前置的方法是否被执行过,没有则会挂起,等待前置的执行完成后再被触发执行,以达到约束的目的。
需要注意的是,虽然可以通过上述方法来控制脚本的执行顺序,但依赖脚本执行顺序可能会导致代码的性能和可维护性下降。我们在开发时应尽量避免设计过于复杂的脚本依赖关系,使用模块等方式优化代码结构和逻辑才是管理脚本的执行顺序的更好方法。
|