Search code examples
javascriptcanvas

JS code is supposed have a player eat something, but then the object to be eaten disappears in the wrong place, canvas is 400 X 400 object is 16x16


I am unsure how to continue with this, Can I please have help? Like if it passes by or goes above the object, it just disappears. Here is my code:

const stage = document.getElementById("stage"); //Gets the canvas
const ctx = stage.getContext("2d"); //Context
var scoreval = 0 //Score
var bleachx = 0 //food x
var bleachy = 0 //food y
const playerimg = new Image(); // Create Player Image
const bleachimg = new Image(); // Create Food Image
bleachimg.src = "../IMG/bleach.png"; //Food Image file
var playerx = 0 //PlayerX
var playery = 0 //PlayerY
function draw() {
playerimg.addEventListener("load", () => {
        ctx.drawImage(playerimg,playerx,playery);
        console.log("Image Drawn");
    });
    playerimg.src = "../IMG/bob.png"; // Set source path
    
    ctx.fillText('Score: ' + scoreval, 5, (stage.height - 5));
    drawbleach() //Loads Bleach
} //Draws player

//up
window.addEventListener("keydown", (event) => {
  if (event.isComposing || event.keyCode === 37) {
    return;
  }

    ctx.clearRect(playerx,playery,playerimg.height,playerimg.width);
    playerx = playerx + 16;
    ctx.drawImage(playerimg,playerx,playery);
}); 
//right
window.addEventListener("keydown", (event) => {
  if (event.isComposing || event.keyCode === 38) {
    return;
  }
    ctx.clearRect(playerx,playery,playerimg.height,playerimg.width);
    playery = playery + 16;
    ctx.drawImage(playerimg,playerx,playery);
}); 
//up
window.addEventListener("keydown", (event) => {
  if (event.isComposing || event.keyCode === 39) {
    return;
  }
    ctx.clearRect(playerx,playery,playerimg.height,playerimg.width);
    playerx = playerx - 16;
    ctx.drawImage(playerimg,playerx,playery);
}); 
//down
window.addEventListener("keydown", (event) => {
  if (event.isComposing || event.keyCode === 40) {
    return;
  }
    ctx.clearRect(playerx,playery,playerimg.height,playerimg.width);
    playery = playery - 16;
    ctx.drawImage(playerimg,playerx,playery);
    console.log(event.keyCode);
}); 

function drawbleach () {
    bleachx = Math.abs(Math.round(Math.random() * 25 - 25 ))*16
    bleachy = Math.abs(Math.round(Math.random() * 25 - 25 ))*16
    ctx.drawImage(bleachimg,bleachx,bleachy)
}

window.addEventListener("keydown", (event) => {
if (playerx == bleachx && playery == bleachy) {
        scoreval = scoreval+1
        ctx.fillText('Score: ' + scoreval, 5, (stage.height - 5));
        drawbleach()
}
}); //checks if touching bleach when key pressed

function notify() { //doesn't matter
    alert("Hi!") 
}

So I tried reworking the code, and I got the same bug, What happens is if i go in the spots directly above the food, it disappears, and then I have to go to the food spot still. Any ideas? If you want to try it, you can, the player and food is 16x16 pxl, and the canvas is 400x400 pxl.


Solution

  • Not sure what the exact problem is since your snippet does not run out of the box, but I do see some potential issues:

    • Make sure both images are loaded before you draw them,
    • It's easier to clear the whole frame and re-render it completely, rather than just trying to clear the parts that moved
    • Watch out with multiple event listeners; it's better to add one keydown listener and update your game state in one go

    Here's a refactored snippet that seems to work as you intended:

    const stage = document.getElementById("stage"); //Gets the canvas
    const ctx = stage.getContext("2d"); //Context
    
    const PX = 16;
    const S = 20;
    
    stage.width = S * PX;
    stage.height = S * PX;
    
    var scoreval = 0 //Score
    var bleachx = S / 2 * PX;
    var bleachy = S / 2 * PX;
    const playerimg = new Image(); // Create Player Image
    const bleachimg = new Image(); // Create Food Image
    
    var playerx = 0 //PlayerX
    var playery = 0 //PlayerY
    
    
    const imageLoader = new Set([playerimg, bleachimg]);
    
    imageLoader.forEach(img => {
      img.addEventListener("load", () => {
        imageLoader.delete(img);
    
        if (imageLoader.size === 0) init();
      });
    });
    
    
    function init() {
      const LEFT = 37, UP = 38, RIGHT = 39, DOWN = 40;
      
      window.addEventListener("keydown", e => {
        if (e.isComposing) return;
        e.preventDefault();
        
        // Move player
        let dx = 0, dy = 0;
        switch(e.keyCode) {
          case DOWN: 
            dy = PX;
            break;
          case RIGHT: 
            dx = PX;
            break;
          case LEFT: 
            dx = -PX;
            break;
          case UP:
            dy = -PX;
            break;
    
        }
        
        playerx += dx;
        playery += dy;
        
        if (playerx === bleachx && playery === bleachy) {
          scoreval += 1;
          bleachx = Math.floor(Math.random() * S) * PX;
          bleachy = Math.floor(Math.random() * S) * PX;
        }
        
        
        // Render
        draw();
      });
      
      draw();
    }
    
    function draw() {
      // Clear everything
      ctx.clearRect(0, 0, stage.width, stage.height);
      
      // Draw a quick grid for debugging
      for (let c = 0; c < S; c += 1) {
        for (let r = 0; r < S; r += 1) {
          ctx.fillStyle = (c + (r % 2)) % 2 ? "#efefef" : "white"
          ctx.fillRect(c * PX, r * PX, PX, PX);
        }
      }
    
      // Draw player
      ctx.drawImage(playerimg, playerx, playery);
    
      // Draw bleach
      ctx.drawImage(bleachimg, bleachx, bleachy)
    
      // Draw score
      ctx.fillStyle = "black";
      ctx.fillText('Score: ' + scoreval, 5, (stage.height - 5));
    
    }
    
    bleachimg.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAB5JREFUOE9j/M/A8J+BAsA4agDDaBgwjIYBw7AIAwCl1B/xy1zUvwAAAABJRU5ErkJggg=="
    
    playerimg.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAB5JREFUOE9jZPjP8J+BAsA4agDDaBgwjIYBw7AIAwCV5B/xAsMbygAAAABJRU5ErkJggg==";
    <canvas id="stage" style="border: 1px solid red"></canvas>