Search code examples
javascriptspritetiming

Timing on a spritesheet


I made a spritesheet and coded it so it would run through it. How do I make the draw function run every second. When I made it run the function in the update function, it made the spritesheet go super fast because thats how fast the world is being updated, but I want it to update at a different speed.

(function () {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})();

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    width = 1000,
    height = 200,
    player = {
        x: width / 2,
        y: height - 15,
        width: 48,
        height: 64,
        speed: 3,
        velX: 0,
        velY: 0,
        jumping: false,
        grounded: false,
        count: 0,
        img: new Image()
    },
    keys = [],
    friction = 0.8,
    gravity = 0.3;
    player.img.src = "img/playersheet.png";
    player.img.onload = draw;
    var sprX;
    var sprY;
    setTimeout(draw, 3000);

var boxes = [];

// dimensions
boxes.push({
    x: 0,
    y: 0,
    width: 10,
    height: height
});
boxes.push({
    x: 0,
    y: height - 2,
    width: width,
    height: 50
});
boxes.push({
    x: width - 10,
    y: 0,
    width: 50,
    height: height
});

boxes.push({
    x: 120,
    y: 100,
    width: 80,
    height: 80
});
boxes.push({
    x: 250,
    y: 150,
    width: 80,
    height: 80
});
boxes.push({
    x: 400,
    y: 180,
    width: 80,
    height: 80
});
boxes.push({
    x: 270,
    y: 150,
    width: 40,
    height: 40
});

canvas.width = width;
canvas.height = height;

function draw() {
	requestAnimationFrame(draw);
	sprX = (player.count % 3) * 171;
    	sprY = Math.floor(player.count / 9) * 351;
    	ctx.drawImage(player.img, sprX, sprY, 171, 351, 50, 50, 32, 32);
    	if(player.count == 2)
    		player.count = 0;
    	else
    		player.count++;
}

function update() {
    // check keys
    if (keys[87] || keys[32]) {
        // up arrow or space
        if (!player.jumping && player.grounded) {
            player.jumping = true;
            player.grounded = false;
            player.velY = -player.speed * 2;
        }
    }
    if (keys[68]) {
        // right arrow
        if (player.velX < player.speed) {
            player.velX++;
            //player.img.src = "img/player_r.png";

        }
    }
    if (keys[65]) {
        // left arrow
        if (player.velX > -player.speed) {
            player.velX--;
            //player.img.src = "img/player.png";
        }
    }
     if (keys[83]) {
        // down arrow
            //player.img.src = "img/player_crouch.png";
    }

    player.velX *= friction;
    player.velY += gravity;

    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = "black";
    ctx.beginPath();
    
    player.grounded = false;
    for (var i = 0; i < boxes.length; i++) {
        ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
        
        var dir = colCheck(player, boxes[i]);

        if (dir === "l" || dir === "r") {
            player.velX = 0;
            player.jumping = false;

        } else if (dir === "b") {
            player.grounded = true;
            player.jumping = false;
        } else if (dir === "t") {
            player.velY *= -1;
        }

    }
    
    if(player.grounded){
         player.velY = 0;
    }
    
    player.x += player.velX;
    player.y += player.velY;

    ctx.fill();

    requestAnimationFrame(update);
}



function colCheck(shapeA, shapeB) {
    // get the vectors to check against
    var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
        vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
        // add the half widths and half heights of the objects
        hWidths = (shapeA.width / 2) + (shapeB.width / 2),
        hHeights = (shapeA.height / 2) + (shapeB.height / 2),
        colDir = null;

    // if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
    if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
        // figures out on which side we are colliding (top, bottom, left, or right)
        var oX = hWidths - Math.abs(vX),
            oY = hHeights - Math.abs(vY);
        if (oX >= oY) {
            if (vY > 0) {
                colDir = "t";
                shapeA.y += oY;
            } else {
                colDir = "b";
                shapeA.y -= oY;
            }
        } else {
            if (vX > 0) {
                colDir = "l";
                shapeA.x += oX;
            } else {
                colDir = "r";
                shapeA.x -= oX;
            }
        }
    }
    return colDir;
}

document.body.addEventListener("keydown", function (e) {
    keys[e.keyCode] = true;
});

document.body.addEventListener("keyup", function (e) {
    keys[e.keyCode] = false;
});


window.addEventListener("load", function () {
    update();
});
<head>
    <title>Platformer Game</title>
</head>
<body>
  <h3>Arrow keys to move, and space to jump</h3>
    <canvas id="canvas"></canvas>
    <style>
    canvas {
    border:1px solid #d3d3d3;
    background-color: #f1f1f1;
	}
	</style>
</body>


Solution

  • If I understand correctly your draw function is just looping through your 3x3 sprite and constantly drawing. One approach you might try is setting your own frame rate (fps) and checking the offset from your start time:

    var fps = 24;
    var msPerFrame = 1000 / fps;
    var startTime;
    
    function draw() {
      if (!startTime) startTime = Date.now();
      var elapsedTime = Date.now() - startTime;
      var spriteIndex = Math.floor(elapsedTime / msPerFrame) % 9;
    
      requestAnimationFrame(draw);
      sprX = (spriteIndex % 3) * 171;
      sprY = Math.floor(spriteIndex / 9) * 351;
      ctx.drawImage(player.img, sprX, sprY, 171, 351, 50, 50, 32, 32);
    }
    

    I made a working fiddle here using a sprite sheet that is 4x4 and tried to reuse a lot of your code so you can see what's going on.