All my layers are not showing

Hello,
I’m having a problem with my map. When I create my map with three layers, only my first layer is shown. I use Tiled and a JavaScript program to display my map on the browser. I don’t know what to do.

This is what the browser shows me :
test

This is what I have in Tiled :

Can you help me please ?
Please answer me, it’s my homework for wednesday and I’m new on Tiled.

PS: sorry for my english, I’m French.

This isn’t a Tiled problem, but some issue with your rendering code in JavaScript. You’d be better off asking in a JavaScript community.

Make sure you’re:

  1. Drawing all the layers and not just the bottom layer
  2. Drawing the layers in the correct order
  3. NOT clearing your screen with white between layers
  4. Using alpha blending instead of overwriting pixels

Thank you for your message !
But it’s weird because the JS program is my teacher’s program and it works very well with his map.
I just changed the map (and the JSON file therefore).
I checked the four conditions that you mentioned but it doesn’t work. I’m gonna asking in a JS community.

Thank you again :slight_smile:

Consider posting a link to your code, perhaps someone here can find the mistake.

You are right :slight_smile: .

Here is my Javascript code :

let cnv = document.getElementById("myCanvas");
let ctx = cnv.getContext("2d");
let tilemap;
let tilemap_loaded = 0;
let tileset;
let tileset_loaded = 0;
let tileset_elts = [];
let layer;

function onload_tilemap () {
   if(this.status == 200) {
      tilemap_loaded = 1;
      tilemap = JSON.parse(this.responseText);
      let map_height = tilemap["height"];
      let map_width = tilemap["width"];
      tileset = new Image();
      tileset.src = tilemap["tilesets"][0]["image"];
      tileset.onload = function() {
         tileset_loaded = 1;
         let tileset_i = 1;
         let tileset_j = 1;
         let tileset_imageheight = tilemap["tilesets"][0]["imageheight"];
         let tileset_imagewidth = tilemap["tilesets"][0]["imagewidth"];
         let tileset_margin = tilemap["tilesets"][0]["margin"];
         let tileset_spacing = tilemap["tilesets"][0]["spacing"];
         let tileset_tileheight = tilemap["tilesets"][0]["tileheight"];
         let tileset_tilecount = tilemap["tilesets"][0]["tilecount"];

         let layer0_data = tilemap["layers"][0]["data"];
         let layer0_height = tilemap["layers"][0]["height"]; 
         let layer0_width = tilemap["layers"][0]["width"];

         let layer1_data = tilemap["layers"][1]["data"];
         let layer1_height = tilemap["layers"][1]["height"];
         let layer1_width = tilemap["layers"][1]["width"];

         let layer2_data = tilemap["layers"][2]["data"];
         let layer2_height = tilemap["layers"][2]["height"];
         let layer2_width = tilemap["layers"][2]["width"];

         //console.log(tileset_imageheight);
         //console.log(tileset_imagewidth);
         //console.log(tileset_tileheight);
         //console.log(layer0_data);
         //console.log(layer0_height);
         //console.log(layer0_width);

         let canvas = document.createElement('canvas');
         canvas.height = map_height*tileset_tileheight;
         canvas.width = map_width*tileset_tileheight;
         let context = canvas.getContext('2d');
         //ctx.drawImage(tileset, 0, 0, tileset.width, tileset.height);
         context.drawImage(tileset, 0, 0, tileset.width, tileset.height);
         let ih = 1;
         //for(let ih = 1, nh = tileset_imageheight; ih < nh; ih += (tileset_tileheight+2)) {
         //for(let iw = 1, nw = tileset_imagewidth; iw < nw; iw += (tileset_tileheight+2)) {
         for(let ih = 1, nh = tileset_imageheight; ih < nh; ih += (tileset_tileheight+2)) {
            for(let iw = 1, nw = tileset_imagewidth; iw < nw; iw += (tileset_tileheight+2)) {
               let canvas2 = document.createElement('canvas');
               canvas2.height = tileset_tileheight;
               canvas2.width = tileset_tileheight;
               let context2 = canvas2.getContext('2d');
               let canvasImageData = context.getImageData(iw, ih, tileset_tileheight, tileset_tileheight);
               let canvasData = canvasImageData.data;
               let canvasImageData2 = context2.getImageData(0, 0, tileset_tileheight, tileset_tileheight);
               let canvasData2 = canvasImageData2.data;
               for(let i = 0, n = canvasData.length; i < n; i += 4) {
                  canvasData2[i] = canvasData[i];
                  canvasData2[i + 1] = canvasData[i + 1];
                  canvasData2[i + 2] = canvasData[i + 2];
                  canvasData2[i + 3] = canvasData[i + 3];
               }
               context2.putImageData(canvasImageData2, 0,0);
               tileset_elts.push(canvas2);
               console.log(tileset_elts);
            }
         }
         //console.log(layer0_data[0]);
         //console.log(layer0_data[1]);
         
         /*gets data to draw */
         let layer0_data_i = 0;
         for(let ih = 0, nh = layer0_height; ih < nh; ih += 1) {
            for(let iw = 0, nw = layer0_width; iw < nw; iw += 1) {
               if(layer0_data[layer0_data_i] > 0) {
                  ctx.drawImage(tileset_elts[layer0_data[layer0_data_i]-1], iw*tileset_tileheight, ih*tileset_tileheight);
               }
               layer0_data_i += 1;
            }
         }
   
         let layer1_data_i = 0;
         for(let ih = 0, nh = layer1_height; ih < nh; ih += 1) {
            for(let iw = 0, nw = layer1_width; iw < nw; iw += 1) {
               if(layer1_data[layer1_data_i] > 0) {
                  ctx.drawImage(tileset_elts[layer1_data[layer1_data_i]-1], iw*tileset_tileheight, ih*tileset_tileheight);
               }
               layer1_data_i += 1;
            }
         }

      let layer2_data_i = 0;
         for(let ih = 0, nh = layer2_height; ih < nh; ih += 1) {
            for(let iw = 0, nw = layer2_width; iw < nw; iw += 1) {
               if(layer2_data[layer2_data_i] > 0) {
                  ctx.drawImage(tileset_elts[layer2_data[layer2_data_i]-1], iw*tileset_tileheight, ih*tileset_tileheight);
               }
               layer2_data_i += 1;
            }
         }
      }
   }
}

let xobj = new XMLHttpRequest();
xobj.onload = onload_tilemap;
xobj.overrideMimeType("application/json");
xobj.open("GET", "./tilemaps/sans_titre6.json", true); //json file containing the data
xobj.send();

function print(){
   //console.log(tilemap);
   //console.log(tilemap["height"]);
   //console.log(tilemap["width"]);
   //console.log(tilemap["tilewidth"]);
   //console.log(tilemap["type"]);
   //console.log(tilemap["layers"].length);
   //console.log(tilemap["layers"][0]["width"]);
   //console.log(tilemap["layers"][0]["height"]);
   //console.log(tilemap["tilesets"][0]["image"]);
   console.log(tileset.src);
   //console.log(tileset);
}

function update(timestamp) {
   if(tilemap_loaded == 1 && tileset_loaded == 1) {
      print();
      //ctx.drawImage(tileset, 100, 100, tileset.width, tileset.height);
   } 
   else {
      requestAnimationFrame(update);
   }
}
requestAnimationFrame(update);

Since I don’t have the rest of the application I can’t run this, but I looked over the code. Couldn’t find anything immediately standing out as horribly wrong (inefficient, but not wrong xP).

Have you done basic debugging? Have you checked that layers 1 and 2 and their data exist prior to drawing? You’re accessing layers without checking whether they exist, and then further using their data, which not only makes your code error-prone if the input is ever imperfect, but makes it harder to debug problems like this.

Hi,
Like I said, it’s my teacher’s code and it works for three layers even if I don’t verify the existence of layers. But you’re right it’s not complete :).

Here my JSON file :

{ "compressionlevel":-1,
 "editorsettings":
    {
     "export":
        {
         "format":"json",
         "target":"sans_titre6.json"
        }
    },
 "height":5,
 "infinite":false,
 "layers":[
        {
         "data":[1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
         "height":5,
         "id":1,
         "name":"orange",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":5,
         "x":0,
         "y":0
        }, 
        {
         "data":[0, 0, 0, 0, 0, 0, 49, 49, 49, 0, 0, 49, 0, 49, 0, 0, 49, 49, 49, 0, 0, 0, 0, 0, 0],
         "height":5,
         "id":2,
         "name":"bleu",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":5,
         "x":0,
         "y":0
        }, 
        {
         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         "height":5,
         "id":3,
         "name":"violet",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":5,
         "x":0,
         "y":0
        }],
 "nextlayerid":4,
 "nextobjectid":1,
 "orientation":"orthogonal",
 "renderorder":"left-up",
 "tiledversion":"1.4.2",
 "tileheight":16,
 "tilesets":[
        {
         "columns":8,
         "firstgid":1,
         "image":"..\/tilesets\/4 BigSet.png",
         "imageheight":432,
         "imagewidth":128,
         "margin":0,
         "name":"4 BigSet",
         "spacing":0,
         "tilecount":216,
         "tileheight":16,
         "tilewidth":16
        }],
 "tilewidth":16,
 "type":"map",
 "version":1.4,
 "width":5
}

The HTML code :

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="data:;base64,=">
  <title>json tilemap</title>
  <style>
    body {margin: 0px; padding: 0px;}
    canvas {border: 1px solid black;}
  </style>
</head>
<body>
  <canvas id="myCanvas" width="1280" height="1280"></canvas>
<script type="module" src="./js/prg.js"></script>
</body>
</html>

And the tileset I use :
4 BigSet

I have three directories : js (js code), tilesets (tileset image png) and tilemap (json file). The HTML code is outside directories.

Thank you,

Did some debugging. Your code is correctly reading the map data and correctly trying to draw the tiles. The problem is with how you handle the tileset that when you create your canvas to temporarily house the tileset, you’re making it the size of the map rather than the size of the tileset, and any tiles that don’t fit get drawn off-canvas, where you can’t access them. So, when you then draw from that canvas onto the individual tile canvases, nothing gets drawn.

         let canvas = document.createElement('canvas');
         canvas.height = map_height*tileset_tileheight;
         canvas.width = map_width*tileset_tileheight;
         let context = canvas.getContext('2d');
         //ctx.drawImage(tileset, 0, 0, tileset.width, tileset.height);
         context.drawImage(tileset, 0, 0, tileset.width, tileset.height);

Where you set the canvas width and height, you should be using the tileset’s width and height, i.e.

         canvas.height = tileset_imageheight;
         canvas.width = tileset_imagewidth;

There are also a number of other things wrong in the code, assumptions about the files that aren’t always true. For example, this code will break horribly if given non-square tiles, because every tile is assumed to be tileheight x tileheight in size, rather than tilewidth x tileheight.
Another example: your code assumes a 2px spacing and 1px margins in the tileset loops here:

         for(let ih = 1, nh = tileset_imageheight; ih < nh; ih += (tileset_tileheight+2)) {
            for(let iw = 1, nw = tileset_imagewidth; iw < nw; iw += (tileset_tileheight+2)) {

but your tileset actually has 0 spacing and 0 margins, causing the wrong tiles to be drawn even with the fixes above. You should be reading the margin and spacing data from the tileset instead of assuming it (this causes the correct tiles to be drawn).

Once these two problems are fixed, you get the correct result:
image

1 Like

Thank you so much !!! I just tried your code and it works ! :grin:

I had already tried changing the spacing and margin values but it still didn’t work. The problem was therefore with canvas.height and canvas.width.
I will do as you said ie read the margin and spacing data from the tileset instead of assuming them.

Merci :slight_smile: