Javascript 当游戏状态包含函数时存储游戏状态
我正在开发一个简单的网络游戏,需要启用“保存游戏状态”,以便用户在关闭浏览器或刷新页面后可以选择停止的位置。游戏完全在浏览器中运行,并使用基本的HTML/CSS/Javascript 我目前正在使用本地存储,因为它为跨会话保存游戏状态的问题提供了一个简单的解决方案:Javascript 当游戏状态包含函数时存储游戏状态,javascript,functional-programming,local-storage,Javascript,Functional Programming,Local Storage,我正在开发一个简单的网络游戏,需要启用“保存游戏状态”,以便用户在关闭浏览器或刷新页面后可以选择停止的位置。游戏完全在浏览器中运行,并使用基本的HTML/CSS/Javascript 我目前正在使用本地存储,因为它为跨会话保存游戏状态的问题提供了一个简单的解决方案: function saveGame() { window.localStorage.setItem('gameData', JSON.stringify(game)); } function loadGame() { ga
function saveGame() {
window.localStorage.setItem('gameData', JSON.stringify(game));
}
function loadGame() {
game = JSON.parse(window.localStorage.getItem('gameData'));
}
但是,我的游戏状态包括一个函数数组和一个包含函数的对象数组。当我加载上一个游戏状态时,这些函数和对象没有正确加载,因为函数无法转换为JSON(至少-不容易。我尝试过将函数字符串化()并对其求值(),尽管它们似乎存储正确,但我无法检索它们。无论哪种方式,这都感觉是一个糟糕的解决方案)
有没有更好的方法来保存和恢复包含函数的游戏状态?这是数据模型问题吗?此外,我还遇到过通过编程修改HTML的情况。HTML是否也可以存储并在以后重新加载,以便在重新加载后修改后的HTML保持不变
编辑:添加游戏对象以供参考:
function Game() {
this.player = new Player();
this.triggerFnSet = new Set();
this.tasks = [];
this.activeTask = undefined;
this.resources = { fame: {},
money: {},
beats: { instrument: "laptop",
clicksPer: 30,
xpPer: 5 },
samples: { instrument: "laptop",
resourcesPer: 25,
requiredResource: "beats",
xpPer: 50 },
notes: { instrument: "keyboard",
clicksPer: 50,
xpPer: 5 },
measures: { instrument: "keyboard",
resourcesPer: 25,
requiredResource: "notes",
xpPer: 50 }
};
this.specialResources = { songs: { instruments: ["laptop", "keyboard"],
resourcesPer: 50,
validResources: ["samples", "measures"],
xpPer: 500 }};
this.instruments = { laptop: { level: 1,
currentTempo: "slow",
tempoSpeeds: { slowest: 25,
slow: 15,
fast: 10,
fastest: 5 },
dropActive: false },
keyboard: { currentNote: undefined,
currentSong: undefined }
};
};
有问题的字段是tasks和triggerFnSet,其中任务如下所示:
function Task(name, tooltip, checkFn, failFn, startFn, tickFn, finishFn, timeToComplete) {
this.name = name;
this.tooltip = tooltip;
this.checkFn = checkFn;
this.failFn = failFn;
this.startFn = startFn;
this.tickFn = tickFn;
this.finishFn = finishFn;
this.timeToComplete = timeToComplete;
}
触发器fn如下所示,在游戏中每勾选一次就会执行一次,并在返回true后从列表中删除:
function firstBeatTrigger() {
if (game.player.stats.beats.lifetime >= 1) {
document.getElementById('beats').style.display = "block";
appendToOutputContainer("You've created your first beat. A building block to something greater.");
game.triggerFnSet.add(tenthBeatTrigger);
return true;
}
}
这似乎有效,但我不推荐它
除此之外,执行eval(“函数t(l){return l+1;}”)
//不带括号
将函数注册到window对象中,允许您调用它
t(2);
(即使它不会退回)
这似乎有效,但我不推荐它
除此之外,执行eval(“函数t(l){return l+1;}”)
//不带括号
将函数注册到window对象中,允许您调用它
t(2);
(即使它不会返回)在这种情况下,您可能需要将反序列化对象映射到包含所有函数的完整模型。也许JSON会从您首选的库中合并。此外,我认为在JSON对象中将HTML存储为值没有问题。
但是,实际上,要将功能与模型分开。所有函数都应该是一个单独的类。称之为gameEngine之类的东西。在这种情况下,您可能需要将反序列化对象映射到包含所有函数的完整模型。也许JSON会从您首选的库中合并。此外,我认为在JSON对象中将HTML存储为值没有问题。
但是,实际上,要将功能与模型分开。所有函数都应该是一个单独的类。可以称之为gameEngine或其他东西。正如前面所评论的,您的游戏状态不应该依赖于函数,但值得注意的是,函数数组可以通过引用键而不是函数来解决,并确保始终有一个包含可能函数的对象可用 因此:
a={},
a、 m=函数(){}
然后像这样调用数组a[array[1]]()
而不是array[1]()
如果没有一点重写代码,这种方法将无法轻松处理对象(除非它们只承载函数),而重写代码可以更好地用于从数据中分离逻辑的更干净的解决方案。但是,正如前面所述,您的游戏状态不应依赖函数,值得注意的是,函数数组可以通过引用键而不是函数来求解,并确保始终有一个包含可能函数的对象可用 因此:
a={},
a、 m=函数(){}
然后像这样调用数组a[array[1]]()
而不是array[1]()
如果不重写代码,这种方法将无法轻松处理对象(除非它们只承载函数),而重写代码可以更好地用于更干净的解决方案,将逻辑从数据中分离出来。首先,这里的大多数评论都是正确的,因为这主要是数据模型问题。我不打算重构模型,因此我正在考虑以下解决方法以获得正确答案: 将函数序列化为字符串引用:
function saveGame() {
var triggers = [];
game.triggerFnSet.forEach(function (trigger){
triggers.push(trigger.name);
});
// Serialize regular game data
window.localStorage.setItem('gameData', JSON.stringify(game));
// Serialize triggerFns
window.localStorage.setItem('triggers', JSON.stringify(triggers));
}
然后通过窗口对象对函数进行查找,并将其转换回函数来反序列化:
function loadGame() {
var triggers = JSON.parse(window.localStorage.getItem('triggers'));
var gameData = JSON.parse(window.localStorage.getItem('gameData'));
if (gameData !== null) {
game = gameData;
game.triggerFnSet = new Set();
triggers.forEach(function (trigger){
game.triggerFnSet.add(window[trigger]);
});
}
}
这是因为我的函数不是匿名的,存在于全局上下文中,可以通过窗口轻松访问 首先,这里的大多数评论都是正确的,因为这主要是一个数据模型问题。我不打算重构模型,因此我正在考虑以下解决方法以获得正确答案: 将函数序列化为字符串引用:
function saveGame() {
var triggers = [];
game.triggerFnSet.forEach(function (trigger){
triggers.push(trigger.name);
});
// Serialize regular game data
window.localStorage.setItem('gameData', JSON.stringify(game));
// Serialize triggerFns
window.localStorage.setItem('triggers', JSON.stringify(triggers));
}
然后通过窗口对象对函数进行查找,并将其转换回函数来反序列化:
function loadGame() {
var triggers = JSON.parse(window.localStorage.getItem('triggers'));
var gameData = JSON.parse(window.localStorage.getItem('gameData'));
if (gameData !== null) {
game = gameData;
game.triggerFnSet = new Set();
triggers.forEach(function (trigger){
game.triggerFnSet.add(window[trigger]);
});
}
}
这是因为我的函数不是匿名的,存在于全局上下文中,可以通过窗口轻松访问 游戏状态不应包含函数。您应该能够从游戏状态生成所需的任何内容,否则,它真的是游戏状态吗?是的,这是一个数据模型问题。您需要找到一种方法来表示没有函数的状态。使用函数本身并没有什么错(例如,与具有属性和方法的类实例相比),但正如您所发现的,它们很难序列化/反序列化。您能告诉我们
game
的样子吗?如果您使用的是闭包,那么无论如何都不能将它们存储为代码。将它们转换成可以解释的对象。@Bergi我已经在上面添加了游戏对象和相关对象。这些函数是在代码中正确定义的(即,它们不是匿名的),因此游戏模型可能应该以其他方式引用函数,而不是保存函数本身。@DerekPollard好奇您是否知道游戏状态应该如何保存有关应执行哪些函数的信息?您的游戏状态