Reading JSON Tiled map editor file and displaying to canvas

11,932

Tiled + Canvas

I looked at the Tiled+Canvas blog post on http://blog.hashrocket.com/posts/using-tiled-and-canvas-to-render-game-screens by Shane Riley. An interesting post!

Good News…I grabbed his code from his demo and I have his code working locally on my development computer.

In going through the process and in looking at your code, I think you can get your code to work by taking care of 2 issues:

1) You have a small bug in your get_tileset function.

2) You need to point all of Shane’s demo files towards files located on your local computer. I just put all these files together in a single folder (worked for me). You will need to touch these files (details below):

  • mountain.html
  • mountain.json
  • mountain.tmx
  • mountain_landscape_23.png
  • render_scene.js

Here are the details. These worked for me and they should work for you. But if not, let me know and I can post my complete code.

A Bug -- In your get_tileset(), the tileset.onload is expecting a named function or inline function, not a function call.

// not this.tileset.onload=renderLayers(this)
this.tileset.onload=renderLayers;    

// change the signature of renderLayers 
// (you have “layers” in scope for visibility in this function so this s/b ok)
// So: not function renderLayers(layers)
function renderLayers()    

Please include an error catcher in your $.getJSON so you get visibility on failed requests!

$.getJSON('maps/'+ name + '.json', function(json){
        get_tileset(json);
}).fail( alert(“I think you should know that something has gone horribly wrong!”);  );

Here are the changes required to localize your files.

In mountain.html:

    <script src="render_scene.js" type="text/javascript"></script>

In render_scene.js (if you downloaded from the Gist)

load: function(name) {
  return $.ajax({
    url: "mountain.json",
    dataType: "text json"
  }).done($.proxy(this.loadTileset, this));
}

In mountain.json:

"image":"mountain_landscape_23.png",

In mountain.tmx:

<image source="mountain_landscape_23.png" width="512" height="512"/>

Mountain_landscape_23.png

Important! Depending on how you’ve got your development environment set up, you might get a cross-domain-security-error and the browser will refuse to draw your tiles. If so, take this png file into an editor like photoshop and save it back out to your dev domain to nullify the CORS error.

Share:
11,932
Tom Burman
Author by

Tom Burman

Updated on June 16, 2022

Comments

  • Tom Burman
    Tom Burman almost 2 years

    Im following this this tutorial to be able to load json map files created by tiled map editor in my javascript/canvas game.

    ive got to the point where i have implemented my own kind of version, and am getting no errors in firebug in console or net etc.

    And as far as i can see, by putting in console.logs and alerts, the script is running absolutely fine!

    The problem is the canvas stays blank! when it should have a tilemap now on it.

    Here is my version of the tutorial implemented in my game:

    function Level() {
    var c;
    var data;
    var layers = [];
    
    this.get_map = function(name,ctx){
        c = ctx;
        $.getJSON('maps/'+ name + '.json', function(json){
        get_tileset(json);
        });
    };
    
    function get_tileset(json) {
        data = json;
        this.tileset = $("<img />", { src: json.tilesets[0].image })[0];
        this.tileset.onload = renderLayers(this);
    }
    
    function renderLayers(layers){
        layers = $.isArray(layers) ? layers : data.layers;
        layers.forEach(renderLayer);
    }
    
    function renderLayer (layer){
        if (layer.type !== "tilelayer" || !layer.opacity) {
            alert("Not a tileLayer");
        }
        var s = c.canvas.cloneNode(),
                size = data.tileWidth;
        s = s.getContext("2d");
    
        if (layers.length < data.layers.length) {
            layer.data.forEach(function(tile_idx, i) {
                if (!tile_idx) { return; }
                var img_x, img_y, s_x, s_y,
                    tile = data.tilesets[0];
                tile_idx--;
                img_x = (tile_idx % (tile.imagewidth / size)) * size;
                img_y = ~~(tile_idx / (tile.imagewidth / size)) * size;
                s_x = (i % layer.width) * size;
                s_y = ~~(i / layer.width) * size;
                s.drawImage(this.tileset, img_x, img_y, size, size,
                    s_x, s_y, size, size);
            });
    
            layers.push(s.canvas.toDataURL());
            c.drawImage(s.canvas, 0, 0);
        }
        else {
            layers.forEach(function(src) {
                var i = $("<img />", { src: src })[0];
                c.drawImage(i, 0, 0);
            });
        }
    
    }
    
    }
    

    and it is called from my main javascript file which is this:

    $(document).ready(function(){
    
    var canvas = document.getElementById("TBG");
    var ctx = canvas.getContext("2d");
    
    var ui = new Gui();
    var level = new Level();
    
    //----------Login/Register Gui --------------
    $('#TBG').hide();
    $('#load-new').hide();
    $('#reg').hide();
    $('#login').hide();
    
    //if login_but is clicked do ui.login function
    $('#login_but').click(ui.login);
    //if reg_but is clicked do ui.register function
    $('#reg_but').click(ui.register);
    
    $('#new_but').click(function(){
        game_settings("new");
    });
    
    $('#load_but').click(function(){
        game_settings("load");
    });
    
    //if login_sumbit button is clicked do ui.login_ajax function
    $("#login_submit").click(ui.login_ajax);
    
    $("#reg_submit").click(ui.register_ajax);
    
    $("#welcome").on("click", "#logout_but", ui.logout);
    
    //________________________
    
    //Initialisation of game
    
    function game_settings(state){
        if(state == "load"){
            ui.load_game();
            //do ajax call to load user last save
            level.get_map("level_01",ctx);
        }
        else{
            //set beginning params
    
    
            //Change screens
            ui.new_game();
            alert("new game");
        }
    }
    
    // End Loop ------------------------------------------------------
    
    
    
    
    
    });
    

    I don't suppose you lovely people could spot why the tile-map isn't being printed to my canvas?

    Thanks for any help Tom