1

I am making a simple JS game framework and I am trying to make an image that can move around canvas with WASD. The code below should render a movable image but it doesnt do anything. Please help.

HTML

<html>
  <head>
    <title>raptorjs example</title>
    <script src="raptor.js"></script>
  </head>
  <body>
    <canvas id="canvas" width=200 height=200></canvas>
    <div style="display:none">
      <img src="player.png" alt="d" id="player">
    </div>
    <script>
      var pl = new Player("player",50,50,20,20);
      pl.Update= function(){
        var x = pl.x
        var y = pl.y
        if (Keyboard.check("w")){ y -= 1}
        if (Keyboard.check("s")){ y += 1}
        if (Keyboard.check("a")){ x -= 1}
        if (Keyboard.check("d")){ x += 1}
      }
    </script>
  </body>
</html>

JS (framework code)


var canvas = document.getElementById("canvas");
var cv = canvas.getContext("2d")
var pressedKeys = [];
function addKey(ev){
  pressedKeys.splice(0,0,ev);
}
function minKey(ev){
  var ix = pressedKeys.indexOf(ev);
  pressedKeys.splice(ix,1);
}
document.addEventListener("keydown",addKey(e.code));
document.addEventListener("keyup",minKey(e.code));

var Keyboard = new Object();
Keyboard.check = function(k){
  if (pressedKeys.indexOf(k)!= -1){
    return true;
  } else {
    return false;
  }
}
function delObj(obj){
  for (const key in obj){
    delete obj[key]
  }
}
function Player(img,lx,ly,wid,hig){
  this.x = lx;
  this.y = ly;
  this.width = wid;
  this.height = hig;
  this.Update = function(){
    //playerid.Update = yourFunction()
  }
  this.Draw = function(){
    cv.clearRect(this.x,this.y,this.width,this.height)
    var im = document.getElementById(img)
    cv.drawImage(im,this.x,this.y,this.width,this.height)
  }
  function bothf(){
    this.Draw()
    this.Update()
  }
  setInterval(bothf(),20)
}

Any help would be greatly appreciated. My main focus is getting the image to appear, but if there are any fixes to the keyboard check function that would be cool too!

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56
interpixle
  • 55
  • 7
  • ` var x = pl.x` this and the next line, are not pointers to pl.x if they are numbers (which seems so) it's only a copy of the Number which you are changing there – Scriptkiddy1337 May 13 '22 at 21:29
  • What does `doesn't do anything` mean? It renders but does not move the image? It renders but doesn't display the image? You cannot even find the canvas element in the DOM? – slebetman May 14 '22 at 01:04
  • nothing will render on the screen at all – interpixle May 15 '22 at 16:45

1 Answers1

-1

I think you have overcomplicated the keyboard interaction, the var pressedKeys = [] just to later read it again... I'm not sure where did you get that from, but I would recommend against that, all we need to do is the action right on that event.

Even if we remove the image from your code and we replace that with just drawing a square nothing shows, you should probably start with something simpler.

How about something like this:

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

function Player(x, y, color) {
  this.x = x;
  this.y = y;
  this.color = color

  this.draw = function() {
    cv.beginPath()
    cv.fillStyle = this.color;
    cv.rect(this.x, this.y, 20, 20);
    cv.fill();
  }
}

var pl1 = new Player(50, 50, "red");
var pl2 = new Player(90, 5, "blue");

window.onkeydown = (e) => {
  if (e.keyCode == 87) pl1.y -= 0.5 // "w"
  if (e.keyCode == 83) pl1.y += 0.5 // "s"
  if (e.keyCode == 65) pl1.x -= 0.5 // "a"
  if (e.keyCode == 68) pl1.x += 0.5 // "d"
};

function drawGame() { 
  cv.clearRect(0, 0, canvas.width, canvas.height)
  pl1.draw() 
  pl2.draw() 
  requestAnimationFrame(drawGame);
}
drawGame()
<canvas id="canvas" width=160 height=160></canvas>

Key points:

  • I simplified your Player to draw just a rectangle, you can certainly later use an image.
  • Your original setInterval(bothf(),20) was inside the player, that is not correct, setInterval expects a function not the output of a function. I moved that outside that way we can draw multiple elements.
  • In my tests on the keydown e.code does not evaluate to a letter like you have, instead I'm using e.keyCode to determine what key was pressed
  • For images you need to listen to the load event, once you are ready, look at the documentation examples: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#examples

If you are really serious about building a game you should consider using a game engine:
https://github.com/collections/javascript-game-engines
That will save you a lot of time!

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56
  • this works for rendering the squares however movement is not very smooth. Do you have any ideas on how to make the movement a little less stuttery? – interpixle May 15 '22 at 16:48
  • @interpixle, sure one thing you can do is reduce the speed, instead of the `+= 1` you can do `+= 0.5` I made that change on my sample, you should see the difference ... but ultimately once you have many "players" a game engine will be your best bet to improve performance – Helder Sepulveda May 15 '22 at 17:00
  • @interpixle another improvement is to use `requestAnimationFrame` instead of `setInterval`, I made that correction on the code too ... you can read more about it here: https://stackoverflow.com/questions/38709923/why-is-requestanimationframe-better-than-setinterval-or-settimeout – Helder Sepulveda May 15 '22 at 17:06