AutoTileSet for Flashpunk


(Jacob Albano) #1

I used AutoTileGen to create the tilesets for my #gbjam game, but at that time the algorithm for actually arranging the tiles in a tilemap didn’t exist for Flash. I got in contact with the creator and put this together with his help.

Here’s how you use it:

  • Design your map in the editor of your choice, but don’t actually place the tiles. In Ogmo, I used a grid layer to specify which tiles were solid.
  • Load your map into a Grid.
  • Create a Tilemap using the image AutoTileGen creates from your source.
//  To generate the entire map, do this:
AutoTileSet.createFromGrid(map, grid);

//  To only set one tile, do this:
AutoTileSet.setTile(map, grid, x, y);
package  
{
    import net.flashpunk.graphics.Tilemap;
    import net.flashpunk.masks.Grid;
    
    public class AutoTileSet 
    {
        /**
         * Instantiating this has no effect, so probably don't do it.
         */
        public function AutoTileSet() {}
        
        /**
         * Set each tile in a tilemap based on its neighbors
         * @param    map    The tilemap to set the tiles of
         * @param    grid The grid to use for determining tile neighbors
         */
        public static function createFromGrid(map:Tilemap, grid:Grid):void
        {
            var near:Array = [];
            for (var x:int = 0; x < grid.columns; x++) 
            {
                for (var y:int = 0; y < grid.rows; y++) 
                {
                    setTile(map, grid, x, y, near);
                }
            }
        }
        
        /**
         * Set a tile based on its neighbors
         * @param    map    The tilemap to set the tiles of
         * @param    grid The grid to use for determining tile neighbors
         * @param    x X index of the tile
         * @param    y Y index of the tile
         * @param    near    Optional array to use for storing neighbor data. If not supplied, the function will create a new one to use.
         */
        public static function setTile(map:Tilemap, grid:Grid, x:int, y:int, near:Array = null):void 
        {
            if (!grid.getTile(x, y))
            {
                map.setTile(x, y, map.tileCount - 1);
                return;
            }
            
            near = near || [];
            function test(i:int, j:int):Boolean { return grid.getTile(x + i, y + j); }
            
            near[0] = test(0, -1);
            near[1] = test(1, 0);
            near[2] = test(0, 1);
            near[3] = test(-1, 0);
            near[4] = test(-1, -1);
            near[5] = test(1, -1);
            near[6] = test(1, 1);
            near[7] = test( -1, 1);
            
            //    value for a single block with no neighbors, otherwise it'll be set to (0, 0)
            var sx:int = 6, sy:int = 2;
            if (all(near[3])){sx=2;sy=2;}
            if (all(near[0])){sx=3;sy=2;}
            if (all(near[1])){sx=4;sy=2;}
            if (all(near[2])){sx=5;sy=2;}
            if (all(near[1],near[3])){sx=0;sy=2;}
            if (all(near[0],near[2])){sx=1;sy=2;}
            if (all(near[0],near[3])){sx=7;sy=1;}
            if (all(near[1],near[0])){sx=0;sy=0;}
            if (all(near[2],near[1])){sx=1;sy=0;}
            if (all(near[3],near[2])){sx=2;sy=0;}
            if (all(near[2],near[3],near[7])){sx=4;sy=3;}
            if (all(near[3],near[0],near[4])){sx=5;sy=3;}
            if (all(near[0],near[1],near[5])){sx=6;sy=3;}
            if (all(near[1],near[2],near[6])){sx=7;sy=3;}
            if (all(near[0],near[1],near[3])){sx=3;sy=0;}
            if (all(near[1],near[2],near[0])){sx=4;sy=0;}
            if (all(near[2],near[3],near[1])){sx=5;sy=0;}
            if (all(near[3],near[0],near[2])){sx=6;sy=0;}
            if (all(near[0],near[1],near[2],near[3])){sx=7;sy=4;}
            if (all(near[0],near[2],near[3],near[7])){sx=7;sy=2;}
            if (all(near[1],near[3],near[0],near[4])){sx=0;sy=1;}
            if (all(near[2],near[0],near[1],near[5])){sx=1;sy=1;}
            if (all(near[3],near[1],near[2],near[6])){sx=2;sy=1;}
            if (all(near[0],near[1],near[3],near[5])){sx=3;sy=1;}
            if (all(near[1],near[2],near[0],near[6])){sx=4;sy=1;}
            if (all(near[2],near[3],near[1],near[7])){sx=5;sy=1;}
            if (all(near[3],near[0],near[2],near[4])){sx=6;sy=1;}
            if (all(near[1],near[2],near[3],near[6],near[7])){sx=0;sy=3;}
            if (all(near[0],near[2],near[3],near[4],near[7])){sx=1;sy=3;}
            if (all(near[0],near[1],near[3],near[4],near[5])){sx=2;sy=3;}
            if (all(near[0],near[1],near[2],near[5],near[6])){sx=3;sy=3;}
            if (all(near[0],near[1],near[2],near[3],near[7])){sx=3;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[4])){sx=4;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[5])){sx=5;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[6])){sx=6;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[5],near[7])){sx=1;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[6])){sx=2;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[6],near[7])){sx=5;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[7])){sx=6;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[5])){sx=7;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[5],near[6])){sx=0;sy=4;}
            if (all(near[0],near[1],near[2],near[3],near[5],near[6],near[7])){sx=1;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[6],near[7])){sx=2;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[5],near[7])){sx=3;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[5],near[6])){sx=4;sy=5;}
            if (all(near[0],near[1],near[2],near[3],near[4],near[5],near[6],near[7])){sx=0;sy=5;}
            
            //    convert coords for top-left index
            var currentTileIndex:int = ( 5 - sy ) * 8 + sx;
            
            map.setTile(x, y, currentTileIndex);
        }
        
        private static function all(...bools):Boolean
        {
            return bools.indexOf(false) < 0;
        }
    }
}

(TaylorAnderson) #2

NICE! I’ve been procrastinating on doing something like this for some time. This is a very nice tool to have


(Mike Evmm) #3

I don’t really understand :confused: How would you design the map, but not place the tiles?


(Jacob Albano) #4

The idea is that AutoTileSet takes care of placing each individual tile for you, so all you do is specify which spaces should be filled in.

So you give it a grid like this:

And it turns that into a tilemap in-game, like this:


(Mike Evmm) #5

Ohh, awesome! :smiley: I’ve been wanting to do a platformer for a while, this makes things a lot easier!