'adding a div inside a JavaScript and CSS game which is using canvas and context

I have the following code for a beginner's flappy bird game, but am struggling to understand how to add a green-yellow block (using css and an html div and id) into the existing game which is using the context and canvas.

I have this code so far, and wish to insert into it (on the drawn canvas which is 400 by 400) a green-yellow block as generated by this css:

I want to add this in the html:

  <div id="block"></div>

with this CSS:

<style>
#block{
    width: 50px;
    height: 500px;
    background-color: greenyellow;
    position: relative;
    left: 400px;
    animation: block 2s infinite linear;
}
@keyframes block{
    0%{left:400px}
    100%{left:-50px}
}
</style>

The code I have currently is here (all in one file):

<body style="height: 100vh; background: #111; text-align: center;">
  <canvas id="c" width="400" height="400"></canvas>
          
  <script>
      
    //set up context
    context = c.getContext("2d");
    //create bird
    const bird = new Image();
    bird.src = "bird.png";
    //create variables
    var canvasSize = 400;
    var birdSize=30;
    var birdX = 0;
    var birdY =200;
    var birdDY = 0;
      
    var score = 0;
    var bestScore=0;
    var interval = 30; //the speed at which the game is played
    
    c.onclick = () => (birdDY = 9) ;
    //expand the avove out into an if statement?
      
      setInterval(() => {
      context.fillStyle = "skyblue";
      context.fillRect(0,0,canvasSize,canvasSize); // Draw sky
      birdY -= birdDY -= 0.5; // Gravity
      context.drawImage(bird, birdX, birdY, birdSize * (524/374), birdSize); // Draw bird
      context.fillStyle = "black";
      context.fillText(`Flappy Birds`, 170, 10); //x and y
      context.fillText(`Score: ${score++}`,350, 380); // Draw score
       
    }, interval)
  </script>
</body>
 

I have tried to integrate my css generated block like so, but while it does generate the blocks on the screen, they are not inside the canvas.

<style>
#block{
    width: 50px;
    height: 500px;
    background-color: greenyellow;
    position: relative;
    left: 400px;
    animation: block 2s infinite linear;
}
@keyframes block{
    0%{left:400px}
    100%{left:-50px}
}

</style>
 <body style="height: 100vh; background: #111; text-align: center;">
  <canvas id="c" width="400" height="400"></canvas>
  
  <div id="block"></div>
          
  <script>
      
    //set up context
    context = c.getContext("2d");
    //create bird
    const bird = new Image();
    bird.src = "bird.png";
    //create variables
    var canvasSize = 400;
    var birdSize=30;
    var birdX = 0;
    var birdY =200;
    var birdDY = 0;
      
    var score = 0;
    var bestScore=0;
    var interval = 30; //the speed at which the game is played
    
    c.onclick = () => (birdDY = 9) ;
    //expand the avove out into an if statement?
      
      setInterval(() => {
      context.fillStyle = "skyblue";
      context.fillRect(0,0,canvasSize,canvasSize); // Draw sky
      birdY -= birdDY -= 0.5; // Gravity
      context.drawImage(bird, birdX, birdY, birdSize * (524/374), birdSize); // Draw bird
      context.fillStyle = "black";
      context.fillText(`Flappy Birds`, 170, 10); //x and y
      context.fillText(`Score: ${score++}`,350, 380); // Draw score
       
    }, interval)
  </script>
</body>
 

For an answer, I would like a) a solution as to how to generate the css blocks INSIDE the current context/canvas b) Explanation as to the workings of it, and why this approach did not work.

I have previously never worked with context generated entities before.

c)It would also be useful to see (separately) how the same thing is achieved using context/canvas as opposed to CSS to compare which one is more efficient.

I've also tried adding the div blocks inside the interval function but that didn't work at all.

Importantly, if I continue down this line of using these two different approaches, will I be able to code in collision detection? Please explain if there are difficulties that would crop up with this approach.



Solution 1:[1]

This question might be a duplicate of Html over the Canvas?.

However...

a) Solution is to use position: absolute; instead of position: relative; and then use left and top for positioning.

b) The canvas is a DOM element as the div. There isn't really a way to overlap different DOM elements without making them absolute to the window. Using position: absolute; the block will ignore the canvas in regards to position and styling.

c) You could create the blocks using JS. If so, you would want to use something like this:

.block {
  position: absolute;
  width: 50px;
  background-color: greenyellow;
  animation: block 2s infinite linear;
}
@keyframes block{
  0%{left:400px}
  100%{left:-50px}
}
let block = document.createElement('div');
block.setAttribute('left', 400px);
block.setAttribute('top', 280px);
block.setAttribute('height', 100px);
document.appendChild(block);

Then you could change the left tag using block.style.left inside your loop. You could also get the value to make collision detection. You would also probably use unique IDs for each block or having them in an array.

However this seems to be way more complicated than just using the canvas and context.rectangle(). It is a bad idea to mix DOM and canvas in this way when you can use canvas for everything.

I think you are better of looking up a tutorial on how to use entities.

Tips:

  • The Coding Train, great tutorials. I think he have made a version of Flappy Bird.
  • Try using p5.js it is a great library for beginners but could be used for more advanced stuff. P5 is much simpler than using pure JS/Context canvas.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1