Howdy, Stranger!

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

Does Twine/Sugarcube support key input response?

What I have in mind, for Sugarcube 2, is you set up a <<set $random to random("a","b","c"...)>><<print $random>> for the alphabet, and have a random number shown on screen. Then with the time macro, the player would have a certain amount of time to press the corresponding key on the keyboard. If they pressed the wrong key or were too slow, something bad would happen.

Is this possible? Any help would be appreciated.

Comments

  • One possible way to do this is to use the jQuery one() event handling function to monitor the keyboard for a single keypress until the time has run out and then to use the off() function to stop monitoring the keyboard.

    The event type to monitor for is "keypress", and because you don't want to interfere with any other code that may be monitoring the same event type it is a good idea to add a namespace to the end of the event type so in the following example I will use a namespace of "keygame":

    The following assigns the value of any key pressed to the $keyPressed variable, only supports the letters A to Z, and only waits two seconds:
    <<set $keyPressed to "">>
    <<set $random to either("A","B","C")>>
    <<print $random>>
    
    /% Monitor for a single key press. %/
    <<run $(document)
    	.one("keydown.keygame",
    		function(ev) {
            	// Only interested in A-Z.
    			if (ev.which >= 65 && ev.which <= 90) {
    				State.variables.keyPressed = String.fromCharCode(ev.which);
    			}
    		});>>
    
    <<timed 2s>>
    	/% Stop monitoring for a keypress %/
    	<<run $(document).off("keydown.keygame");>>
    	Key Pressed was: $keyPressed
    	<<if $keyPressed is $random>>You Win!<<else>>Loser!<</if>>
    <</timed>>
    
  • greyelf wrote: »
    One possible way to do this is to use the jQuery one() event handling function to monitor the keyboard for a single keypress until the time has run out and then to use the off() function to stop monitoring the keyboard.

    The event type to monitor for is "keypress", and because you don't want to interfere with any other code that may be monitoring the same event type it is a good idea to add a namespace to the end of the event type so in the following example I will use a namespace of "keygame":

    The following assigns the value of any key pressed to the $keyPressed variable, only supports the letters A to Z, and only waits two seconds:
    <<set $keyPressed to "">>
    <<set $random to either("A","B","C")>>
    <<print $random>>
    
    /% Monitor for a single key press. %/
    <<run $(document)
    	.one("keydown.keygame",
    		function(ev) {
            	// Only interested in A-Z.
    			if (ev.which >= 65 && ev.which <= 90) {
    				State.variables.keyPressed = String.fromCharCode(ev.which);
    			}
    		});>>
    
    <<timed 2s>>
    	/% Stop monitoring for a keypress %/
    	<<run $(document).off("keydown.keygame");>>
    	Key Pressed was: $keyPressed
    	<<if $keyPressed is $random>>You Win!<<else>>Loser!<</if>>
    <</timed>>
    

    This works exactly how I imagined it when I asked the question. Thanks a bundle.
  • The <<run>> macro performs TwineScript processing on the passed expression. For what you're doing there, I'd really suggest using the <<script>> macro, as it simply executes the code as JavaScript.

    For example:
    <<script>>
    $(document).one("keydown.keygame", function(evt) {
    	// Only interested in A-Z.
    	if (evt.which >= 65 && evt.which <= 90) {
    		State.variables.keyPressed = String.fromCharCode(evt.which);
    	}
    });
    <</script>>
    
    And:
    	<<script>>$(document).off("keydown.keygame");<</script>>
    
  • ... I'd really suggest using the <<script>> macro, as it simply executes the code as JavaScript.
    I'll remember that for next time.
  • The <<run>> macro performs TwineScript processing on the passed expression. For what you're doing there, I'd really suggest using the <<script>> macro, as it simply executes the code as JavaScript.

    For example:
    <<script>>
    $(document).one("keydown.keygame", function(evt) {
    	// Only interested in A-Z.
    	if (evt.which >= 65 && evt.which <= 90) {
    		State.variables.keyPressed = String.fromCharCode(evt.which);
    	}
    });
    <</script>>
    
    And:
    	<<script>>$(document).off("keydown.keygame");<</script>>
    

    That does look quite a bit more efficient, however I'm having trouble replicated the desired effect I had with greyelf's code

    Here's greyelf's code. It's one passage with the name "z". A message shows up at the bottom saying "Key pressed was:" and tells you if you win or lose.

    <<set $keyPressed to "">>\
    <<set $random to either("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")>>\
    \
    <b>\
    <span style="color:silver">\
    <span style="font-size:72px"><<print $random>></span>\
    </span>\
    </b>\
    \
    /% Monitor for a single key press. %/\
    <<run $(document)
    .one("keydown.keygame",
    function(ev) {
    // Only interested in A-Z.
    if (ev.which >= 65 && ev.which <= 90) {
    State.variables.keyPressed = String.fromCharCode(ev.which);
    }
    });>>\

    <<timed 2s>>\
    /% Stop monitoring for a keypress %/\
    <<run $(document).off("keydown.keygame");>>
    Key Pressed was: $keyPressed
    <<if $keyPressed is $random>>\
    You Win!
    <<timed 1s>>\
    <<goto z>>\
    <</timed>>\
    <<else>>\
    Loser!
    <<timed 1s>>\
    <<goto z>>\
    <</timed>>\
    <</if>>\
    <</timed>>\

    And here's the code with the script in it, a single passage named "zx". It doesn't have the message at the bottom displaying the "Key pressed is:". It may have something to do with a simple code placement or syntax issue on my part, or it might require some reworking I'm unaware of to cooperate with the new script command.

    <<set $keyPressed to "">>\
    <<set $random to either("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")>>\
    \
    <b>\
    <span style="color:silver">\
    <span style="font-size:72px"><<print $random>></span>\
    </span>\
    </b>\
    \
    /% Monitor for a single key press. %/\
    <<script>>
    $(document).one("keydown.keygame", function(evt) {
    // Only interested in A-Z.
    if (evt.which >= 65 && evt.which <= 90) {
    State.variables.keyPressed = String.fromCharCode(evt.which);
    }
    });
    <</script>>

    <<timed 2s>>\
    /% Stop monitoring for a keypress %/\
    <script>>$(document).off("keydown.keygame");<</script>>
    Key Pressed was: $keyPressed
    <<if $keyPressed is $random>>\
    You Win!
    <<timed 1s>>\
    <<goto zx>>\
    <</timed>>\
    <<else>>\
    Loser!
    <<timed 1s>>\
    <<goto zx>>\
    <</timed>>\
    <</if>>\
    <</timed>>\
  • The <<script>> macro after the /% Stop monitoring for a keypress %/\ line is missing a < character at the start.
Sign In or Register to comment.