What steps should I take to correct the orientation of my tilemap that appears flipped when loaded from the array it was created from?

I've been struggling with a tilemap rendering issue in my HTML 5 Canvas game. For some reason, the map appears flipped both vertically and horizontally despite all my efforts to fix it using JavaScript.

Here's my code:

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);

And here's the Map Class code:

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
                    );
                };
            };
        }
    }
};

If anyone has any suggestions on how to resolve this issue, I would be extremely grateful!

Answer №1

Your 2D array utilizes Y as the primary dimension and X as the secondary dimension. This organization is due to your data being structured as an array of rows rather than an array of columns.

If you access elements using this.data[y][x], you should obtain the desired outcome.

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";
            }

            // Restructured code to avoid unnecessary repetition
            this.ctx.fillRect(
                x * this.tileSize,
                y * this.tileSize,
                this.tileSize, this.tileSize
            );
        }
    }
}

You can visualize the implementation in action through the following 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);

Answer №2

You've made a fundamental error in printing your array. The issue lies in the fact that you created your array assuming it was displayed on 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

However, when you print this on a screen using this.data[x][y], the y remains fixed at 0 and x moves from 0 to width.

First iteration:

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

So, you are printing data[0][0], data[1][0], data[2][0] (going through columns)

The correct way is data[0][1], data[0][2], data[0][3] (going through lines)

If you change the order of loops:

First iteration:

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

So, you are printing data[0][0], data[0][1], data[0][2] (going through columns)

But here's the issue... as y increases, you're actually printing in columns!!!

The solution is simple: you need to rotate your map to align it with the 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 could change x to y in:

this.data[x][y];

Take a look at the example: https://codepen.io/Luis4raujo/pen/NWbvvay

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Empower the user with the ability to interact through touch on dynamically

I am trying to make a div touchable and draggable. I have dynamically created 1 to 10 divs within another div. Currently, these divs can only be dragged using the mouse or cursor. However, I want to enable dragging through touch as well. Can anyone provi ...

Is it possible to create cloud functions for Firebase using both JavaScript and TypeScript?

For my Firebase project, I have successfully deployed around 4 or 5 functions using JavaScript. However, I now wish to incorporate async-await into 2 of these functions. As such, I am considering converting these specific functions to TypeScript. My conc ...

What are the best practices for ensuring secure PUT and DELETE requests?

For the backend of my current project, I have a question regarding security measures. As an illustration, one of the tasks involves handling various "/notes" requests. /notes => retrieve all notes belonging to the authenticated user /notes => creat ...

Leveraging strings as URLs to embed PDFs in Wordpress using PDF Embedder

I'm encountering an issue related to a Wordpress plugin called PDF Embedder, as well as concatenating/using a string with document.write. My goal is to make this code work: <script src="http://nooze.org/wp-content/uploads/scripts/dateGetter.js"> ...

Click event on Angular leaflet marker

Currently, I am using leaflet in conjunction with Angular and have a query regarding making a button clickable within a message popup. Although I understand that I need to compile the HTML, I am struggling to implement it successfully as there are no examp ...

ReactJS encountered an error: _this3.onDismissID is not defined as a function

My goal is to retrieve the latest news related to a specific search term from a website, showcase them, and provide a dismiss button next to each news item for users to easily remove them if desired. Here's a snippet of the code I'm using: import ...

The list countdown for loop only appears in the initial iteration

Hey there, I'm currently facing an issue with duplicating my JavaScript countdowns and displaying images of cards on each loop iteration. Strangely, the countdown only appears in the first instance even though it's within the loop. I'm seeki ...

What is the best way to display "No results found" in Mat-select-autocomplete?

I am working with the mat-select-autocomplete for a multiselect dropdown. When searching for values that are not in the list, I want to display a message saying "No results found". Can someone please help me achieve this? Link to Code ...

Tips for utilizing the selected option in the name attribute with Javascript or jQuery

I am looking to use the "selected" attribute in the option element based on the name attribute using JavaScript or jQuery. Essentially, I want the option with name="1" to be automatically selected when the page loads. I have attempted the following code, b ...

Tips for resolving state change issues in VUEX

I am facing an issue with making changes to the state while splicing an element from another array without affecting the state itself. To clarify, I want to remove one element from the array arrayWithFilters = [] without altering the state.selected.filte ...

Failure to display updated property value

After rendering an array of objects, I am attempting to add a new property using a function. However, the new property value is not displaying on the page even though it is present when I log the object in the console. The new property that I want to add ...

Tool for tracking response time on basic Ajax-requested webpage

Looking for an easy way to use ajax to load content onto a page. I want the loaded content to wait before appearing on the page, but using jQuery's .delay() function didn't work as expected. Any suggestions on how to achieve this? Appreciate any ...

Maximizing CSS opacity for optimal performance in image fading

I'm working on creating a smooth fade in-out effect for the images in my photo gallery by adjusting the CSS opacity value using JavaScript. However, I've noticed that this process is quite sluggish on certain computers, such as my relatively new ...

"Double the Data: A D3.js JSON Tale of Two Creators

I found inspiration from this example: http://bl.ocks.org/mbostock/1062288 to create a collapsible Force Layout. One challenge I'm facing is how to display a graph where a single node is connected to two parent nodes. father father | | ...

What is the best way to create a reusable component for a Material-UI Snackbar?

Having trouble getting my Alert component to display a message that says "Successfully submitted" in the parent component. The message doesn't seem to be showing up. AlertComponent import React, { useState } from "react"; import { Snackbar, Alert } f ...

In JavaScript, what is the best way to target the initial option element in HTML?

As a newcomer to javascript, I'm wondering how to target the first option in the HTML <option value="">Choose an image...</option> without altering the HTML itself? My thought is: memeForm.getElementById('meme-image').getElement ...

Is there a simpler method to access the source element for an event?

I'm just starting to learn JavaScript and jQuery, and right now I have the following code in my HTML: <a id="tog_table0" href="javascript:toggle_table('#tog_table0', '#hideable_table0');">show</a> After that, I hav ...

How about utilizing node.js as a peer for WebRTC?

Are there any available modules for utilizing node.js as a peer in WebRTC? I am interested in using WebRTC in a client/server manner rather than P2P for its ability to send packets unreliably (i.e. avoiding the delay caused by TCP's guarantee of packe ...

Angular directive ceases to trigger

I am currently working on implementing an infinite scrolling directive. Initially, when the page loads and I start scrolling, I can see the console log. However, after the first scroll, it stops working. It seems like it only triggers once. Can anyone poi ...

Executing polymorphism in Javascript without the use of OOP classes

In JavaScript or other object-oriented programming languages, polymorphism is achieved by creating different types. For instance: class Field {...} class DropdownField extends Field { getValue() { //implementation .... } } Imagine a library f ...