Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 当游戏状态包含函数时存储游戏状态_Javascript_Functional Programming_Local Storage - Fatal编程技术网

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

我正在开发一个简单的网络游戏,需要启用“保存游戏状态”,以便用户在关闭浏览器或刷新页面后可以选择停止的位置。游戏完全在浏览器中运行,并使用基本的HTML/CSS/Javascript

我目前正在使用本地存储,因为它为跨会话保存游戏状态的问题提供了一个简单的解决方案:

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好奇您是否知道游戏状态应该如何保存有关应执行哪些函数的信息?您的游戏状态