skip to Main Content

I’m trying to make a 2d game with multiple maps. I am trying to make 8×8 map with squares of same size.

Here is the code for the function I have problem with. I expect that the map will be the same as the array I wrote. When I try it looks similar but it is completely off.

function loadMap(ctx, map) {
  var w = innerWidth / 8
  var x = 0
  var y = 0

  for (var i = 0; i < map.length; i++) {
    if (map[i] == 1) {
      rect(x, y, w, w, ctx, 'orange')
      x += w
    } else {
      x += w
    }

    if (Number.isInteger(i / 8)) {
      y += w
      x = 0
    }
  }
}

function rect(x, y, w, h, ctx, color = 'white') {
  ctx.beginPath()
  ctx.fillStyle = color
  ctx.fillRect(x, y, w, h)
}

const map1 = [
  1, 1, 1, 1, 1, 1, 1, 1,
  1, 0, 1, 0, 0, 0, 0, 1,
  1, 0, 1, 1, 0, 0, 0, 1,
  1, 0, 0, 0, 0, 1, 1, 1,
  1, 0, 0, 1, 1, 0, 0, 1,
  1, 0, 0, 0, 0, 0, 0, 1,
  1, 0, 0, 0, 0, 0, 0, 1,
  1, 1, 1, 1, 1, 1, 1, 1
]

loadMap(document.querySelector('#cnv').getContext('2d'), map1);
<canvas id="cnv"></canvas>

Here is the rect function:

2

Answers


  1. There are two issues in your logic, both to do with how to increment y and x.

    Firstly, 0 / 8 returns an integer, so the first iteration of the loop causes a new line to be rendered. You can also use the modulo operator for this instead of checking that the result is an integer.

    Secondly, you need to perform the new line check before you render a line’s first square.

    Also note that there’s no need for the else condition as x += w happens in both logic flows.

    function loadMap(ctx, map) {
      var w = 15; // hard-coded to fit in this demo
      var x = 0
      var y = 0
    
      for (var i = 0; i < map.length; i++) {
        if (map[i] == 1)
          rect(x, y, w, w, ctx, 'orange');
          
        x += w
        
        if (i > 0 && i % 8 === 7) {
          y += w
          x = 0
        }
      }
    }
    
    function rect(x, y, w, h, ctx, color = 'white') {
      ctx.beginPath();
      ctx.fillStyle = color;
      ctx.fillRect(x, y, w, h);
    }
    
    const map1 = [
      1, 1, 1, 1, 1, 1, 1, 1,
      1, 0, 1, 0, 0, 0, 0, 1,
      1, 0, 1, 1, 0, 0, 0, 1,
      1, 0, 0, 0, 0, 1, 1, 1,
      1, 0, 0, 1, 1, 0, 0, 1,
      1, 0, 0, 0, 0, 0, 0, 1,
      1, 0, 0, 0, 0, 0, 0, 1,
      1, 1, 1, 1, 1, 1, 1, 1
    ]
    
    loadMap(document.querySelector('#cnv').getContext('2d'), map1);
    <canvas id="cnv"></canvas>

    Note that you could keep the if condition to start the new line after the rect() call, but you would have to change the logic to something like this, which is not very intuitive:

    if (i > 0 && i % 8 === 7)
    
    Login or Signup to reply.
  2. Every 8 iterations we enter a new row. Before drawing a row’s first element, you should move the draw position (i.e. x and y) accordingly.

    With the if (Number.isInteger(i / 8)) ... statement (which sets the draw position to the start of the next row) after drawing a row’s first element, the following elements will be misplaced.

    You can fix this by either:

    • Checking for the end of a row (i.e. Number.isInteger((i + 1) / 8), or in words: "When i is one element before the next row"), or
    • Moving the if-statement to before drawing. Note: The if-statement currently advances the draw position by one row. You will have to exclude repositioning for the first row (i.e. the case i == 0), so as to not be one row off when drawing.

    Alternatively to keeping track of x and y across iterations, we can also calculate them for the given value of i:

    for (var i = 0; i < map.length; i++) {
      var x = (i % 8) * w; // How far into a row (i.e. a set of 8 elements)
      var y = Math.floor(i / 8) * w; // How many previous rows
    
      rect(x, y, w, w, ctx, 'orange');
    }
    

    Note: Here I use the remainder operator % (also called modulo operator) which returns the remainder of the implied division. You can also use the remainder operator in the if-statement, as in Rory McCrossan’s answer.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search