How can I fix my tilemap being flipped from the array it's generated from?

65 Views Asked by At

I'm trying to render a tilemap in a game that I'm working on, but when rendering it's flipped both vertically and horizontally. I'm working on it in the HTML 5 Canvas using JavaScript. I've tried everything I can think of, but I can't seem to get rid of the issue.

Index JS:

import Map from './MapClass.js';

export var miniMapScale = .5;

var MiniMap = document.createElement("canvas");
document.body.appendChild(MiniMap);
MiniMap.width = miniMapScale * 640;
MiniMap.height = miniMapScale * 640;
MiniMap.id = "TopDownView";
var ctx = MiniMap.getContext("2d");

var TestMap = new Map([
    [1,1,1,1,1,1,1,1,1,1],
    [1,0,1,0,0,0,0,0,0,1],
    [1,0,1,0,0,0,0,0,0,1],
    [1,0,1,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,1,1,1,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,1,1,1,1,1,1,1,1,1]

]);

function drawTopDownMap() {
    ctx.clearRect(0, 0, MiniMap.width, MiniMap.height);

    TestMap.draw();

    requestAnimationFrame(drawTopDownMap);
};

requestAnimationFrame(drawTopDownMap);

Map Class JS:

import { miniMapScale } from './index.js';

export default class Map{
    constructor(mapData) {
        this.data = mapData;
        this.tileSize = miniMapScale * 64;
        this.width = this.data[0].length;
        this.height = this.data.length;
        this.ctx = document.getElementById("TopDownView").getContext("2d");
    };

    draw() {
        for(var y = 0; y < this.height; y++) {
            for(var x = 0; x < this.width; x++) {
                var wall = this.data[x][y];

                if(wall == 0) {
                    this.ctx.fillStyle = "#ffe4c4";

                    this.ctx.fillRect(
                        x * this.tileSize,
                        y * this.tileSize,
                        this.tileSize, this.tileSize
                    );
                }else if(wall == 1) {
                    this.ctx.fillStyle = "#000000";

                    this.ctx.fillRect(
                        x * this.tileSize,
                        y * this.tileSize,
                        this.tileSize, this.tileSize
                    );
                };
            };
        }
    }
};

Any help would be greatly appreciated!

2

There are 2 best solutions below

0
On BEST ANSWER

Your 2D array has Y as the first dimension and X as the second dimension. This is because your data is arranged as an array of rows, not an array of columns.

Using this.data[y][x] should provide the expected result.

draw() {
    for(var y = 0; y < this.height; y++) {
        for(var x = 0; x < this.width; x++) {
            var wall = this.data[y][x]; // instead of [x][y]

            if(wall == 0) {
                this.ctx.fillStyle = "#ffe4c4";
            } else if(wall == 1) {
                this.ctx.fillStyle = "#000000";
            }

            // Moved this out of the if statement to avoid repeated code
            this.ctx.fillRect(
                x * this.tileSize,
                y * this.tileSize,
                this.tileSize, this.tileSize
            );
        }
    }
}

Here's a working snippet:

var miniMapScale = 0.5;

class Map {
  constructor(mapData) {
    this.data = mapData;
    this.tileSize = miniMapScale * 64;
    this.width = this.data[0].length;
    this.height = this.data.length;
    this.ctx = document.getElementById('TopDownView').getContext('2d');
  }

  draw() {
    for (var y = 0; y < this.height; y++) {
      for (var x = 0; x < this.width; x++) {
        var wall = this.data[y][x];

        if (wall == 0) {
          this.ctx.fillStyle = '#ffe4c4';
        } else if (wall == 1) {
          this.ctx.fillStyle = '#000000';
        }
        this.ctx.fillRect(
          x * this.tileSize,
          y * this.tileSize,
          this.tileSize,
          this.tileSize
        );
      }
    }
  }
}

var MiniMap = document.createElement('canvas');
console.log(document);
document.body.appendChild(MiniMap);
MiniMap.width = miniMapScale * 640;
MiniMap.height = miniMapScale * 640;
MiniMap.id = 'TopDownView';
var ctx = MiniMap.getContext('2d');

var TestMap = new Map([
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [1, 0, 1, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 1, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 1, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 0, 0, 0, 0, 1, 1, 1, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]);

function drawTopDownMap() {
  ctx.clearRect(0, 0, MiniMap.width, MiniMap.height);

  TestMap.draw();

  requestAnimationFrame(drawTopDownMap);
}

requestAnimationFrame(drawTopDownMap);

0
On

You have a basic mistake in print your array. The point 1 is that u created your array considering as a screen:

[[1,1,1,1,1,1,1,1,1,1] // <- top screen
[1,0,1,0,0,0,0,0,0,1] ] //<- 1 position after top

But, when you print this in screen with this.data[x][y] the y is fix in 0 and x walk of 0 to width.

Fist interation:

x=0, y=0; 
x=1, y=0; 
x=2, y=0. 

So, you are print in data[0][0], data[1][0], data[2][0] (walking in column)

The correct is data[0][1], data[0][2], data[0][3] (walking in line)

if you change order of loops:

Fist interation:

x=0, y=0; 
x=0, y=1; 
x=0, y=2. 

So, you are print in data[0][0], data[0][1], data[0][2] (walkin in column)

But this is a problem... y is growing up then you are print in column!!!

The solution is simples: you need rotate your Map to match with code:

var TestMap = new Map([
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,1,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,1,0,1],
[1,0,0,0,0,0,0,1,0,1],
[1,0,0,0,0,0,0,1,0,1],
[1,1,1,1,1,1,1,1,1,1]
]);

Or you change x to y in:

this.data[x][y];

Look the example: https://codepen.io/Luis4raujo/pen/NWbvvay