5

When I move the object, it's slow and doesn't move in diagonal, only up, down, right and left.

How can I fix this, is this a good way to start or should I do it otherwise?

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 600;
var object = {
    height: 40,
    width: 40,
    x: 10,
    y: 10, 
    color: "#FF0000"        
}

document.addEventListener('keydown', function(event) {
    //left
    if(event.keyCode == 37) {
        object.x -= 1;
    }
    //top
    else if(event.keyCode == 38) {
        object.y -= 1;
    }
    //right
    else if(event.keyCode == 39) {
        object.x += 1;
    }
    //bottom
    else if(event.keyCode == 40) {
        object.y += 1;
    }
});

function renderCanvas(){
    ctx.fillStyle = "#000000";
    ctx.fillRect(0, 0, 600, 600);
} 
function renderObject(){
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(object.x, object.y, object.width, object.height);
}
function run(){
    renderCanvas();
    renderObject();
}

setInterval(run, 10);

Here's a jsfiddle

I'm kind of a newbie in javascript and I really need help on this ;)

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Gabs
  • 63
  • 1
  • 1
  • 6
  • You might be able to animate the movement with js or css keyframes, so it moves diagonally. But you would have to do a check if 2 arrows are pushed down somehow. Like if (event.keyCode == 37 AND event.keyCode == 40)... not sure if it works though. Else you have to set a flag when an arrow is pushed down and check if the flag is active with another arrow... – Medda86 May 10 '14 at 19:44
  • Try taking out the `else if` and replacing it by ifs (otherwise the keys are always mutually exclusive). I'm not sure if that works though… – nils May 10 '14 at 19:52

5 Answers5

7

Use flags or an object with flags that is updated when keys are pressed and released:

var Keys = {
        up: false,
        down: false,
        left: false,
        right: false
    };

Then update in key events:

window.onkeydown = function(e) {
    var kc = e.keyCode;
    e.preventDefault();

    if      (kc === 37) Keys.left = true;  // only one key per event
    else if (kc === 38) Keys.up = true;    // so check exclusively
    else if (kc === 39) Keys.right = true;
    else if (kc === 40) Keys.down = true;
};

window.onkeyup = function(e) {
    var kc = e.keyCode;
    e.preventDefault();

    if      (kc === 37) Keys.left = false;
    else if (kc === 38) Keys.up = false;
    else if (kc === 39) Keys.right = false;
    else if (kc === 40) Keys.down = false;
};

This will now allow you to check keys that are pressed at the same time (if you want to move continuously you need to check status of the key object in a loop or else you will get a repeat delay):

if (Keys.up) {
    dy+=3;
}
else if (Keys.down) {  // both up and down does not work so check excl.
    dy-=3;
}

if (Keys.left) {
    dx+=3;
}
else if (Keys.right) {
    dx-=3;
}

FIDDLE

3

Flags, yes, but 2 is plenty: dx and dy:

http://jsfiddle.net/rudiedirkx/paw4X/1/

var dx = 0, dy = 0;
var speed = 100; // px per second

var activeKey = 0;
document.addEventListener('keydown', function(e) {
    if (activeKey == e.keyCode) return;
    activeKey = e.keyCode;

    //left
    if (e.keyCode == 37) {
        console.log('start moving LEFT');
        dx = -1;
    }
    //top
    else if (e.keyCode == 38) {
        console.log('start moving UP');
        dy = -1;
    }
    //right
    else if (e.keyCode == 39) {
        console.log('start moving RIGHT');
        dx = 1;
    }
    //bottom
    else if (e.keyCode == 40) {
        console.log('start moving DOWN');
        dy = 1;
    }
});
document.addEventListener('keyup', function(e) {
    switch (e.keyCode) {
        case 37: // left
        case 39: // right
            console.log('stop moving HOR');
            dx = 0;
            break;

        case 38: // up
        case 40: // down
            console.log('stop moving VER');
            dy = 0;
            break;
    }

    activeKey = 0;
});

function fun(){
    renderCanvas();

    object.x += dx / 60 * speed;
    object.y += dy / 60 * speed;
    renderObject();

    requestAnimationFrame(fun);
}
requestAnimationFrame(fun);

The ugly activeKey part is necessary, because some keyboards repeat the keydown event every X ms until the key is released.

Rudie
  • 52,220
  • 42
  • 131
  • 173
  • 1
    just to comment on the key repeat : they keyboards themselves do repeat. This might be changed by the OS if you change the settings, but browsers (guilty of many other sins) are not the bad guys here :-) – GameAlchemist May 11 '14 at 16:02
  • @GameAlchemist I didn't know that. I believe you. Thanks. – Rudie May 11 '14 at 16:05
1
    var object = {
height: 40,
width: 40,
x: 10,
y: 10, 
color: "#FF0000"        
    }

You seem to have forgotten a semicolon. Let me show you:

    var object = {
height: 40,
width: 40,
x: 10,
y: 10, 
color: "#FF0000"        
};
Karthadon
  • 11
  • 1
0

How about using the number-pad keys?

These number keys are already marked with the up/down/left/right arrowkeys so using 1,3,7,9 for diagonal moves would be understandable and convenient for the user.

To speed up your movement, you can add more than 1 pixel with each keystroke.

To move diagonally, you'll want to change both the object.x and object.y values simultaneously.

// move 4 pixels with each key

var distance=4;

// for example, move diagonally up & left
object.x-=distance;
object.y-=distance;

Here's example code and a Demo: http://jsfiddle.net/m1erickson/RnJLZ/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>
<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var distance=4;
    var object = {
        height: 40,
        width: 40,
        x: 10,
        y: 10, 
        color: "#FF0000"        
    }

    renderObject();

    document.body.onkeydown=function(event){

        switch(event.keyCode){
            case 97: // 1
                object.x-=distance;
                object.y+=distance;        
                break;
            case 98: // 2
                object.x+=0;
                object.y+=distance;
                break;
            case 99: // 3
                object.x+=distance;
                object.y+=distance;        
                break;
            case 100: // 4
                object.x-=distance;
                object.y+=0;        
                break;
            case 101: // 5
                object.x+=0;
                object.y+=0;        
                break;
            case 102: // 6
                object.x+=distance;
                object.y+=0;        
                break;
            case 103: // 7
                object.x-=distance;
                object.y-=distance;        
                break;
            case 104: // 8
                object.x+=0;
                object.y-=distance;        
                break;
            case 105: // 9
                object.x+=distance;
                object.y-=distance;        
                break;
        }

        renderObject();

    }

    function renderObject(){
        if(ctx.fillStyle!=object.color.toLowerCase()){
            console.log(ctx.fillStyle,object.color);
            ctx.fillStyle=object.color;
        }
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.fillRect(object.x,object.y,object.width,object.height);
    }


}); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
markE
  • 102,905
  • 11
  • 164
  • 176
0

I tried and it looks like you had to set flags. I came up with this: http://jsfiddle.net/medda86/y6WU9/

html

<div class="pic"></div>

css

html,body{
width:100%;
height:100%;
margin:0px;}

.pic{
position:absolute;
margin-left:100px;
margin-top:100px;
width:100px;
height:100px;
background-color:#ccc;}

jquery

// MOVE OBJECT DIAGONALLY
$(document).ready(function(){

    var movementSpeed = 10;
    var intervalSpeed = 60;
    var runAnimation = false;
    var animationSpeed = 10;

    var leftMarginLimit = parseInt($('.pic').parent().css('width')) - parseInt($('.pic').css('width'));
    var topMarginLimit = parseInt($('.pic').parent().css('height')) - parseInt($('.pic').css('height'));
    var leftMargin = parseInt($('.pic').css('margin-left'));
    var topMargin = parseInt($('.pic').css('margin-top'));
    var animationComplete = true;

    // flags
    var left = false;
    var right = false;
    var up = false;
    var down = false;

    $(document).keyup(function(key) {

        if (key.which == 37){left = false;}
        if (key.which == 39){right = false;}
        if (key.which == 38){up = false;}
        if (key.which == 40){down = false;}
    });

    $(document).keydown(function(key) {

        if (key.which == 37){left = true;}
        if (key.which == 39){right = true;}
        if (key.which == 38){up = true;}
        if (key.which == 40){down = true;}
    });




    setInterval(runMovement,intervalSpeed);

    function runMovement() {

        if (animationComplete){

            // LEFT
            if (left){
                leftMargin -=movementSpeed;
                if (leftMargin < 0){leftMargin = 0;}
                if (leftMargin > leftMarginLimit){leftMargin = leftMarginLimit;}
            }

            // RIGHT
            if (right){
                leftMargin +=movementSpeed;
                if (leftMargin < 0){leftMargin = 0;}
                if (leftMargin > leftMarginLimit){leftMargin = leftMarginLimit;}
            }

            // UP
            if (up){
                topMargin -=movementSpeed;
                if (topMargin < 0){topMargin = 0;}
                if (topMargin > topMarginLimit){topMargin = topMarginLimit;}
            }

            // DOWN
            if (down){
                topMargin +=movementSpeed;
                if (topMargin < 0){topMargin = 0;}
                if (topMargin > topMarginLimit){topMargin = topMarginLimit;}
            }

                // ANIMATION?
                if (runAnimation){
                    animationComplete = false;
                    $('.pic').animate({'margin-left': leftMargin+'px','margin-top': topMargin+'px'},animationSpeed,function(){
                        animationComplete = true;
                    });
                }
                    else{
                        $('.pic').css({'margin-left': leftMargin+'px','margin-top': topMargin+'px'});
                    }

        }
    }
});

You can change theese settings, like how fast to move object and if you wanna run the animation, and set the animationspeed. Also you cna set the interval here.. game speed :P

var movementSpeed = 10;
var intervalSpeed = 60;
var runAnimation = false;
var animationSpeed = 10;

EDIT: I had to add the setinterval, got a bit buggy the other way with keydown and keyup. Now you can move all around more smoothly :)

Medda86
  • 1,582
  • 1
  • 12
  • 19
  • 1
    Use `requestAnimationFrame()` instead of `setInterval()`. It triggers every 1/60th second, or as much as the browser can handle. You have to manually request **every** animation frame, not just the first (like `setInterval`). – Rudie May 10 '14 at 21:32