1
\$\begingroup\$

I am not able to draw only one HUD of my game on a separate canvas, so I do not have to redraw it to each frame, I have four functions, init(), render(), loop() and drawHUD():

init() is my function that I call when starting the game, right at the end of the script.

render() is my rendering function

loop() is my game loop function (do not notice it, I've simplified it with minimal to leave the code cleaner for reading)

drawHUD() is my function to draw HUD on Canvas HUD_CANVAS

The problem is that the code below does not work, the screen remains blank, but if I put drawHUD() inside the render() before CTX.drawImage (HUD_CANVAS, 0, 0); then it works and I can see the image on the screen, however I wish I could draw only once, not every frame, since my HUD will not always be updating.

What am I doing wrong?

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Test</title>

    <style type="text/css" media="screen">
        canvas {
            padding: 0;
            margin: auto;
            display: block;
            width: 640px;
            height: 480px;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            border: 1px solid #999;
        }
    </style>

</head>

<body>

    <canvas id="canvas" style="z-index: 0;" width="640" height="480"></canvas>
    <canvas id="hud-canvas" style="z-index: 1;" width="640" height="480"></canvas>

    <script>
    const CANVAS = document.getElementById('canvas');
    const CTX = CANVAS.getContext('2d');
    const HUD_CANVAS = document.getElementById('hud-canvas');
    const HUD_CTX = HUD_CANVAS.getContext('2d');

    function drawHUD() {
        const imgHUD = new Image();
        imgHUD.src = './hand_hud_maya.png';
        HUD_CTX.drawImage(imgHUD, 0, 0, 96, 96, 0, 0, 96, 96);
    }


    function init() {
        drawHUD();
        loop();
    }


    function render() {
        CTX.drawImage(HUD_CANVAS, 0, 0);
    }

    function loop() {
        render();
        requestAnimationFrame(loop);
    }

    init();

    </script>

</body>
</html>

Example:

https://jsfiddle.net/twkq0sn6/

Up1:

Change that part of the function, I can see the red rectangle on the screen, so I think the problem is with the drawImage() function, but I do not know what it can be, I already tested several images, I do not think it's the image.

 function drawHUD() {
     HUD_CTX.fillStyle = "red";
     HUD_CTX.fillRect(50, 50, 50, 50);
 }

the image is loaded properly, I can see in the chrome network tab the preview of it, all OK. I do not get any errors, it's hard to figure out where I'm going wrong.

\$\endgroup\$
  • \$\begingroup\$ "I am not able to draw only one HUD of my game on a separate canvas, so I do not have to redraw it to each frame" Why are you not able to do this? Can you show us your intended appearance versus what you see now? \$\endgroup\$ – DMGregory Jul 30 '18 at 11:49
  • \$\begingroup\$ @DMGregory I'm showing in the above code, when the drawHUD() function is in the loop() it works, but when it's init() does not work. \$\endgroup\$ – PerduGames Jul 30 '18 at 15:06
  • \$\begingroup\$ @DMGregory here's the example: jsfiddle.net/n3s2u60z/2 \$\endgroup\$ – PerduGames Jul 30 '18 at 16:58
1
\$\begingroup\$

Building on your answer, you definitely need to preload all your resources before even starting the game. So your process would be

preload_assets ==> Start_game

Here's an extract from this great article on asset loading in HTML5 games:

function loadImages(names, callback) {  
  var n,name,
      result = {},
      count  = names.length,
      onload = function() { if (--count == 0) callback(result); };

  for(n = 0 ; n < names.length ; n++) {
    name = names[n];
    result[name] = document.createElement('img');
    result[name].addEventListener('load', onload);
    result[name].src = "images/" + name + ".png";
  }

}

Now to run the game you pretty much do something like loadImages([...], startGameLoop);

EDIT: Always set the onload event before you set the src attribute.

Otherwise, you image could finish loading before your onload event fires which means you never get the image drawn on screen.

\$\endgroup\$
1
\$\begingroup\$

I found the error, the image was being called in drawImage() before it was loaded, unfortunately I did not receive any error that could inform me of this. But I did work by changing the function to:

function drawHUD() {
    const imgHUD = new Image();
    imgHUD.src = './my_hud_image.png';
    imgHUD.onload = function(){
        HUD_CTX.drawImage(imgHUD, 0, 0, 256, 256, 0, 0, 256, 256);
    };
    imgHUD.onerror = function(){
        alert("Image error.");
    };
}

I think it will be interesting to load all the images and hunting for their possible errors in a separate script called resources.js by example, where I load everything that is necessary for the game to run, before it starts.

to read more about Image:

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images

\$\endgroup\$
0
\$\begingroup\$
const CANVAS = document.getElementById('canvas');
const CTX = canvas.getContext('2d');
const HUD_CANVAS = document.getElementById('hud-canvas');
const HUD_CTX = canvas.getContext('2d');

Did you mean to get your HUD context from the HUD canvas, instead of from the same canvas used for the main game context?

const HUD_CTX = HUD_CANVAS.getContext('2d');
\$\endgroup\$
  • \$\begingroup\$ I typed it fast, did not realize it, but it is not that, the problem continues. \$\endgroup\$ – PerduGames Jul 30 '18 at 17:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.