<canvas width="300" height="200"></canvas>
canvas {
  border: 1px solid black;
}
let img = new Image();
img.src = 'https://opengameart.org/sites/default/files/Green-Cap-Character-16x18.png';
img.onload = function() {
  window.requestAnimationFrame(gameLoop);
};

let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');

const SCALE = 2;
const WIDTH = 16;
const HEIGHT = 18;
const SCALED_WIDTH = SCALE * WIDTH;
const SCALED_HEIGHT = SCALE * HEIGHT;

function drawFrame(frameX, frameY, canvasX, canvasY) {
  ctx.drawImage(img,
                frameX * WIDTH, frameY * HEIGHT, WIDTH, HEIGHT,
                canvasX, canvasY, SCALED_WIDTH, SCALED_HEIGHT);
}

const CYCLE_LOOP = [0, 1, 0, 2];
let currentLoopIndex = 0;
let frameCount = 0;
const FRAME_LIMIT = 12;

const FACING_DOWN = 0;
const FACING_UP = 1;
const FACING_LEFT = 2;
const FACING_RIGHT = 3;
let currentDirection = FACING_DOWN;

let keyPresses = {};

window.addEventListener('keydown', keyDownListener);
function keyDownListener(event) {
    keyPresses[event.key] = true;
}

window.addEventListener('keyup', keyUpListener);
function keyUpListener(event) {
    keyPresses[event.key] = false;
}

const MOVEMENT_SPEED = 1;
let positionX = 0;
let positionY = 0;

function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  let hasMoved = false;
  
  if (keyPresses.w) {
    positionY -= MOVEMENT_SPEED;
    currentDirection = FACING_UP;
    hasMoved = true;
  } else if (keyPresses.s) {
    positionY += MOVEMENT_SPEED;
    currentDirection = FACING_DOWN;
    hasMoved = true;
  }

  if (keyPresses.a) {
    positionX -= MOVEMENT_SPEED;
    currentDirection = FACING_LEFT;
    hasMoved = true;
  } else if (keyPresses.d) {
    positionX += MOVEMENT_SPEED;
    currentDirection = FACING_RIGHT;
    hasMoved = true;
  }
  
  if (hasMoved) {
    frameCount++;
    if (frameCount >= FRAME_LIMIT) {
      frameCount = 0;
      currentLoopIndex++;
      if (currentLoopIndex >= CYCLE_LOOP.length) {
        currentLoopIndex = 0;
      }
    }
  }
  
  drawFrame(CYCLE_LOOP[currentLoopIndex], currentDirection, positionX, positionY);
  window.requestAnimationFrame(gameLoop);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.