diff --git a/assets/scripts/gameplay-prototype/drone.toy b/assets/scripts/gameplay-prototype/drone.toy deleted file mode 100644 index 1722fc2..0000000 --- a/assets/scripts/gameplay-prototype/drone.toy +++ /dev/null @@ -1,163 +0,0 @@ -import standard; -import node; -import random; - -//variables -var gridPositionX: int = 1; -var gridPositionY: int = 1; - -var direction: int = null; //BUGFIX: animation not looping properly - -var stepAI: int = 0; - -//polyfills - animating different cycles on one image -var walkAnimationCounter: int = 0; - -fn faceDown(node: opaque) { - if (direction == 0) return; - direction = 0; - node.setNodeRect(0, 0, 32, 32); - node.setNodeFrames(2); - walkAnimationCounter = 12; -} - -fn faceUp(node: opaque) { - if (direction == 1) return; - direction = 1; - node.setNodeRect(32 * 2, 0, 32, 32); - node.setNodeFrames(2); - walkAnimationCounter = 12; -} - -fn faceRight(node: opaque) { - if (direction == 2) return; - direction = 2; - node.setNodeRect(32 * 4, 0, 32, 32); - node.setNodeFrames(2); - walkAnimationCounter = 12; -} - -fn faceLeft(node: opaque) { - if (direction == 3) return; - direction = 3; - node.setNodeRect(32 * 6, 0, 32, 32); - node.setNodeFrames(2); - walkAnimationCounter = 12; -} - - -//accessors & mutators -fn setGridPosition(node: opaque, x: int, y: int) { - gridPositionX = x; - gridPositionY = y; - - node.setNodePositionX(floor( gridPositionX * node.getNodeRectW() / node.getNodeScaleX() )); - node.setNodePositionY(floor( gridPositionY * node.getNodeRectH() / node.getNodeScaleY() )); -} - -fn getGridPositionX(node: opaque) { - return gridPositionX; -} - -fn getGridPositionY(node: opaque) { - return gridPositionY; -} - - -//lifecycle functions -fn onLoad(node: opaque) { - node.loadNodeTexture("sprites:/drone.png"); - node.faceDown(); - - node.setNodeScaleX(CAMERA_SCALE_X); - node.setNodeScaleY(CAMERA_SCALE_Y); -} - -//fn onUpdate(node: opaque, delta: int) { -// // -//} - -fn onStep(node: opaque) { - if (++walkAnimationCounter >= 12) { - node.incrementCurrentNodeFrame(); - walkAnimationCounter = 0; - } - - //move in realspace - var distX = gridPositionX * TILE_PIXEL_WIDTH - node.getNodePositionX(); - var distY = gridPositionY * TILE_PIXEL_HEIGHT - node.getNodePositionY(); - - node.setNodeMotionX( normalize(distX) ); - node.setNodeMotionY( normalize(distY) ); -} - -fn onFree(node: opaque) { - node.freeNodeTexture(); -} - -fn onDraw(node: opaque) { - var posX: int = node.getNodeWorldPositionX(); - var posY: int = node.getNodeWorldPositionY(); - - var scaleX: float = node.getNodeWorldScaleX(); - var scaleY: float = node.getNodeWorldScaleY(); - - //this offset is because the sprite cell for lejana is twice as big as the sprite cell for the floor tiles - var originOffsetX: int = node.getNodeRectW() * int scaleX / 4; - var originOffsetY: int = node.getNodeRectH() * int scaleY / 2; - - node.drawNode( - floor(posX * scaleX) - originOffsetX + globalCameraX, - floor(posY * scaleY) - originOffsetY + globalCameraY, - floor(node.getNodeRectW() * scaleX), - floor(node.getNodeRectH() * scaleY) - ); -} - -//gameplay functions -fn runAI(node: opaque, rng: opaque) { - if (stepAI++ >= 1) { - stepAI = 0; - - var dir = rng.generateRandomNumber() % 4; - var moveX = 0; - var moveY = 0; - - if (dir == 0) { - moveY += 1; - node.faceDown(); - } - - if (dir == 1) { - moveY -= 1; - node.faceUp(); - } - - if (dir == 2) { - moveX += 1; - node.faceRight(); - } - - if (dir == 3) { - moveX -= 1; - node.faceLeft(); - } - - if (node.getParentNode().callNodeFn("getWalkableAt", gridPositionX + moveX, gridPositionY + moveY)) { - gridPositionX += moveX; - gridPositionY += moveY; - } - } -} - - -//polyfills - move these to standard -fn normalize(x): int { - if (x > 0) { - return 1; - } - if (x < 0) { - return -1; - } - return 0; -} \ No newline at end of file diff --git a/assets/scripts/gameplay-prototype/lejana.toy b/assets/scripts/gameplay-prototype/lejana.toy deleted file mode 100644 index 3962745..0000000 --- a/assets/scripts/gameplay-prototype/lejana.toy +++ /dev/null @@ -1,258 +0,0 @@ -import standard; -import node; - -var gridPositionX: int = 1; //position on the game grid -var gridPositionY: int = 1; - -var inputX: int = 0; //cache the keyboard input -var inputY: int = 0; - -var direction: int = null; //BUGFIX: animation not looping properly -var enableMovementCounter: int = 60 * 3; //BUGFIX: freeze while drones reach their starting spot - -//polyfills - animating different cycles on one image -var walkAnimationCounter: int = 0; -var attackAnimationCounter: int = 0; - -//utils for facing different directions (idling) -fn faceDown(node: opaque) { - if (direction == 0) return; - direction = 0; - node.setNodeRect(0, 0, 32, 32); - node.setNodeFrames(4); - walkAnimationCounter = 12; -} - -fn faceUp(node: opaque) { - if (direction == 1) return; - direction = 1; - node.setNodeRect(32 * 4, 0, 32, 32); - node.setNodeFrames(4); - walkAnimationCounter = 12; -} - -fn faceRight(node: opaque) { - if (direction == 2) return; - direction = 2; - node.setNodeRect(32 * 8, 0, 32, 32); - node.setNodeFrames(4); - walkAnimationCounter = 12; -} - -fn faceLeft(node: opaque) { - if (direction == 3) return; - direction = 3; - node.setNodeRect(32 * 12, 0, 32, 32); - node.setNodeFrames(4); - walkAnimationCounter = 12; -} - -//accessors & mutators -fn setGridPosition(node: opaque, x: int, y: int) { - gridPositionX = x; - gridPositionY = y; - - node.setNodePositionX(floor( gridPositionX * node.getNodeRectW() / node.getNodeScaleX() )); - node.setNodePositionY(floor( gridPositionY * node.getNodeRectH() / node.getNodeScaleY() )); -} - -fn getGridPositionX(node: opaque) { - return gridPositionX; -} - -fn getGridPositionY(node: opaque) { - return gridPositionY; -} - -//lifecycle functions -fn onLoad(node: opaque) { - node.loadNodeTexture("sprites:/lejana.png"); //NOTE: all of this script is mapped to this sprite sheet - node.faceDown(); - - node.setNodeScaleX(CAMERA_SCALE_X); - node.setNodeScaleY(CAMERA_SCALE_Y); -} - -//fn onUpdate(node: opaque, delta: int) { -// // -//} - -fn onStep(node: opaque) { - //initial freeze - if (enableMovementCounter > 0) { - enableMovementCounter--; - return; - } - - //animation - start idling - if (attackAnimationCounter == 0) { - //move to standing state - if (node.getNodeRectY() != 0) { - node.setNodeRect(direction * 32 * 4, 0, 32, 32); - node.setNodeFrames(4); - walkAnimationCounter = 12; - } - } - - //animation - start attacking - if (--attackAnimationCounter >= 0) { - //move to attacking state - if (node.getNodeRectY() != 32) { - node.setNodeRect(direction * 32 * 4, 32, 32, 32); - node.setNodeFrames(3); - } - - if ((attackAnimationCounter+1) % 4 == 0) { //+1 for a bugfix - node.incrementCurrentNodeFrame(); - } - - //skip out - return; - } - - //facing - if (inputY > 0) { - node.faceDown(); - } - - else if (inputY < 0) { - node.faceUp(); - } - - else if (inputX > 0) { - node.faceRight(); - } - - else if (inputX < 0) { - node.faceLeft(); - } - - //BUGFIX for smooth animation fo - var lesser = 0; - if ((inputX != 0 || inputY != 0) && attackAnimationCounter == 0) { - lesser = 6; - } - - //actually animate - if (--walkAnimationCounter <= lesser) { - node.incrementCurrentNodeFrame(); - walkAnimationCounter = 12; - } - - var parent = node.getParentNode(); //check for collisions from the parent - - if (parent.callNodeFn("getWalkableAt", gridPositionX + inputX, gridPositionY + inputY) && abs(inputX) != abs(inputY)) { - //calc movement - gridPositionX += inputX; - gridPositionY += inputY; - - parent.callNodeFn("runAI"); - } - - //move in realspace - var distX = gridPositionX * TILE_PIXEL_WIDTH - node.getNodePositionX(); - var distY = gridPositionY * TILE_PIXEL_HEIGHT - node.getNodePositionY(); - - node.setNodeMotionX( normalize(distX) ); - node.setNodeMotionY( normalize(distY) ); - - //reset input - inputX = 0; - inputY = 0; -} - -fn onFree(node: opaque) { - node.freeNodeTexture(); -} - -fn onDraw(node: opaque) { - var posX: int = node.getNodeWorldPositionX(); - var posY: int = node.getNodeWorldPositionY(); - - var scaleX: float = node.getNodeWorldScaleX(); - var scaleY: float = node.getNodeWorldScaleY(); - - //this offset is because the sprite cell for lejana is twice as big as the sprite cell for the floor tiles - var originOffsetX: int = player.getNodeRectW() / 2; - var originOffsetY: int = player.getNodeRectH(); - - node.drawNode( - floor(posX * scaleX) - originOffsetX + globalCameraX, - floor(posY * scaleY) - originOffsetY + globalCameraY, - floor(node.getNodeRectW() * scaleX), - floor(node.getNodeRectH() * scaleY) - ); -} - - -//event functions -fn onKeyDown(node: opaque, event: string) { - //initial freeze - if (enableMovementCounter > 0) { - return; - } - - //enable attack - if (event == "character_attack" && inputX == 0 && inputY == 0) { - attackAnimationCounter = 12; - return; - } - - //if moving, don't take any more input - if (node.getNodeMotionX() != 0 || node.getNodeMotionY() != 0) { - return; - } - - if (event == "character_up") { - inputY -= 1; - return; - } - - if (event == "character_down") { - inputY += 1; - return; - } - - if (event == "character_left") { - inputX -= 1; - return; - } - - if (event == "character_right") { - inputX += 1; - return; - } -} - -fn onKeyUp(node: opaque, event: string) { - if (event == "character_up" && inputY < 0) { - inputY = 0; - return; - } - - if (event == "character_down" && inputY > 0) { - inputY = 0; - return; - } - - if (event == "character_left" && inputX < 0) { - inputX = 0; - return; - } - - if (event == "character_right" && inputX > 0) { - inputX = 0; - return; - } -} - -//polyfills - move these to standard -fn normalize(x): int { - if (x > 0) { - return 1; - } - if (x < 0) { - return -1; - } - return 0; -} \ No newline at end of file diff --git a/assets/scripts/gameplay-prototype/scene.toy b/assets/scripts/gameplay-prototype/scene.toy deleted file mode 100644 index d19a65d..0000000 --- a/assets/scripts/gameplay-prototype/scene.toy +++ /dev/null @@ -1,161 +0,0 @@ -import standard; -import node; -import random; - - -//persistent members -var tilemap: opaque = null; -var stepCounter: opaque = null; -var player: opaque = null; -var enemies: [opaque] = null; - -var collisionDataCache: [bool] = null; - -var rng: opaque = null; //TODO: does this have an opaque tag? - -//lifecycle functions -fn onInit(node: opaque) { - //load the map stuff - tilemap = node.loadChild("scripts:/gameplay/tilemap.toy"); - node.generateScene(clock().hash(), MAP_GRID_WIDTH, MAP_GRID_HEIGHT); - - //load and initialize the UI (depends on map stuff) - stepCounter = node.loadChild("scripts:/gameplay/step-counter.toy"); - stepCounter.setNodeRect(0, 0, CAMERA_SCREEN_W, 32); - stepCounter.callNodeFn("setMaxSteps", 100); - stepCounter.setNodeLayer(100); - - //offset the scene node, so it shows the map outside separate from the UI - node.setNodePositionY(16); -} - -fn onFree(node: opaque) { - //cleanup - if (rng != null) { - rng.freeRandomGenerator(); - } -} - -// fn onUpdate(node: opaque, delta: int) { -// print "delta: " + string delta; -// } - -//fn onStep(node: opaque) { -// // -//} - -fn onDraw(node: opaque) { - //use the onDraw to sort - skip too many steps - node.sortChildrenNode(depthComparator); - - var scaleX: float = player.getNodeWorldScaleX(); - var scaleY: float = player.getNodeWorldScaleY(); - - //this offset is because the sprite cell for lejana is twice as big as the sprite cell for the floor tiles - var originOffsetX: int = player.getNodeRectW() / 2; - var originOffsetY: int = player.getNodeRectH() / 2; - - //use the room scene's onDraw to set the global camera position - globalCameraX = floor((CAMERA_SCREEN_W / 2) - (player.getNodeWorldPositionX() * scaleX)) - originOffsetX; - globalCameraY = floor((CAMERA_SCREEN_H / 2) - (player.getNodeWorldPositionY() * scaleY)) - originOffsetY; -} - -//gameplay functions -fn generateScene(node: opaque, seed: int, width: int, height: int) { - //reset the array - enemies = []; - - if (rng != null) { - rng.freeRandomGenerator(); - } - rng = createRandomGenerator(seed); - - //generate map - tilemap.callNodeFn("generateFromRng", rng, width, height); - collisionDataCache = tilemap.callNodeFn("getCollisionData"); - - //place player here, so drop dropping can avoid the player - player = node.loadChild("scripts:/gameplay/lejana.toy"); - player.callNodeFn("setGridPosition", 1, 1); - - //generate drones - var droneCount: int const = rng.generateRandomNumber() % 2 + 20; - for (var i = 0; i < droneCount; i++) { - var d: opaque = node.loadChild("scripts:/gameplay/drone.toy"); - d.initNode(); - - enemies.push(d); - - var x = 0; - var y = 0; - - //while generated spot is a collision, or too close to the player - while (x == 0 && y == 0 || node.getWalkableAt(x, y) == false || x < width / 6 * 2 && y < height / 6 * 2) { - x = rng.generateRandomNumber() % width; - y = rng.generateRandomNumber() % height; - } - - d.callNodeFn("setGridPosition", x, y); - d.setNodePositionX(MAP_GRID_WIDTH * TILE_PIXEL_WIDTH); - d.setNodePositionY(MAP_GRID_HEIGHT * TILE_PIXEL_HEIGHT); - } -} - -fn getWalkableAt(node: opaque, x: int, y: int) { - if (collisionDataCache == null || x == null || y == null) { - return false; - } - - //entities - if (x == player.callNodeFn("getGridPositionX") && y == player.callNodeFn("getGridPositionY")) { - return false; - } - - for (var i = 0; i < enemies.length(); i++) { - if (x == enemies[i].callNodeFn("getGridPositionX") && y == enemies[i].callNodeFn("getGridPositionY")) { - return false; - } - } - - //outside the grid - if (y * MAP_GRID_WIDTH + x < 0 || y * MAP_GRID_WIDTH + x >= collisionDataCache.length()) { - return false; - } - - //default - return collisionDataCache[y * MAP_GRID_WIDTH + x]; -} - -fn runAI(node: opaque) { - for (var i = 0; i < enemies.length(); i++) { - enemies[i].callNodeFn("runAI", rng); - } - - stepCounter.callNodeFn("alterRemainingSteps", -1); -} - -//utils - polyfills -fn loadChild(parent: opaque, fname: string) { - //TODO: add this to the API proper - var child: opaque = loadNode(fname); - parent.pushNode(child); - return child; -} - -fn depthComparator(lhs: opaque, rhs: opaque) { //for sorting by depth - var lhsPositionY = lhs.getNodeWorldPositionY(); - var rhsPositionY = rhs.getNodeWorldPositionY(); - - if (lhsPositionY == null || rhsPositionY == null) { //BUGFIX: children without that function - return true; - } - - if (lhsPositionY == rhsPositionY) { //BUGFIX: prevent z-fighting - var lhsPositionX = lhs.getNodeWorldPositionX(); - var rhsPositionX = rhs.getNodeWorldPositionX(); - - return lhsPositionX < rhsPositionX; - } - - return lhsPositionY < rhsPositionY; -} diff --git a/assets/scripts/gameplay-prototype/step-counter.toy b/assets/scripts/gameplay-prototype/step-counter.toy deleted file mode 100644 index 24c3312..0000000 --- a/assets/scripts/gameplay-prototype/step-counter.toy +++ /dev/null @@ -1,68 +0,0 @@ -import node; - -//members -var maxSteps: int = 0; -var remainingSteps: int = 0; - -//accessors -fn getMaxSteps(node: opaque) { - return maxSteps; -} - -fn getRemainingSteps(node: opaque) { - return remainingSteps; -} - -//mutators -fn setMaxSteps(node: opaque, steps: int) { - maxSteps = steps; - remainingSteps = steps; -} - -fn setRemainingSteps(node: opaque, steps: int) { - remainingSteps = steps; -} - -//utility mutators -fn alterRemainingSteps(node: opaque, increment: int) { - remainingSteps += increment; - if (remainingSteps > maxSteps) { - remainingSteps = maxSteps; - } - - if (remainingSteps < 0) { - remainingSteps = 0; - } - - return remainingSteps; -} - -//utils - polyfills -fn loadChild(parent: opaque, fname: string) { - var child: opaque = loadNode(fname); - parent.pushNode(child); - child.setNodeLayer(parent.getNodeLayer()); - return child; -} - -//lifecycle functions -fn onLoad(node: opaque) { - node.loadNodeTexture("sprites:/stepcounter.png"); - - node - .loadChild("scripts:/gameplay/text.toy") - .setNodeText("fonts:/alphbeta.ttf", 32, "Water", 0, 60, 240, 255); //rgba -} - -fn onFree(node: opaque) { - node.freeNodeTexture(); -} - -fn onDraw(node: opaque) { - if (remainingSteps > 0 && maxSteps > 0) { - var tmp = float remainingSteps / maxSteps * node.getNodeRectW(); - var h = node.getNodeRectH(); - - node.drawNode(node.getNodePositionX(), node.getNodePositionY(), int tmp, h); - } -} \ No newline at end of file diff --git a/assets/scripts/gameplay-prototype/text.toy b/assets/scripts/gameplay-prototype/text.toy deleted file mode 100644 index 3b5004f..0000000 --- a/assets/scripts/gameplay-prototype/text.toy +++ /dev/null @@ -1,18 +0,0 @@ -import node; - -//this is a child of the step counter, which simply renders text - -fn onDraw(node: opaque) { - var posX: int = node.getNodePositionX(); - var posY: int = node.getNodePositionY(); - var scaleX: float = node.getNodeScaleX(); - var scaleY: float = node.getNodeScaleY(); - - node.drawNode(floor(posX * scaleX), floor(posY * scaleY)); -} - -fn onFree(node: opaque) { - node.freeNodeTexture(); -} - -//TODO: polyfill? \ No newline at end of file diff --git a/assets/scripts/gameplay-prototype/tilemap.toy b/assets/scripts/gameplay-prototype/tilemap.toy deleted file mode 100644 index cfc4878..0000000 --- a/assets/scripts/gameplay-prototype/tilemap.toy +++ /dev/null @@ -1,187 +0,0 @@ -import standard; -import node; - -//constants mapped to the given file "tileset.png" -var tileset: [string : [int]] const = [ - "empty": [-1. -1, -1], - - "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; -} diff --git a/assets/scripts/tilemap/generator.toy b/assets/scripts/tilemap/generator.toy index 35ae88b..8e9b665 100644 --- a/assets/scripts/tilemap/generator.toy +++ b/assets/scripts/tilemap/generator.toy @@ -24,8 +24,8 @@ var tileset: [string : [int]] const = [ "temple-edge-tl": [0, 4, 0], "temple-edge-tr": [1, 4, 0], - "temple-edge-bl": [2, 4, 0], - "temple-edge-br": [3, 4, 0] + "temple-edge-bl": [3, 4, 0], //would be great if these were the right way around... + "temple-edge-br": [2, 4, 0] ]; var themes: [string] const = [ @@ -104,7 +104,8 @@ fn generateTilemapData(rng: opaque) { //etch the corridors etchCorridors(roomData, corridorData, rng); - //TODO: etch the walls with a filter, based on the room's themes + //etch the walls with marching squares, based on the room's themes + etchWalls(roomData); //save the metadata for later retrieval metadata = roomData; @@ -153,52 +154,6 @@ fn etchRoom(rng: opaque, metadata: [string: any]) { tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 2] = tileset[theme + "-floor-" + string floorIndex][2]; } } - - // //create the string constants here, so refstring can do it's job - // var T_WALL: [int] const = tileset[ theme + "-wall-t" ]; - // var B_WALL: [int] const = tileset[ theme + "-wall-b" ]; - // var L_WALL: [int] const = tileset[ theme + "-wall-l" ]; - // var R_WALL: [int] const = tileset[ theme + "-wall-r" ]; - - // //etch the walls of each room - // for (var i: int = x; i < x + w; i++) { - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 0] = T_WALL[0]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 1] = T_WALL[1]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 2] = T_WALL[2]; - - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 0] = B_WALL[0]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 1] = B_WALL[1]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 2] = B_WALL[2]; - // } - - // for (var j: int = y; j < y + h; j++) { - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 0] = L_WALL[0]; - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 1] = L_WALL[1]; - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 2] = L_WALL[2]; - - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 0] = R_WALL[0]; - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 1] = R_WALL[1]; - // tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 2] = R_WALL[2]; - // } - - // //etch the corners - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 0] = tileset[ theme + "-corner-tl" ][0]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 1] = tileset[ theme + "-corner-tl" ][1]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 2] = tileset[ theme + "-corner-tl" ][2]; - - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 0] = tileset[ theme + "-corner-bl" ][0]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 1] = tileset[ theme + "-corner-bl" ][1]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 2] = tileset[ theme + "-corner-bl" ][2]; - - - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 0] = tileset[ theme + "-corner-tr" ][0]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 1] = tileset[ theme + "-corner-tr" ][1]; - // tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 2] = tileset[ theme + "-corner-tr" ][2]; - - - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 0] = tileset[ theme + "-corner-br" ][0]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 1] = tileset[ theme + "-corner-br" ][1]; - // tilemap[(h + y - 1) * CELL_WIDTH * CELL_COUNT_X * 3 + (x + w - 1) * 3 + 2] = tileset[ theme + "-corner-br" ][2]; } fn generateCorridorData(rng: opaque) { @@ -419,6 +374,189 @@ fn etchLine(x: int, y: int, xLength: int, yLength: int, theme: string, rng: opaq } } +fn etchWalls(roomData) { + //zero'd signals + var signals: [string] = []; + + for (var j: int = 0; j < CELL_COUNT_Y * CELL_HEIGHT; j++) { + for (var i: int = 0; i < CELL_COUNT_X * CELL_WIDTH; i++) { + signals.push(""); //empty + } + } + + //determine the walls' layout from the tilemap + for (var i: int = 0; i < MAP_GRID_WIDTH; i++) { + for (var j: int = 0; j < MAP_GRID_HEIGHT; j++) { + signals[j * MAP_GRID_WIDTH + i] = parseTilemapAt(i, j); + } + } + + //etch the walls into the tilemap, based on the room theme + for (var i: int = 0; i < MAP_GRID_WIDTH; i++) { + for (var j: int = 0; j < MAP_GRID_HEIGHT; j++) { + if (signals[j * MAP_GRID_WIDTH + i] == "") { + continue; + } + + var theme = roomData[floor(i / CELL_WIDTH)][floor(j / CELL_HEIGHT)]["theme"]; + tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 0] = tileset[theme + "-" + signals[j * MAP_GRID_WIDTH + i]][0]; + tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 1] = tileset[theme + "-" + signals[j * MAP_GRID_WIDTH + i]][1]; + tilemap[j * CELL_WIDTH * CELL_COUNT_X * 3 + i * 3 + 2] = tileset[theme + "-" + signals[j * MAP_GRID_WIDTH + i]][2]; + } + } +} + +/* +//lets say snapshot looks like this +snapshot: + +0, 0, 1 +0, 0, 1 +0, 0, 1 + +result should be "wall-l", + +//lets say filter looks like this +filter: + +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 + +find the position within the filter, that gives the result "wall-l" + +//lets say result looks like this + +"edge-br" "wall-b" "edge-bl" +"wall-r" "pillar" "wall-l" +"edge-tr" "wall-t" "edge-tl" + +let's try this... + +*/ + +/* 9x9 +var marchingFilter: [int] const = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1 +]; + +var marchingFilterResult: [string] const = [ +"", "", "", "", "", "", "", "", "", +"", "edge-tr", "wall-b", "wall-b", "wall-b", "wall-b", "wall-b", "edge-tl", "", +"", "wall-r", "corner-tl", "wall-t", "wall-t", "wall-t", "corner-tr", "wall-l", "", +"", "wall-r", "wall-l", "", "", "", "wall-r", "wall-l", "", +"", "wall-r", "wall-l", "", "", "", "wall-r", "wall-l", "", +"", "wall-r", "wall-l", "", "", "", "wall-r", "wall-l", "", +"", "wall-r", "corner-bl", "wall-b", "wall-b", "wall-b", "corner-br", "wall-l", "", +"", "edge-br", "wall-t", "wall-t", "wall-t", "wall-t", "wall-t", "edge-bl", "", +"", "", "", "", "", "", "", "", "" +]; +*/ + + +//this is a nightmare +var marchingFilter: [int] const = [ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, +1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, +1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, +1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, +1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, +1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +]; + +var marchingFilterResult: [string] const = [ +"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" , +"" ,"" ,"edge-tl" ,"wall-b" ,"wall-b" ,"wall-b" ,"wall-b" ,"wall-b" ,"wall-b" ,"edge-tr" ,"" ,"" , +"" ,"edge-tl" ,"corner-br" ,"" ,"corner-tl" ,"wall-t" ,"wall-t" ,"corner-tr" ,"" ,"corner-bl" ,"edge-tr" ,"" , +"" ,"wall-r" ,"" ,"" ,"wall-l" ,"" ,"" ,"wall-r" ,"" ,"" ,"wall-l" ,"" , +"" ,"wall-r" ,"corner-tl" ,"wall-t" ,"edge-br" ,"" ,"" ,"edge-bl" ,"wall-t" ,"corner-tr" ,"wall-l" ,"" , +"" ,"wall-r" ,"wall-l" ,"" ,"" ,"" ,"" ,"" ,"" ,"wall-r" ,"wall-l" ,"" , +"" ,"wall-r" ,"wall-l" ,"" ,"" ,"" ,"" ,"" ,"" ,"wall-r" ,"wall-l" ,"" , +"" ,"wall-r" ,"corner-bl" ,"wall-b" ,"edge-tr" ,"" ,"" ,"edge-tl" ,"wall-b" ,"corner-br" ,"wall-l" ,"" , +"" ,"wall-r" ,"" ,"" ,"wall-l" ,"" ,"" ,"wall-r" ,"" ,"" ,"wall-l" ,"" , +"" ,"edge-bl" ,"corner-tr" ,"" ,"corner-bl" ,"wall-b" ,"wall-b" ,"corner-br" ,"" ,"corner-tl" ,"edge-br" ,"" , +"" ,"" ,"edge-bl" ,"wall-t" ,"wall-t" ,"wall-t" ,"wall-t" ,"wall-t" ,"wall-t" ,"edge-br" ,"" ,"" , +"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" +]; + + +//if walkable is below, then return top, etc. +fn parseTilemapAt(x: int, y: int) { + //parse based on walkability, for now + if (tilemap[y * CELL_WIDTH * CELL_COUNT_X * 3 + x * 3 + 2] != 0) { + return ""; //empty + } + + //generate the snapshot of the current position + var snapshot = generateSnapshotAt(x, y); + + //find the snapshot's position within the filter + for (var i: int = 0; i < 12 -2; i++) { + for (var j: int = 0; j < 12 -2; j++) { + if ( + marchingFilter[(j + 0) * 12 + (i + 0)] == snapshot[0 * 3 + 0] && + marchingFilter[(j + 0) * 12 + (i + 1)] == snapshot[0 * 3 + 1] && + marchingFilter[(j + 0) * 12 + (i + 2)] == snapshot[0 * 3 + 2] && + + marchingFilter[(j + 1) * 12 + (i + 0)] == snapshot[1 * 3 + 0] && + marchingFilter[(j + 1) * 12 + (i + 1)] == snapshot[1 * 3 + 1] && + marchingFilter[(j + 1) * 12 + (i + 2)] == snapshot[1 * 3 + 2] && + + marchingFilter[(j + 2) * 12 + (i + 0)] == snapshot[2 * 3 + 0] && + marchingFilter[(j + 2) * 12 + (i + 1)] == snapshot[2 * 3 + 1] && + marchingFilter[(j + 2) * 12 + (i + 2)] == snapshot[2 * 3 + 2] + ) + { + return marchingFilterResult[(j+1) * 12 + (i+1)]; + } + } + } + + //anything else, just plop down a pillar + fn nonZero(key: int, value: int) { + return value != 0; + } + + if (snapshot.some(nonZero)) { + return "pillar"; + } + + return ""; +} + +fn generateSnapshotAt(x: int, y: int) { + var result: [int] = []; + + for (var j: int = -1; j < 2; j++) { + for (var i: int = -1; i < 2; i++) { + if (x + i < 0 || y + j < 0 || x + i >= MAP_GRID_WIDTH || y + j >= MAP_GRID_HEIGHT) { + result.push(0); + } + else { + result.push(tilemap[(y+j) * CELL_WIDTH * CELL_COUNT_X * 3 + (x+i) * 3 + 2] != 0 ? 1 : 0); //walkable + } + } + } + + return result; +} + //polyfill fn sign(x) { if (x > 0) return 1;