diff --git a/Toy b/Toy index f869c94..f84cdff 160000 --- a/Toy +++ b/Toy @@ -1 +1 @@ -Subproject commit f869c9425a9070e243d975f4fe7748662ce27f6b +Subproject commit f84cdff88319108d1a8e0f910700ec5d570af9f4 diff --git a/assets/scripts/empty.toy b/assets/scripts/empty.toy index 2b82815..8776059 100644 --- a/assets/scripts/empty.toy +++ b/assets/scripts/empty.toy @@ -1 +1,6 @@ -//this file is a polyfill TODO: fix this \ No newline at end of file +//this file is a polyfill TODO: fix this + +fn onDraw(node: opaque) { + //debug draw at the origin + node.drawNode(0, 0); +} \ No newline at end of file diff --git a/assets/scripts/gameplay/drone.toy b/assets/scripts/gameplay/drone.toy index 7d8dfd7..35fac16 100644 --- a/assets/scripts/gameplay/drone.toy +++ b/assets/scripts/gameplay/drone.toy @@ -1,5 +1,6 @@ import standard; import node; +import random; //constants var SPEED: int const = 4; @@ -140,8 +141,6 @@ fn runAI(node: opaque, rng: opaque) { if ((stepAI++) >= 1) { //TODO: Toy bug here, something to do with precedence of postfix++? stepAI = 0; - import random; - var dir = rng.generateRandomNumber() % 4; var moveX = 0; var moveY = 0; diff --git a/assets/scripts/gameplay/scene.toy b/assets/scripts/gameplay/scene.toy index af74c83..cac5b48 100644 --- a/assets/scripts/gameplay/scene.toy +++ b/assets/scripts/gameplay/scene.toy @@ -1,5 +1,6 @@ import standard; import node; +import random; //consts var TILE_WIDTH: int const = 32; @@ -11,6 +12,7 @@ var MAP_HEIGHT: int const = 16; var tilemap: opaque = null; var player: opaque = null; + var enemies: [opaque] = []; var entities: [opaque] = null; //full list of entities @@ -23,14 +25,25 @@ var rng: opaque = null; var stepCounter: int = 0; var drawCounter: int = 0; +var textNode: opaque = null; + //lifecycle functions fn onLoad(node: opaque) { tilemap = node.loadChild("scripts:/gameplay/tilemap.toy"); player = node.loadChild("scripts:/gameplay/lejana.toy"); + textNode = node.loadChild("scripts:/empty.toy"); } fn onInit(node: opaque) { node.generateLevel(clock().hash(), MAP_WIDTH, MAP_HEIGHT); + + //debugging +// textNode.setNodeText("fonts:/alphbeta.ttf", 48, "Hello world", 128, 0, 0, 255); + textNode.setNodeText("fonts:/Ancient God.ttf", 48, "Hello world", 128, 0, 0, 255); +} + +fn onFree(node: opaque) { + rng.freeRandomGenerator(); } fn onStep(node: opaque) { @@ -46,7 +59,7 @@ fn onStep(node: opaque) { fn onDraw(node: opaque) { drawCounter++; - //call each child's custom sort fn + //call each child's custom draw fn tilemap.callNodeFn("customOnDraw"); for (var i = 0; i < entities.length(); i++) { entities[i].callNodeFn("customOnDraw"); @@ -66,8 +79,6 @@ fn generateLevel(node: opaque, seed: int, width: int, height: int) { enemies = []; entities = [player]; //assume the player exists already - import random; - if (rng != null) rng.freeRandomGenerator(); rng = createRandomGenerator(seed); @@ -91,7 +102,7 @@ fn generateLevel(node: opaque, seed: int, width: int, height: int) { var y = 0; //while generated spot is a collision, or too close to the player - while ((x == 0 && y == 0) || node.getCollisionAt(x, y) == false || (x < (width / 3 * 2) && y < (height / 3 * 2))) { //TODO: toy bug - no short-circuiting? + while ((x == 0 && y == 0) || node.getCollisionAt(x, y) == false || (x < (width / 6 * 2) && y < (height / 6 * 2))) { //TODO: toy bug - no short-circuiting? x = rng.generateRandomNumber() % width; y = rng.generateRandomNumber() % height; } diff --git a/box/box_engine_node.c b/box/box_engine_node.c index 53f3f11..5f3a77d 100644 --- a/box/box_engine_node.c +++ b/box/box_engine_node.c @@ -271,7 +271,21 @@ void Box_incrementCurrentFrame(Box_EngineNode* node) { } } +void Box_setTextEngineNode(Box_EngineNode* node, TTF_Font* font, const char* text, SDL_Color color) { + SDL_Surface* surface = TTF_RenderText_Solid(font, text, color); + + node->texture = SDL_CreateTextureFromSurface(engine.renderer, surface); + + node->rect = (SDL_Rect){ .x = 0, .y = 0, .w = surface->w, .h = surface->h }; + node->frames = 1; + node->currentFrame = 0; + + SDL_FreeSurface(surface); +} + + void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest) { + if (!node->texture) return; SDL_Rect src = node->rect; src.x += src.w * node->currentFrame; //TODO: improve this SDL_RenderCopy(engine.renderer, node->texture, &src, &dest); diff --git a/box/box_engine_node.h b/box/box_engine_node.h index 11d3a0e..701a7d9 100644 --- a/box/box_engine_node.h +++ b/box/box_engine_node.h @@ -69,4 +69,6 @@ BOX_API void Box_setCurrentFrameEngineNode(Box_EngineNode* node, int currentFram BOX_API int Box_getCurrentFrameEngineNode(Box_EngineNode* node); BOX_API void Box_incrementCurrentFrame(Box_EngineNode* node); +BOX_API void Box_setTextEngineNode(Box_EngineNode* node, TTF_Font* font, const char* text, SDL_Color color); + BOX_API void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest); diff --git a/box/lib_node.c b/box/lib_node.c index aad6930..b390587 100644 --- a/box/lib_node.c +++ b/box/lib_node.c @@ -747,6 +747,139 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume return 0; } +static int nativeSetNodeText(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 8) { + interpreter->errorOutput("Incorrect number of arguments passed to setNodeText\n"); + return -1; + } + + //extract the arguments + Toy_Literal aLiteral = Toy_popLiteralArray(arguments); + Toy_Literal bLiteral = Toy_popLiteralArray(arguments); + Toy_Literal gLiteral = Toy_popLiteralArray(arguments); + Toy_Literal rLiteral = Toy_popLiteralArray(arguments); + Toy_Literal textLiteral = Toy_popLiteralArray(arguments); + Toy_Literal sizeLiteral = Toy_popLiteralArray(arguments); + Toy_Literal fontLiteral = Toy_popLiteralArray(arguments); + Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal nodeLiteralIdn = nodeLiteral; + if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) { + Toy_freeLiteral(nodeLiteralIdn); + } + + Toy_Literal fontLiteralIdn = fontLiteral; + if (TOY_IS_IDENTIFIER(fontLiteral) && Toy_parseIdentifierToValue(interpreter, &fontLiteral)) { + Toy_freeLiteral(fontLiteralIdn); + } + + Toy_Literal sizeLiteralIdn = sizeLiteral; + if (TOY_IS_IDENTIFIER(sizeLiteral) && Toy_parseIdentifierToValue(interpreter, &sizeLiteral)) { + Toy_freeLiteral(sizeLiteralIdn); + } + + Toy_Literal textLiteralIdn = textLiteral; + if (TOY_IS_IDENTIFIER(textLiteral) && Toy_parseIdentifierToValue(interpreter, &textLiteral)) { + Toy_freeLiteral(textLiteralIdn); + } + + Toy_Literal rLiteralIdn = rLiteral; + if (TOY_IS_IDENTIFIER(rLiteral) && Toy_parseIdentifierToValue(interpreter, &rLiteral)) { + Toy_freeLiteral(rLiteralIdn); + } + + Toy_Literal gLiteralIdn = gLiteral; + if (TOY_IS_IDENTIFIER(gLiteral) && Toy_parseIdentifierToValue(interpreter, &gLiteral)) { + Toy_freeLiteral(gLiteralIdn); + } + + Toy_Literal bLiteralIdn = bLiteral; + if (TOY_IS_IDENTIFIER(bLiteral) && Toy_parseIdentifierToValue(interpreter, &bLiteral)) { + Toy_freeLiteral(bLiteralIdn); + } + + Toy_Literal aLiteralIdn = aLiteral; + if (TOY_IS_IDENTIFIER(aLiteral) && Toy_parseIdentifierToValue(interpreter, &aLiteral)) { + Toy_freeLiteral(aLiteralIdn); + } + + //check argument types + if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_STRING(fontLiteral) || !TOY_IS_INTEGER(sizeLiteral) || !TOY_IS_STRING(textLiteral) + || !TOY_IS_INTEGER(rLiteral) || !TOY_IS_INTEGER(gLiteral) || !TOY_IS_INTEGER(bLiteral) || !TOY_IS_INTEGER(aLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to setNodeText\n"); + Toy_freeLiteral(nodeLiteral); + Toy_freeLiteral(fontLiteral); + Toy_freeLiteral(sizeLiteral); + Toy_freeLiteral(textLiteral); + Toy_freeLiteral(rLiteral); + Toy_freeLiteral(gLiteral); + Toy_freeLiteral(bLiteral); + Toy_freeLiteral(aLiteral); + return -1; + } + + //bounds checks + if (TOY_AS_INTEGER(rLiteral) < 0 || TOY_AS_INTEGER(rLiteral) > 255 || + TOY_AS_INTEGER(gLiteral) < 0 || TOY_AS_INTEGER(gLiteral) > 255 || + TOY_AS_INTEGER(bLiteral) < 0 || TOY_AS_INTEGER(bLiteral) > 255 || + TOY_AS_INTEGER(aLiteral) < 0 || TOY_AS_INTEGER(aLiteral) > 255) { + interpreter->errorOutput("Color out of bounds in to setNodeText\n"); + Toy_freeLiteral(nodeLiteral); + Toy_freeLiteral(fontLiteral); + Toy_freeLiteral(sizeLiteral); + Toy_freeLiteral(textLiteral); + Toy_freeLiteral(rLiteral); + Toy_freeLiteral(gLiteral); + Toy_freeLiteral(bLiteral); + Toy_freeLiteral(aLiteral); + return -1; + } + + //get the font + Toy_Literal fileLiteral = Toy_getFilePathLiteral(interpreter, &fontLiteral); + + TTF_Font* font = TTF_OpenFont( Toy_toCString(TOY_AS_STRING(fileLiteral)), TOY_AS_INTEGER(sizeLiteral) ); + + if (!font) { + interpreter->errorOutput("Failed to open a font file: "); + interpreter->errorOutput(SDL_GetError()); + interpreter->errorOutput("\n"); + + Toy_freeLiteral(fileLiteral); + Toy_freeLiteral(nodeLiteral); + Toy_freeLiteral(fontLiteral); + Toy_freeLiteral(sizeLiteral); + Toy_freeLiteral(textLiteral); + Toy_freeLiteral(rLiteral); + Toy_freeLiteral(gLiteral); + Toy_freeLiteral(bLiteral); + Toy_freeLiteral(aLiteral); + return -1; + } + + //make the color + SDL_Color color = (SDL_Color){ .r = TOY_AS_INTEGER(rLiteral), .g = TOY_AS_INTEGER(gLiteral), .b = TOY_AS_INTEGER(bLiteral), .a = TOY_AS_INTEGER(aLiteral) }; + + //actually set + Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral); + Box_setTextEngineNode(node, font, Toy_toCString(TOY_AS_STRING(textLiteral)), color); + + //cleanup + TTF_CloseFont(font); + + Toy_freeLiteral(fileLiteral); + Toy_freeLiteral(nodeLiteral); + Toy_freeLiteral(fontLiteral); + Toy_freeLiteral(sizeLiteral); + Toy_freeLiteral(textLiteral); + Toy_freeLiteral(rLiteral); + Toy_freeLiteral(gLiteral); + Toy_freeLiteral(bLiteral); + Toy_freeLiteral(aLiteral); + + return 0; +} + static int nativeCallNodeFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //checks if (arguments->count < 2) { @@ -847,6 +980,7 @@ int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter {"getCurrentNodeFrame", nativeGetCurrentNodeFrame}, {"incrementCurrentNodeFrame", nativeIncrementCurrentNodeFrame}, {"drawNode", nativeDrawNode}, + {"setNodeText", nativeSetNodeText}, {"callNodeFn", nativeCallNodeFn}, //TODO: get rect, get node var, create empty node