1

I am writing a simple page with JQuery and HTML5 canvas tags where I move a shape on the canvas by pressing 'w' for up, 's' for down, 'a' for left, and 'd' for right. I have it all working, but I would like the shape to start moving at a constant speed upon striking a key. Right now there is some kind of hold period and then the movement starts. How can I get the movement to occur immediately?

Here is the important part of my code:

<script src="jquery.js"></script>
<script src="JQuery.print.js"></script>    
<body>
<canvas id="myCanvas" width="500" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<br><br>
start navigating<input type="text" id = "enter"/>
<div id = "soul2">
coords should pop up here
</div>
<div id = "soul3">
key should pop up here
</div>

<script>

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
//keypress movements
var xtriggered = 0;
var keys = {};
var north = -10;
var east = 10;
var flipednorth = 0;

$(document).ready(function(e){
  $("input").keydown(function(){
    keys[event.which] = true;
    if (event.which == 13) {
         event.preventDefault();
      }
    //press w for north
    if (event.which == 87) {
         north++;
         flipednorth--;
      }
    //press s for south
    if (event.which == 83) {
         north--;
         flipednorth++;
      }
    //press d for east
     if (event.which == 68) {
         east++;
      }
    //press a for west
    if (event.which == 65) {
         east--;
      }
     var  msg = 'x: ' + flipednorth*5 + ' y: ' + east*5;
     ctx.beginPath();
     ctx.arc(east*6,flipednorth*6,40,0,2*Math.PI);
     ctx.stroke();
     $('#soul2').html(msg);
    $('#soul3').html(event.which );
     $("input").css("background-color","#FFFFCC");
  });

  $("input").keyup(function(){
    delete keys[event.which];
    $("input").css("background-color","#D6D6FF");
  });
});

</script>

please let me know if I shouldn't be posting code this lengthy.

Emanegux
  • 1,092
  • 2
  • 20
  • 38
  • likely getting error thrown in `keyup` , no `event` argument so `event.which` should throw error. The `keys` object doesn't seem to be used for anything anyway – charlietfl Nov 24 '12 at 04:13
  • I'm using chrome. Also, I get no error. I'll post the html too so you guys can understand a little better. Why the down votes? – Emanegux Nov 24 '12 at 04:24
  • charlietfl, The keys object is used for pressing two or more keys at once. I learned about it here: http://stackoverflow.com/questions/4954403/can-jquery-keypress-detect-more-than-one-key-at-the-same-time – Emanegux Nov 24 '12 at 04:34

3 Answers3

11

What you're missing is a "game loop".

Instead of reacting directly to key down or up in deciding whether and when to move your shape around the canvas, you need to use the key events to keep track of which keys are down at any given moment, and then check the key state from a setTimeout()-based loop running independent of the key events.

You've started to do that with your keys variable keeping track of whether a given key is down at any moment:

// in keydown
keys[event.which] = true;
// in keyup
delete keys[event.which];

...except that event is not defined - you need to make it a parameter of the event handler, and also none of your code ever actually checks the values in keys.

Here's a simplified version of what I'm talking about:

$(document).ready(function(e){
  var keys = {};

  $("input").keydown(function(event){
    keys[event.which] = true;
  }).keyup(function(event){
    delete keys[event.which];
  });

  function gameLoop() {
    // w for north
    if (keys[87]) {
       north++;
       flipednorth--;
    }
    //press s for south
    if (keys[83]) {
       north--;
       flipednorth++;
    }
    // etc. for other keys

    // code to move objects and repaint canvas goes here

    setTimeout(gameLoop, 20);
  }
  gameLoop();
});

Demo: http://jsfiddle.net/ktHdD/1/

The gameLoop() function will run ever 20 milliseconds or so (you can vary this as needed, but that's fast enough for reasonably smooth animation). Each time it runs it checks if any keys are down and if so adjusts the relevant position variables and repaints. If you have other objects that move around automatically (e.g., in a game there might be bad guys) you'd update them in the gameLoop() function too.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • this makes more a lot more sense to keep all the keys. my version just kept the last pressed – Popnoodles Nov 24 '12 at 05:06
  • thank you for the wonderful answer. This is very helpful to me and probably to plenty of other people too. Thank you! – Emanegux Nov 24 '12 at 05:42
  • You're welcome. (Note that I deliberately used the term "game loop" even though you didn't mention anything about your program being a game, because "game loop" is the term you want to search on for more information about this concept if you run into further problems.) – nnnnnn Nov 24 '12 at 06:08
  • there's a whole philosophy behind what you've shown above. This is going to be very significant to the rest of my journey (which is making a game haha). Thank you again for the example, I've implemented the structure of your code into my canvas and its all coming together the way I imagined. – Emanegux Nov 24 '12 at 07:32
1

It's not jQuery. You'll find the exact same delay in Notepad.

What you'll have to do is this

var keydown=false;
$(document).on('keydown', function(e){
    if (!keydown) 
    {
        keydown=e.which;
        console.log('start moving and keep moving');
    }
}).on('keyup', function(){
    console.log("stop moving");
    keydown=false;
});​
Popnoodles
  • 28,090
  • 2
  • 45
  • 53
  • that makes sense. Would you recommend any ways to get around the key delay? – Emanegux Nov 24 '12 at 04:35
  • 2
    @Douglas you haven't understood what my code does. it catches the first keypress you don't care about the rest, all you're waiting for is keyup http://jsfiddle.net/LhBk9/1/ – Popnoodles Nov 24 '12 at 04:36
  • @Drew - there is no delay, we've circumvented what the OS does. – Popnoodles Nov 24 '12 at 04:39
  • @popnoodles I like what you're thinking here, but it seems that this method does not circumvent the OS. The OS happens before the browser so as much as the browser can beg for more registered keystrokes, it can only have as many as are given. I've made a timed example to show the time that passes between each registered `keydown` event. http://jsfiddle.net/LhBk9/3/ You'll notice the time from 0-1 is consistently larger than from 1-2, 2-3, etc. – DACrosby Nov 24 '12 at 05:34
  • @Douglas You still haven't understood what the code is doing. How do I say in a different way what I said in response to your first comment? It looks for the first keypress ONLY not the OS repeat. Look at this http://jsfiddle.net/LhBk9/1/ – Popnoodles Nov 24 '12 at 20:29
  • Could you make a working example? I'm thinking what you're getting at is pretty close to @nnnnnn's gameLoop, just without the 20 millisecond delay? – DACrosby Nov 24 '12 at 20:54
0

I believe what you're seeing is the repeat rate of a key. This is set in a user's OS - not the browser. Basically, there's nothing you can do aside from ask users to change it.

http://windows.microsoft.com/en-US/windows-xp/help/adjust-the-character-repeat-rate

EDIT

This isn't the answer to your question, but I'll leave this up here because the repeat rate is still the issue. Note that @nnnnnn showed there is a viable workaround.

DACrosby
  • 11,116
  • 3
  • 39
  • 51