From b1ee4859056f21e49aeaff0a5655f4238b89340a Mon Sep 17 00:00:00 2001 From: Ratstail91 Date: Sun, 5 Mar 2023 05:13:53 +1100 Subject: [PATCH] Grid-based movement and collisions working --- assets/scripts/gameplay/lejana.toy | 171 +++++++++++++++++----------- assets/scripts/gameplay/scene.toy | 34 ++++++ assets/scripts/gameplay/tilemap.toy | 78 ++++++++----- assets/scripts/init.toy | 2 +- box/lib_node.c | 4 +- 5 files changed, 190 insertions(+), 99 deletions(-) diff --git a/assets/scripts/gameplay/lejana.toy b/assets/scripts/gameplay/lejana.toy index 66744ae..56887e7 100644 --- a/assets/scripts/gameplay/lejana.toy +++ b/assets/scripts/gameplay/lejana.toy @@ -1,72 +1,133 @@ +import standard; import node; //constants var SPEED: int const = 3; +var SPRITE_WIDTH: int const = 64; +var SPRITE_HEIGHT: int const = 64; + + //variables var parent: opaque = null; //cache the parent for quick access -var posX: int = 50; -var posY: int = 50; -var WIDTH: int const = 128; -var HEIGHT: int const = 128; -var xspeed: int = 0; -var yspeed: int = 0; +var gridX: int = 1; //position on the game grid +var gridY: int = 1; + +var realX: int = 0; //will change until realX = gridX * SPRITE_WIDTH +var realY: int = 0; + +var motionX: int = 0; //normalized movement direction +var motionY: int = 0; + +var inputX: int = 0; //cache the keyboard input +var inputY: int = 0; //polyfills - animating different cycles on one image -var SPRITE_WIDTH: int const = 32; -var SPRITE_HEIGHT: int const = 32; var stepCount: int = 0; -var stepDelay: int = 10; fn faceDown(node: opaque) { - node.setNodeRect(0, 0, SPRITE_WIDTH, SPRITE_HEIGHT); + node.setNodeRect(0, 0, 32, 32); node.setNodeFrames(4); } fn faceUp(node: opaque) { - node.setNodeRect(32 * 4, 0, SPRITE_WIDTH, SPRITE_HEIGHT); + node.setNodeRect(32 * 4, 0, 32, 32); node.setNodeFrames(4); } fn faceLeft(node: opaque) { - node.setNodeRect(32 * 12, 0, SPRITE_WIDTH, SPRITE_HEIGHT); + node.setNodeRect(32 * 12, 0, 32, 32); node.setNodeFrames(4); } fn faceRight(node: opaque) { - node.setNodeRect(32 * 8, 0, SPRITE_WIDTH, SPRITE_HEIGHT); + node.setNodeRect(32 * 8, 0, 32, 32); node.setNodeFrames(4); } +//polyfills - move these to standard +fn normalize(x): int { + if (x > 0) { + return 1; + } + if (x < 0) { + return -1; + } + return 0; +} + //lifecycle functions fn onLoad(node: opaque) { - // -} - -fn onInit(node: opaque) { - parent = node.getParentNode(); node.loadTexture("sprites:/lejana.png"); node.faceDown(); } -fn onStep(node: opaque) { - posX += xspeed; - posY += yspeed; +fn onInit(node: opaque) { + parent = node.getParentNode(); +} - //animate after X steps - if (xspeed == 0 && yspeed == 0) { +fn onStep(node: opaque) { + //process input when aligned to a grid + if (realX / SPRITE_WIDTH == gridX && realY / SPRITE_HEIGHT == gridY && motionX == 0 && motionY == 0) { + //disallow wall phasing + if (parent.callNodeFn("getCollisionAt", gridX + inputX, gridY) != true) { + inputX = 0; + } + + if (parent.callNodeFn("getCollisionAt", gridX, gridY + inputY) != true) { + inputY = 0; + } + + //disallow diagonal movement + if (abs(inputX) != 0) { + gridX += inputX; + } + else { + gridY += inputY; + } + + //facing + if (inputY > 0) { + node.faceDown(); + } + + if (inputY < 0) { + node.faceUp(); + } + + if (inputX > 0) { + node.faceRight(); + } + + if (inputX < 0) { + node.faceLeft(); + } + } + + //animation + if (motionX == 0 && motionY == 0) { stepCount = 0; node.setCurrentNodeFrame(0); } - else { - if (++stepCount >= stepDelay) { - node.incrementCurrentNodeFrame(); - stepCount = 0; - } + + if (++stepCount >= 10) { + node.incrementCurrentNodeFrame(); + stepCount = 0; } + + //calc movement + var distX = gridX * SPRITE_WIDTH - realX; + var distY = gridY * SPRITE_HEIGHT - realY; + + motionX = normalize(distX); + motionY = normalize(distY); + + //make movement + realX += abs(distX) > SPEED ? SPEED * motionX : distX; + realY += abs(distY) > SPEED ? SPEED * motionY : distY; } fn onFree(node: opaque) { @@ -80,75 +141,55 @@ fn onDraw(node: opaque) { if (parent != null) { px = parent.callNodeFn("getX"); py = parent.callNodeFn("getY"); + + px = px != null ? px : 0; + py = py != null ? py : 0; } - node.drawNode(posX + px, posY + py, WIDTH, HEIGHT); + node.drawNode(realX + px, realY + py, SPRITE_WIDTH, SPRITE_HEIGHT); } //event functions fn onKeyDown(node: opaque, event: string) { if (event == "character_up") { - yspeed -= SPEED; - faceUp(node); + inputY -= 1; return; } if (event == "character_down") { - yspeed += SPEED; - faceDown(node); + inputY += 1; return; } if (event == "character_left") { - xspeed -= SPEED; - faceLeft(node); + inputX -= 1; return; } if (event == "character_right") { - xspeed += SPEED; - faceRight(node); + inputX += 1; return; } } fn onKeyUp(node: opaque, event: string) { - if (event == "character_up" && yspeed < 0) { - yspeed = 0; + if (event == "character_up" && inputY < 0) { + inputY = 0; return; } - if (event == "character_down" && yspeed > 0) { - yspeed = 0; + if (event == "character_down" && inputY > 0) { + inputY = 0; return; } - if (event == "character_left" && xspeed < 0) { - xspeed = 0; + if (event == "character_left" && inputX < 0) { + inputX = 0; return; } - if (event == "character_right" && xspeed > 0) { - xspeed = 0; + if (event == "character_right" && inputX > 0) { + inputX = 0; return; } -} - -fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) { - // -} - -fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) { - //jump to pos - posX = x - WIDTH / 2; - posY = y - HEIGHT / 2; -} - -fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) { - // -} - -fn onMouseWheel(node: opaque, xrel: int, yrel: int) { - // -} - +} \ No newline at end of file diff --git a/assets/scripts/gameplay/scene.toy b/assets/scripts/gameplay/scene.toy index e69de29..6a9b7a5 100644 --- a/assets/scripts/gameplay/scene.toy +++ b/assets/scripts/gameplay/scene.toy @@ -0,0 +1,34 @@ +import standard; +import node; + +var tilemap: opaque = null; +var player: opaque = null; + +var collisionMap: [[bool]] = null; //cache this, since it won't change during a level + +//lifecycle functions +fn onLoad(node: opaque) { + tilemap = node.loadChild("scripts:/gameplay/tilemap.toy"); + player = node.loadChild("scripts:/gameplay/lejana.toy"); +} + +fn onInit(node: opaque) { + tilemap.callNodeFn("generateFromSeed", clock().hash(), 8, 8); + collisionMap = tilemap.callNodeFn("getCollisionMap"); +} + +//utils - polyfills +fn loadChild(parent: opaque, fname: string) { + var child: opaque = loadNode(fname); + parent.pushNode(child); + return child; +} + +//connective functions +fn getCollisionAt(node: opaque, x: int, y: int) { + if (collisionMap == null) { + return false; + } + + return collisionMap[x][y]; +} diff --git a/assets/scripts/gameplay/tilemap.toy b/assets/scripts/gameplay/tilemap.toy index fecee15..e41ab50 100644 --- a/assets/scripts/gameplay/tilemap.toy +++ b/assets/scripts/gameplay/tilemap.toy @@ -2,9 +2,6 @@ import standard; import node; //consts -var ROOM_WIDTH: int const = 8; -var ROOM_HEIGHT: int const = 8; - var TILE_WIDTH: int const = 64; var TILE_HEIGHT: int const = 64; @@ -13,27 +10,27 @@ var tilemap: [[string]] = null; var collisions: [[bool]] = null; var tileset: [string : [int]] = [ - "pillar": [0, 0, 1], + "pillar": [0, 0, 0], - "floor-0": [0, 1, 0], - "floor-1": [1, 1, 0], - "floor-2": [2, 1, 0], - "floor-3": [3, 1, 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, 1], - "wall-b": [1, 2, 1], - "wall-l": [2, 2, 1], - "wall-r": [3, 2, 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, 1], - "corner-tr": [1, 3, 1], - "corner-bl": [2, 3, 1], - "corner-br": [3, 3, 1], + "corner-tl": [0, 3, 0], + "corner-tr": [1, 3, 0], + "corner-bl": [2, 3, 0], + "corner-br": [3, 3, 0], - "edge-tl": [0, 4, 1], - "edge-tr": [1, 4, 1], - "edge-bl": [2, 4, 1], - "edge-br": [3, 4, 1] + "edge-tl": [0, 4, 0], + "edge-tr": [1, 4, 0], + "edge-bl": [2, 4, 0], + "edge-br": [3, 4, 0] ]; @@ -45,34 +42,41 @@ var camH = 720; //lifecycle functions -fn onInit(node: opaque) { +fn onLoad(node: opaque) { node.loadTexture("sprites:/tileset.png"); - - tilemap = generateTilemap(clock().hash(), ROOM_WIDTH, ROOM_HEIGHT); - collisions = bakeCollisionMap(tilemap, ROOM_WIDTH, ROOM_HEIGHT); - - print tilemap; - print collisions; } fn onDraw(node: opaque) { + if (tilemap == null) { + return; + } + //calc the region to render var lowerX: int = round((camX - camW/2.0) / TILE_WIDTH); var upperX: int = round((camX - camW*1.5) / TILE_WIDTH); var lowerY: int = round((camY - camH/2.0) / TILE_HEIGHT); var upperY: int = round((camY - camH*1.5) / TILE_HEIGHT); + var rwidth = 0; + var rheight = 0; + + if (tilemap.length() != 0) { + rwidth = tilemap.length(); + + if (tilemap[0].length() != 0) { + rheight = (tilemap[0].length()); //TODO: Some kind of Toy bug here, use parentheses + } + } + //bounds check lowerX = max(0, lowerX); - upperX = min(upperX < 0 ? abs(upperX) : 0, ROOM_WIDTH); + upperX = min(upperX < 0 ? abs(upperX) : 0, rwidth); lowerY = max(0, lowerY); - upperY = min(upperY < 0 ? abs(upperY) : 0, ROOM_HEIGHT); - + upperY = min(upperY < 0 ? abs(upperY) : 0, rheight); //draw the tilemap for (var j = lowerY; j < upperY; j++) { for (var i = lowerX; i < upperX; i++) { - var pos = tileset[tilemap[i][j]]; node.setNodeRect(pos[0] * 16, pos[1] * 16, 16, 16); @@ -83,6 +87,14 @@ fn onDraw(node: opaque) { //utils functions for map generation +fn generateFromSeed(node: opaque, seed: int, width: int, height: int) { + tilemap = generateTilemap(seed, width, height); + collisions = bakeCollisionMap(tilemap, width, height); + + print tilemap; + print collisions; +} + fn generateTilemap(seed: int, width: int, height: int) { import random; var rng: opaque = createRandomGenerator(seed); @@ -152,3 +164,7 @@ fn bakeCollisionMap(tilemap: [[string]], width: int, height: int) { return result; } + +fn getCollisionMap(node: opaque) { + return collisions; +} \ No newline at end of file diff --git a/assets/scripts/init.toy b/assets/scripts/init.toy index f531a69..6204726 100644 --- a/assets/scripts/init.toy +++ b/assets/scripts/init.toy @@ -31,7 +31,7 @@ initWindow("Skyland", 1080, 720, false); //kick off the logic of the scene graph - loadRootNode("scripts:/gameplay/tilemap.toy"); + loadRootNode("scripts:/gameplay/scene.toy"); } //Globals go here diff --git a/box/lib_node.c b/box/lib_node.c index ac5f323..aad6930 100644 --- a/box/lib_node.c +++ b/box/lib_node.c @@ -750,7 +750,7 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume static int nativeCallNodeFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //checks if (arguments->count < 2) { - interpreter->errorOutput("Too few arguments passed to callNode\n"); + interpreter->errorOutput("Too few arguments passed to callNodeFn\n"); return -1; } @@ -797,7 +797,7 @@ static int nativeCallNodeFn(Toy_Interpreter* interpreter, Toy_LiteralArray* argu } if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_STRING(fnName)) { - interpreter->errorOutput("Incorrect argument type passed to callNode\n"); + interpreter->errorOutput("Incorrect argument type passed to callNodeFn\n"); Toy_freeLiteral(nodeLiteral); Toy_freeLiteral(fnName); return -1;