import standard; import node; //constants mapped to the given file "tileset.png" var tileset: [string : [int]] const = [ "pillar": [0, 0, 0], "floor-0": [0, 1, 1], "floor-1": [1, 1, 1], "floor-2": [2, 1, 1], "floor-3": [3, 1, 1], "wall-t": [0, 2, 0], "wall-b": [1, 2, 0], "wall-l": [2, 2, 0], "wall-r": [3, 2, 0], "corner-tl": [0, 3, 0], "corner-tr": [1, 3, 0], "corner-bl": [2, 3, 0], "corner-br": [3, 3, 0], "edge-tl": [0, 4, 0], "edge-tr": [1, 4, 0], "edge-bl": [2, 4, 0], "edge-br": [3, 4, 0] ]; //raw string data var rawmap: [[string]] = null; //baked and usable blobs of data var tilemap: [int] = null; // [x0, y0, x1, y1, ...] var collisions: [bool] = null; //metadata about the above blobs var tilemapGridWidth: int = 0; var tilemapGridHeight: int = 0; //fast accessors fn getTilemapData(node: opaque) { return tilemap; } fn getCollisionData(node: opaque) { return collisions; } //lifecycle functions fn onLoad(node: opaque) { node.loadNodeTexture("sprites:/tileset.png"); node.setNodeScaleX(CAMERA_SCALE_X); node.setNodeScaleY(CAMERA_SCALE_Y); } fn onDraw(node: opaque) { assert tilemap, "tilemap is null"; var posX: int const = node.getNodeWorldPositionX(); var posY: int const = node.getNodeWorldPositionY(); //draw everything at twice the original size var scaleX: float const = node.getNodeWorldScaleX(); var scaleY: float const = node.getNodeWorldScaleY(); //draw the tilemap for (var j = 0; j < tilemapGridHeight; j++) { for (var i = 0; i < tilemapGridWidth; i++) { //set the rect of the node on the tilesheet - the "tilemap" var is a single blob of data node.setNodeRect( tilemap[j * tilemapGridWidth * 2 + i * 2] * TILE_PIXEL_WIDTH, tilemap[j * tilemapGridWidth * 2 + i * 2 + 1] * TILE_PIXEL_HEIGHT, TILE_PIXEL_WIDTH, TILE_PIXEL_HEIGHT ); //draw to the screen node.drawNode( floor((i * TILE_PIXEL_WIDTH + posX) * scaleX) + globalCameraX, floor((j * TILE_PIXEL_HEIGHT + posY) * scaleY) + globalCameraY, floor(TILE_PIXEL_WIDTH * scaleX), floor(TILE_PIXEL_HEIGHT * scaleY) ); } } } //utils functions for map generation fn generateFromRng(node: opaque, rng: opaque, width: int, height: int) { //use debug room for now rawmap = generateRawTilemapDebugRoom(rng, width, height); tilemap = bakeTilemap(rawmap, width, height); collisions = bakeCollisionMap(rawmap, width, height); tilemapGridWidth = width; tilemapGridHeight = height; //debugging print tilemap; print collisions; } //"raw" tilemaps are not usable, they are just a 2d array of strings fn generateRawTilemapDebugRoom(rng: opaque, width: int, height: int): [[string]] const { import random; //generate a grid filled with only pillar tiles, as a starting point var result: [[string]] = []; var row: [string] = []; for (var j: int = 0; j < height; j++) { row.push("pillar"); } for (var i: int = 0; i < width; i++) { result.push(row); } //generate the walkable tiles of the grid - floor tiles for (var j: int = 1; j < height - 1; j++) { for (var i: int = 1; i < width - 1; i++) { //select a random floor tile (graphical effect only) var x: int = rng.generateRandomNumber() % 4; var t: string = "floor-" + string x; result[i][j] = t; } } //draw top and bottom walls for (var i: int = 1; i < width - 1; i++) { result[i][0] = "wall-t"; result[i][height - 1] = "wall-b"; } //draw the left and right walls for (var j: int = 1; j < height - 1; j++) { result[0][j] = "wall-l"; result[width-1][j] = "wall-r"; } //draw the corners result[0][0] = "corner-tl"; result[width - 1][0] = "corner-tr"; result[0][height - 1] = "corner-bl"; result[width - 1][height - 1] = "corner-br"; //debugging result[4][4] = "pillar"; result[width - 5][4] = "pillar"; result[4][height - 5] = "pillar"; result[width - 5][height - 5] = "pillar"; //return the raw result of strings return result; } //"baking" converts raw tilemaps into usable blobs of data fn bakeTilemap(tilemap: [[string]] const, width: int, height: int): [int] const { var result: [int] = []; //extract the positions from the tileset for (var j: int = 0; j < height; j++) { for (var i: int = 0; i < width; i++) { result.push(tileset[ tilemap[i][j] ][0]); result.push(tileset[ tilemap[i][j] ][1]); } } return result; } //this bakes the collision map as a separate object fn bakeCollisionMap(tilemap: [[string]] const, width: int, height: int): [bool] const { var result: [bool] = []; //extract the walkable state for (var j: int = 0; j < height; j++) { for (var i: int = 0; i < width; i++) { result.push(tileset[ tilemap[i][j] ][2] != 0); } } return result; }