这是我计划用于未来游戏开发的状态机。
有了这样的东西,你应该能够实现不同状态的绘制,以及回调中的状态变化。通过显示/隐藏 div,或在画布上绘制不同的缓冲区/图形。
创建状态:
// initially hide the divs using css or js
state.add("welcome",
function () {
document.getElementById("Welcome").style.display = "block";
},
function () {
document.getElementById("Welcome").style.display = "none";
}
);
state.add("level01",
function () {
document.getElementById("Game").style.display = "block";
},
function () {
document.getElementById("Game").style.display = "none";
}
);
state.add("end",
function () {
document.getElementById("GameOver").style.display = "block";
}
);
第二个功能是可选的(实际上两者都是,但这样的状态不会做任何事情)。
切换状态(假设我们添加了 3 个状态:“welcome”、“level01”和“end”):
state.enter("welcome");
//... at some point welcome changes state using following:
state.enter("level01");
//... at the end of level1:
state.enter("end");
代码:
var state = (function () {
"use strict";
var currentState = -1,
stateNames = [],
stateCallbacks = [];
return {
current: function () {
if (currentState >= 0) {
return stateNames[currentState];
}
},
add: function (name, onEnter, onExit) {
var index = stateNames.indexOf(name);
if (index !== -1) {
throw "State " + name + " already exist!";
}
stateCallbacks.push({
enterState: onEnter || false,
exitState: onExit || false
});
stateNames.push(name);
},
remove: function (name) {
var index = stateNames.indexOf(name);
if (index === -1) {
throw "State " + name + " not found!";
}
stateNames.splice(index, 1);
stateCallbacks.splice(index, 1);
},
enter: function (name) {
var index = stateNames.indexOf(name);
if (index === -1) {
throw "State " + name + " not found!";
}
if (stateCallbacks[currentState].exitState) {
stateCallbacks[currentState].exitState();
}
currentState = index;
if (stateCallbacks[index].enterState) {
stateCallbacks[index].enterState();
}
},
exit: function () {
if (currentState === -1) {
throw "Not currently in any state";
}
if (stateCallbacks[currentState].exitState) {
stateCallbacks[currentState].exitState();
}
currentState = -1;
}
};
}());
附加评论:
包装代码的匿名函数的结构是来自http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html的 javascript 模块模式。这类似于其他语言中的命名空间。
为了可能获得更好的查找性能(在此处实现为 Array.indexOf(name)),您可能希望添加一个带有与索引值关联的字符串键的对象,尤其是对于大量状态(即具有 100 多个级别的游戏,或一个不同的用例,其中状态切换得更频繁)。不过,我没有对此进行基准测试,因此这是高度投机的。理论上,数组搜索比哈希表查找慢 n - 1 倍(对象可能被实现为)。
编辑:
- 修复了代码中的错误。state.add 现在检查现有名称。
- 添加了免责声明。
- 添加了如何在回调中显示/隐藏 div 的示例。
- 删除免责声明,用改进版本替换代码。