我的意图:使用对象进行CYOA

我是Java语言的新手,并一直尝试使用this code中的this Reddit comment作为模板来制作一个简单的CYOA游戏。但是,我想使用对象(其值旨在保持不变)来存储消息和每个选择所指向的对象的各种字符串值,而不是将所有对象都放置在数组中并且必须使用using来指向它们它们在数组中的索引。我的理由是,(从理论上来说)使用“ msg_001”或“ story5_28”之类的字符串进行组织(从理论上来说)比较简单,而不必在我在中间插入一些新消息集的情况下更改一堆数字数组。

我的问题:第一个消息不再显示

基本上,我想循环回到第一个消息及其答案集,但不会。

最初的printCurrentMsg()起作用(将“消息” div的内容更改为msgText的值,并根据对象中指定的对象遍历对象的choices数组以设置“选择” div中的按钮。 currentMsg)和按钮的相应onlick属性似乎可以正常工作,直到将它们设置为显示msg_000为止。

看来,无论currentMsg的值是什么,printCurrentMsg都不会显示字符串所引用的对象,除非它最初是显示的。此外,在脚本中的各个点使用console.log后,我注意到currentMsg未被更改,并且console.log(typeof)currentMsg都使用window[currentMsg]表示前者是字符串,而后者是字符串。一个东西。我是否无意中创建了两个单独的变量?

我试过了...


...使用printCurrentMessage中的参数。
...在函数中使用currentMsg而不是window[currentMsg]
...使用圆点表示法代替括号表示法。
...使用this[]而不是window[]


我不确定这是否与asynchronicity有关,我不正确地accessing object properties,我对scope的理解存在缺陷,还是我错误地使用了全局变量。我应该使用某种回调吗?

使用“虚拟” msg_000(使另一个对象具有不同的名称但具有相同的属性)可以作为权宜之计,但我仍然不明白问题出在哪里。将所有msg_***对象放在一个数组中并通过索引号而不是字符串来引用它们也可以工作,但出于上述乏味以及我仍然不明白为什么currentMsg的值保持不变。

为了更好地阐明我的问题,here is a jsfiddle with my code,我也将其张贴在下面。



//messages
var msg_000 = { //Starts with this one, I want to be able to go back to it
  msgName: "msg_000",
  msgText: "Sup! Choose an option!",
  choices: [
    ans_000 = {
      ansText: "Climb a hill!",
      ansGoto: "msg_001" //this works
    },
    ans_001 = {
      ansText: "Skin a cat!",
      ansGoto: "msg_002" //this works
    },
    ans_002 = {
      ansText: "Build a birdhouse!",
      ansGoto: "msg_003" //this works
    }
  ]
};
var msg_001 = {
  msgName: "msg_001",
  msgText: "You summit the great snowy peaks!",
  choices: [
    ans_000 = {
      ansText: "Talk to the Recursion Guru!",
      ansGoto: "msg_000" //this doesn't work
    }
  ]
};
var msg_002 = {
  msgName: "msg_002",
  msgText: "You suffer severe lacerations to the face!",
  choices: [
    ans_000 = {
      ansText: "Start Over",
      ansGoto: "msg_000" //this doesn't work
    }
  ]
};
var msg_003 = {
  msgText: "You build a pretty average looking birdhouse. Some grackles have moved in nonetheless, placing their various knicknacks, bedding materials, and chrono-gateways within their new abode.",
  choices: [
    ans_000 = {
      ansText: "Step through the chrono-gateway!",
      ansGoto: "msg_000" //this doesn't work
    },
    ans_001 = {
      ansText: "I think I wanna climb that mountain over there.",
      ansGoto: "msg_001" //this works
    }
  ]
}

var currentMsg = "msg_000"; //the first message is "msg_000"

printCurrentMsg = function() {
  document.getElementById("message").innerHTML =
    window[currentMsg].msgText;
  //sets the message (the div with the id of "message")
  //based on the "currentMsg" variable. "currentMsg.msgText"
  //doesn't seem to work.
  var choices = "";
  for (var i = 0, l = window[currentMsg].choices.length; i < l; i++) {
    choices += "<p><button onclick='setMessage(" +
      window[currentMsg].choices[i].ansGoto + ")'>" +
      window[currentMsg].choices[i].ansText + "<br>Goto " +
      window[currentMsg].choices[i].ansGoto + "</button></p>";
    //make the buttons, sets the button's onclick
    //"setMessage" function's parameter to the the value of
    //the "ansGoto" property -> in the answers object at the
    //i/th index of the choices property array -> in the
    //"msg_(number)" object."
  };
  document.getElementById("choices").innerHTML = choices;
  //takes the value of the "choices" [local?] variable and puts
  //it in the "choices" div.
};

setMessage = function(msg) {
  window[currentMsg] = msg; //I think this is the source of all
  //my problems, it's supposed to set "currentMsg" to the value
  //of the "msg" parameter, but when I check it with
  //console.log(currentMsg) it hasn't been changed (i.e., still
  //it's initial value of "msg_000") and when I use
  //console.log(window[currentMsg]) it returns "[Object
  //object]"; using typeof shows me that "currentMsg" is a
  //string and "window[currentMsg]" is an object. I thought
  //they both were the same object, am I unintentionally
  //creating two different objects?
  printCurrentMsg(); //runs that function, seems to display the
  //messages except the ones from object "msg_000".
};

printCurrentMsg(); //Displays the initial message and choices
//from "msg_000", but after a new message is chosen it won't
//display "msg_000" if it's pointed to from an "ansGoto"
//property.

<!DOCTYPE html>
<html>

<body>

  <div id="message"></div>
  <!-- "msgText" goes here -->
  <div id="choices"></div>
  <!-- "choices" go here -->

</body>

</html>





感谢您的时间。

最佳答案

setMessage()执行window[currentMsg] = msg;时,它将替换保存消息的变量的值。例如。如果当前消息是msg_000,而您执行setMessage(msg_002),则等同于编写msg_000 = msg_002;

您真正想要做的是将currentMsg的值更改为新消息的名称。因此,您应该执行:currentMsg = msg.msgName;

您还缺少msgName中的msg_003属性。

作为最佳实践,您不应该为所有这些使用全局变量。创建自己的对象messages,然后使用messages[currentMsg]



//messages
var msg_000 = { //Starts with this one, I want to be able to go back to it
  msgName: "msg_000",
  msgText: "Sup! Choose an option!",
  choices: [
    ans_000 = {
      ansText: "Climb a hill!",
      ansGoto: "msg_001" //this works
    },
    ans_001 = {
      ansText: "Skin a cat!",
      ansGoto: "msg_002" //this works
    },
    ans_002 = {
      ansText: "Build a birdhouse!",
      ansGoto: "msg_003" //this works
    }
  ]
};
var msg_001 = {
  msgName: "msg_001",
  msgText: "You summit the great snowy peaks!",
  choices: [
    ans_000 = {
      ansText: "Talk to the Recursion Guru!",
      ansGoto: "msg_000" //this doesn't work
    }
  ]
};
var msg_002 = {
  msgName: "msg_002",
  msgText: "You suffer severe lacerations to the face!",
  choices: [
    ans_000 = {
      ansText: "Start Over",
      ansGoto: "msg_000" //this doesn't work
    }
  ]
};
var msg_003 = {
  msgName: "msg_003",
  msgText: "You build a pretty average looking birdhouse. Some grackles have moved in nonetheless, placing their various knicknacks, bedding materials, and chrono-gateways within their new abode.",
  choices: [
    ans_000 = {
      ansText: "Step through the chrono-gateway!",
      ansGoto: "msg_000" //this doesn't work
    },
    ans_001 = {
      ansText: "I think I wanna climb that mountain over there.",
      ansGoto: "msg_001" //this works
    }
  ]
}

var currentMsg = "msg_000"; //the first message is "msg_000"

printCurrentMsg = function() {
  document.getElementById("message").innerHTML =
    window[currentMsg].msgText;
  //sets the message (the div with the id of "message")
  //based on the "currentMsg" variable. "currentMsg.msgText"
  //doesn't seem to work.
  var choices = "";
  for (var i = 0, l = window[currentMsg].choices.length; i < l; i++) {
    choices += "<p><button onclick='setMessage(" +
      window[currentMsg].choices[i].ansGoto + ")'>" +
      window[currentMsg].choices[i].ansText + "<br>Goto " +
      window[currentMsg].choices[i].ansGoto + "</button></p>";
    //make the buttons, sets the button's onclick
    //"setMessage" function's parameter to the the value of
    //the "ansGoto" property -> in the answers object at the
    //i/th index of the choices property array -> in the
    //"msg_(number)" object."
  };
  document.getElementById("choices").innerHTML = choices;
  //takes the value of the "choices" [local?] variable and puts
  //it in the "choices" div.
};

setMessage = function(msg) {
  currentMsg = msg.msgName;
  printCurrentMsg(); //runs that function, seems to display the
  //messages except the ones from object "msg_000".
};

printCurrentMsg(); //Displays the initial message and choices
//from "msg_000", but after a new message is chosen it won't
//display "msg_000" if it's pointed to from an "ansGoto"
//property.

<!DOCTYPE html>
<html>

<body>

  <div id="message"></div>
  <!-- "msgText" goes here -->
  <div id="choices"></div>
  <!-- "choices" go here -->

</body>

</html>

07-25 23:07