Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Do I need a JavaScript Listener? [SugarCube 2]

I'm creating several objects, and then stuffing them into an array $choices. Each object is a possible answer to a question.
<<set $answer1 = {
    		        answerNumber : 1,
			answer		: "This is choice A",
			correct		: "right",
			goNext		: "",
			points		: -1,
			feedback   	: "This isn't the correct choice."
		}
>>
<<set $answer2 = {
       		        answerNumber : 2,
			answer		: "This is choice B",
			correct		: "wrong",
			goNext		: "hacidena",
			points		: -1,
			feedback    	: "sadface"
		}
>>
<<set $answer3 = {
       		        answerNumber : 3,
			answer		: "This is choice C",
			correct		: "right",
			goNext		: "city",
			points		: 1,
			feedback 	        : "Good job!"
		}
>>
<<set $choices = [$answer1, $answer2, $answer3]>>

What I'm envisioning is a <<for>> loop that iterates through the array. It would display the possible answers using <<click>>, and then show the feedback in a <div> using <<replace>>.

Other stuff happens here, too, but I don't think any of it is part of the problem. But just in case, it might be helpful, the <<click>> also
- adds points to the score (on the first attempt only)
- #feedback's child <p> changes its class based on the answer's correctness
- the link for the next passage is set.
<div id="choices">
<<for $i to 0; $i < $choices.length; $i++>>
	<<click $choices[$i].answer>>
		<<if $attempted != true>>
  		  	<<set $totalPoints += $choices[0].points>>
  		  	<<set $attempted = true>>       
  	   <</if>>
            <<nobr>>
            <<if $choices[$i].goNext == 0>>
          	  <<replace ".feedback">>
            	<<= '<p class="' + $choices[$i].correct + '">' + $choices[$i].feedback + '</p>'>>
          	  <</replace>>
       		<<else>>
           	  <<replace ".feedback">>
            	<<= '<p class="' + $choices[$i].correct + '">' + $choices[$i].feedback + " " + '[[Continue|$choices[$i].goNext]]' + '</p>'>>  
              <</replace>>             
             <</if>>   
       <</nobr>>
	<</click>>
<</for>>
</div>

The problem (I think? Maybe?) is that variables in <<click>> aren't evaluated until the link is actually clicked, effectively making the value of $i equal to its last known value after the loop has executes. This means the feedback is the same for every single click. The feedback from $answer3 always shows, never the feedback from $answer1 or $answer2.

I'm starting to think I need to add a listener to the clicks, or maybe put a variable in the <<click>> and use a timer to check if the variable has changed. Or maybe there is an easier way? I'm not at all confident that I could attach a listener to a link created by Twine, so my fingers are crossed that someone has a better solution.

Comments

  • You are correct that the value of a variable used within the <<click>> body is not evaluated until after the click event occurs, but you can get around this issue by using a <<print>> macro to create the <<click>> and by assigning the current value of $i to a local variable within the click body. Because of the complexity of the body of you click macro I will be moving it into a sub passage.

    So the main part of your code would look like the following:
    <div id="choices">
    <<for $i to 0; $i < $choices.length; $i++>>
    	<<print "<<click $choices[$i].answer>><<set $j to " + $i + ">><<display \"Choice Logic\">><</click>>">>
    <</for>>
    </div>
    <<unset $j>>
    
    ... and the Choice Logic passage would contain a copy of the old click body with the $i variable references change to use the $j variable instead.
    <<if $attempted != true>>
    	<<set $totalPoints += $choices[0].points>>
    	<<set $attempted = true>>
    <</if>>
    <<nobr>>
    	<<if $choices[$j].goNext == 0>>
    		<<replace ".feedback">>
    			<<= '<p class="' + $choices[$j].correct + '">' + $choices[$j].feedback + '</p>'>>
    		<</replace>>
    	<<else>>
    		<<replace ".feedback">>
    			<<= '<p class="' + $choices[$j].correct + '">' + $choices[$j].feedback + " " + '[[Continue|$choices[$j].goNext]]' + '</p>'>>
    		<</replace>>
    	<</if>>
    <</nobr>>
    

    note: You can change the name of the Choice Logic passage to whatever makes sense to you, just remember to also change the <<display>> macro call in the main code.
  • Wow, that's a great solution. I still have a lot to learn, thank you!!!
Sign In or Register to comment.