Tilemap not displaying

I’m having trouble hooking up the Tilemap and getting it to display. It compiles fine, but I get WebGL errors showing no texture is bound to the target, and I’ve gone through my code and refactored a dozen or so times to no avail.

Game.hx

this.map = TileMapService.instance
        .setDimensions(10,15)
        .setTileSize(32)
        .setTilesetFromFile("assets/underground.png")
        .setContainer(container)
        .createWorld();

TileMapService.hx

public function setDimensions(width:UInt, height:UInt):TileMapService {
        this.width = width;
        this.height = height;

        return this;
    }

    public function setTileSize(size:UInt):TileMapService {
        this.tileSize = size;

        return this;
    }

    public function setTilesetFromFile(filePath:String):TileMapService {
        var bitmapData = BitmapData.fromFile(filePath);

        this.tileset = new Tileset(bitmapData);

        this.enumMap.set(TileType.EMPTY, this.tileset.addRect(new Rectangle(0,0,32,32)));
        this.enumMap.set(TileType.WALL, this.tileset.addRect(new Rectangle(32,0,32,32)));

        return this;
    }

    public function setContainer(container:DisplayObjectContainer):TileMapService {
        this.container = container;
        this.tilemap = new Tilemap(container.stage.stageWidth, container.stage.stageHeight, this.tileset);
        container.addChild(this.tilemap);
        
        return this;
    }

    public function createWorld():TileMapService {
        var size = this.width * this.height;
        var tileArray = new TileArray(size);
        for (i in 0...size) {
            var x = (i % this.width); 
            var y = Util.fint(i / this.width);
            tileArray.position = i;
            tileArray.matrix = new Matrix(1,0,0,1,x,y);
        }
        tilemap.setTiles (tileArray);

        return this;
    }
enum TileType {
    EMPTY;
    WALL;
}

I did originally set the tilemap directly rather than assigning it with the tilearray, but that caused the same error and I like this more direct method better. No part of the tilemap appears on-screen. Any help would be greatly appreciated.

If I change the path assets/underground.png it will complain about not being able to find it, and I can confirm that in the browser it serves to the correct path that it is looking for.

Perhaps this.tileset = new Tileset(bitmapData); should be:

this.tileset = new Tileset(bitmapData);
this.tileset.addRect(bitmapData.rect);

or

this.tileset = new Tileset(bitmapData, [bitmapData.rect]);

The Tileset/TileArray API is still beta, so I’d be happy to hear any feedback on the API in general. For now, see if this helps :slight_smile:

Thanks for the quick reply :slight_smile:

Modifying my code to use either of your two pattern suggestions was unsuccessful. If the rest of the code looks good to you, then my problem must lie elsewhere although I admit I’m not entirely sure where to start looking. If I try to add a different object (other than my tilemap) to my display container, it will display properly. Is it possible my image is being loaded asynchronously and thus the bitmapdata cannot return a valid texture?

To simplify debugging, I have condensed my code into a single function call.

Game.hx

this.map = TileMapService.instance.createWorld(container);

TileMapService.hx createWorld()

public function createWorld(container:DisplayObjectContainer):TileMapService {
        var bitmapData = BitmapData.fromFile("assets/underground.png");
        this.tileset = new Tileset(bitmapData);
        this.tileset.addRect(new Rectangle(0,0,32,32));
        this.tileset.addRect(new Rectangle(32,0,32,32));

        this.container = container;
        this.tilemap = new Tilemap(container.stage.stageWidth, container.stage.stageHeight, this.tileset);
        container.addChild(this.tilemap);
        
        this.width = 10;
        this.height = 15;
        var size = this.width * this.height;
        var tileArray = new TileArray(size);
        for (i in 0...size) {
            var x = (i % this.width); 
            var y = Util.fint(i / this.width);
            tileArray.position = i;
            tileArray.matrix = new Matrix(1,0,0,1,x,y);
        }
        tilemap.setTiles (tileArray);
        
        return this;
    }

I am getting 4 errors of
WebGL: INVALID_OPERATION: texParameter: no texture bound to target

Followed by 2 errors of
[.Offscreen-For-WebGL-0000019402BC32E0]RENDER WARNING: there is no texture bound to the unit 0


As far as general concerns over the API - there isn’t much in the name of examples and resources online especially given the recent change from Tilesheets to Tilemap and the more recent introduction of TileArray, which makes debugging this on my own much more difficult.

My goal here is to have a grid of tiles that will form the level layout for my game. I’m a little unclear exactly what role Tilemap plays in this. It was my initial impression that I would hook it up to a tilesheet and tell it which tiles should appear in which cells and it would display all the tiles for me (like HaxePunk’s Tilemap), but I’m seeing now that it is much more like a replacement for the displaylist and the tiles that I set need to be positioned manually.

I do believe a list of tiles that have arbitrary positions is necessarily less efficient than a fixed-size array where each cell only stores the ID of the tile it’s supposed to be displaying, but perhaps that is part of the setup I’m required to do on my own? Either way, I’m unclear about it and any clarification would be much appreciated.

Thanks for your time,
Jacob

Alright, I figured it out. As I suspected, the bitmapdata was not loading properly from the file. I believe the problem was the HTML5 target does not allow native file access, and so I need to use the Asset class to embed the image and load it.

The code that ended up working is here:

    public function createWorld(container:DisplayObjectContainer):TileMapService {
        this.container = container;

        Assets.loadBitmapData("assets/underground.png").onComplete(handleImage);
        
        return this;
    }

    public function handleImage(bitmapData:BitmapData):Void {
        this.width = 10;
        this.height = 15;

        this.tileset = new Tileset(bitmapData);
        this.tileset.addRect(new Rectangle(0,0,32,32));
        this.tileset.addRect(new Rectangle(32,0,32,32));

        this.tilemap = new Tilemap(container.stage.stageWidth, container.stage.stageHeight, this.tileset);
        container.addChild(this.tilemap);

        var size = this.width * this.height;
        var tileArray = new TileArray(size);
        for (i in 0...size) {
            var x = (i % this.width); 
            var y = Util.fint(i / this.width);
            tilemap.addTile(new Tile(0, x * 32, y * 32, 1, 1, 1, 0, 0));
        }
    }
1 Like

Sorry I didn’t catch that :slight_smile: