diff --git a/README.md b/README.md index 527d471..b5d3131 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); ``` > [!WARNING] @@ -55,19 +55,19 @@ The final line modifies the default app.d and dub.json files, downloads raylib, * assets: This folder is used to store game assets. * web: This folder is used for exporting to the web. -Once the installation is complete, you should be able to compile/run with: +Once the installation is complete, run the following command: ```bash dub run ``` -You can pass `offline` to the script if you don't want to download raylib. -For more info about exporting to web, read [this](#web-support). +If everything is set up correctly, a window will appear showing the message "Hello world!". +To avoid downloading raylib, pass `offline` to the script. ## Documentation -For an initial understanding, the [examples](examples) folder and the [engine.d](source/popka/game/engine.d) file can be a good starting point. -You can also read the [TOUR.md](TOUR.md) file for a more in-depth overview. +For an initial understanding, the [examples](examples) folder can be a good starting point. +For a more detailed overview, check the [TOUR.md](TOUR.md) file. ## Attributes and BetterC Support @@ -76,9 +76,8 @@ If you encounter errors with BetterC, try using the `-i` flag. ## Web Support -For exporting to web, your project needs to be compatible with BetterC. +To export a game to the web, the game must be compatible with BetterC. The [web](web) folder contains a helper script to assist with the web export process. -If you use DUB, you can run the script with: ```bash dub run popka:web diff --git a/TOUR.md b/TOUR.md index a5dcff0..cf550b9 100644 --- a/TOUR.md +++ b/TOUR.md @@ -1,12 +1,8 @@ -# Tour - -> [!WARNING] -> I am still working on this. +# Tour (WIP) ## Understanding the Code -Let's get started with Popka by creating a simple game that displays the classic message "Hello world!". -Open your app.d file and paste the following code: +To begin, open the main file of your project and copy-paste the following code: ```d import popka; @@ -21,10 +17,11 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); ``` -Let's see how everything works: +This code will create a window that displays the message "Hello world!". +Here is a breakdown of how this code works: 1. Game Loop @@ -36,9 +33,9 @@ Let's see how everything works: ``` This function is the main loop of the game. - It runs every frame, and in this example, it draws the message "Hello world!" on the window. - The `return false` statement tells the game to keep running. - If true is returned, then the program will stop running. + It runs every frame and, in this example, draws the message "Hello world!". + The `return false` statement indicates that the game should continue running. + If `true` were returned, the game would stop. 2. Game Start @@ -47,27 +44,25 @@ Let's see how everything works: lockResolution(320, 180); updateWindow!gameLoop(); } - - mixin addGameStart!(gameStart, 640, 360); ``` This function is the starting point of the game. - It runs only once, and in this example, it locks the game resolution to 320 pixels wide and 180 pixels tall. - The `updateWindow!gameLoop()` call starts the game loop. + It runs only once and, in this example, locks the game resolution to 320 pixels wide and 180 pixels tall. + The `updateWindow!gameLoop` call starts the main game loop. 3. Mixin ```d - mixin addGameStart!(gameStart, 640, 360) + mixin callGameStart!(gameStart, 640, 360) ``` - The line makes sure the `gameStart` function runs when your game starts, - and in this example, it creates a game window that is 640 pixels wide and 360 pixels tall. + This line sets up the `gameStart` function to run when the game starts + and, in this example, creates a game window that is 640 pixels wide and 360 pixels tall. In essence, a Popka game typically relies on two key functions: -* A game loop function. -* A game start function. +* A loop function. +* A start function. ## Drawing @@ -75,18 +70,18 @@ Popka provides a set of drawing functions. While drawing is not pixel-perfect by default, you can enable pixel-perfect drawing by calling the `togglePixelPerfect` function. ```d -// Basic Drawing Functions void drawRect(Rect area, Color color = white); void drawVec2(Vec2 point, float size, Color color = white); void drawCirc(Circ area, Color color = white); void drawLine(Line area, float size, Color color = white); + void drawTexture(Texture texture, Vec2 position, Rect area, DrawOptions options = DrawOptions()); void drawTexture(Texture texture, Vec2 position, DrawOptions options = DrawOptions()); + void drawRune(Font font, Vec2 position, dchar rune, DrawOptions options = DrawOptions()); void drawText(Font font, Vec2 position, IStr text, DrawOptions options = DrawOptions()); void drawDebugText(IStr text, Vec2 position = Vec2(8.0f), DrawOptions options = DrawOptions()); -// Tile Map Drawing Functions void drawTile(Texture texture, Vec2 position, int tileID, Vec2 tileSize, DrawOptions options = DrawOptions()); void drawTileMap(Texture texture, Vec2 position, TileMap tileMap, Camera camera, DrawOptions options = DrawOptions()); ``` @@ -95,5 +90,11 @@ void drawTileMap(Texture texture, Vec2 position, TileMap tileMap, Camera camera, Functions that start with the word load/save will always try to read/write from/to the assets folder. These functions handle both forward slashes and backslashes in file paths, ensuring compatibility across operating systems. -For instance, `loadText("levels/level5.txt")` and `loadText("levels\\level5.txt")` will function identically on any operating system. -Also, if you need text data for just a single frame, consider using the `loadTempText` function. + +```d +loadText("levels/level5.txt"); +loadText("levels\\level5.txt"); +``` + +Both of these calls will function identically on any operating system. +Also, if text is needed for only a single frame, use the `loadTempText` function. diff --git a/examples/camera.d b/examples/camera.d index 11a625a..f576b30 100644 --- a/examples/camera.d +++ b/examples/camera.d @@ -30,4 +30,4 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/coins.d b/examples/coins.d index bf18cf2..1c46f32 100644 --- a/examples/coins.d +++ b/examples/coins.d @@ -66,4 +66,4 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/dialogue.d b/examples/dialogue.d index 38b466a..a35cf96 100644 --- a/examples/dialogue.d +++ b/examples/dialogue.d @@ -1,15 +1,15 @@ -/// This example shows how to use the Popka chat system. +/// This example shows how to use the Popka dialogue system. import popka; // The game variables. -auto chat = Chat(); +auto dialogue = Dialogue(); auto script = " # This is a comment. ! choiceCount * menuPoint - ^ Select first choice. ^ Select second choice. ^ End chat. + ^ Select first choice. ^ Select second choice. ^ End dialogue. * choice1 > Bob @@ -34,34 +34,34 @@ auto script = " bool gameLoop() { // Update the game. - if (chat.canUpdate) { - if (chat.hasChoices) { - auto keys = digitChars[1 .. 1 + chat.choices.length]; + if (dialogue.canUpdate) { + if (dialogue.hasChoices) { + auto keys = digitChars[1 .. 1 + dialogue.choices.length]; foreach (i, key; keys) { if (key.isPressed) { - chat.pick(i); + dialogue.pick(i); break; } } } else if (Keyboard.space.isPressed) { - chat.update(); + dialogue.update(); } } - // Draw the chat. - if (chat.hasChoices) { - foreach (i, choice; chat.choices) { + // Draw the dialogue. + if (dialogue.hasChoices) { + foreach (i, choice; dialogue.choices) { auto choicePosition = Vec2(8, 8 + i * 14); drawDebugText("{}".format(i + 1), choicePosition); drawDebugText(" | {}".format(choice), choicePosition); } - } else if (chat.canUpdate) { - drawDebugText("{}: {}".format(chat.actor, chat.text)); + } else if (dialogue.canUpdate) { + drawDebugText("{}: {}".format(dialogue.actor, dialogue.text)); } else { - drawDebugText("The chat has ended."); + drawDebugText("The dialogue has ended."); } - // Draw the game info/ + // Draw the game info. auto infoPosition = Vec2(8, resolution.y - 2 - 14 * 2); drawRect(Rect(0, resolution.y * 0.8, resolution.x, resolution.y), gray1); drawDebugText("Press 1, 2 or 3 to select a choice.", infoPosition); @@ -71,11 +71,11 @@ bool gameLoop() { void gameStart() { lockResolution(320, 180); - // Parse the chat script of the game. - // The first update makes the chat go to the first available line. - chat.parse(script); - chat.update(); + // Parse the dialogue script of the game. + // The first update makes the dialogue go to the first available line. + dialogue.parse(script); + dialogue.update(); updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/follower.d b/examples/follower.d index 6c74115..76aa57d 100644 --- a/examples/follower.d +++ b/examples/follower.d @@ -56,4 +56,4 @@ void gameStart() { atlas.free(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/hello.d b/examples/hello.d index 4668173..74041b2 100644 --- a/examples/hello.d +++ b/examples/hello.d @@ -1,18 +1,18 @@ /// This example serves as a classic hello-world program, introducing the fundamental structure of a Popka program. import popka; -// The game loop. This is called every frame. -// If true is returned, then the game will stop running. +// The loop function. This is called every frame. +// If true is returned, then the game will stop. bool gameLoop() { drawDebugText("Hello world!"); return false; } -// The game start. This is one time. +// The start function. This is called once. void gameStart() { lockResolution(320, 180); updateWindow!gameLoop(); } // Creates a main function that calls the given function and creates a game window that is 640 pixels wide and 360 pixels tall. -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/map.d b/examples/map.d index 776ab6e..96a77ea 100644 --- a/examples/map.d +++ b/examples/map.d @@ -41,4 +41,4 @@ void gameStart() { atlas.free(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/examples/pong.d b/examples/pong.d index 9b8329b..7b1f4b8 100644 --- a/examples/pong.d +++ b/examples/pong.d @@ -79,4 +79,4 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); diff --git a/scripts/header.d b/scripts/header.d index 2836348..ed6dc83 100755 --- a/scripts/header.d +++ b/scripts/header.d @@ -10,7 +10,7 @@ enum header = "// --- // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // ---"; int main(string[] args) { diff --git a/setup/source/app.d b/setup/source/app.d index eecf722..36d96c6 100755 --- a/setup/source/app.d +++ b/setup/source/app.d @@ -96,7 +96,7 @@ lib* enum defaultAppContent = `import popka; bool gameLoop() { - draw("Hello world!"); + drawDebugText("Hello world!"); return false; } @@ -105,7 +105,7 @@ void gameStart() { updateWindow!gameLoop(); } -mixin addGameStart!(gameStart, 640, 360); +mixin callGameStart!(gameStart, 640, 360); `; /// Check if path exists and print an error message if needed. diff --git a/source/popka/chat.d b/source/popka/dialogue.d similarity index 77% rename from source/popka/chat.d rename to source/popka/dialogue.d index 50d9ba7..bafb20a 100644 --- a/source/popka/chat.d +++ b/source/popka/dialogue.d @@ -3,20 +3,20 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- -/// The `chat` module provides a simple and versatile dialogue system. -module popka.chat; +/// The `dialogue` module provides a simple and versatile dialogue system. +module popka.dialogue; import popka.engine; public import joka; @safe @nogc nothrow: -enum ChatUnitKindChars = ".#*@>|^!+-$"; +enum DialogueUnitKindChars = ".#*@>|^!+-$"; -enum ChatUnitKind { +enum DialogueUnitKind { pause = '.', comment = '#', point = '*', @@ -30,18 +30,19 @@ enum ChatUnitKind { command = '$', } -struct ChatUnit { +struct DialogueUnit { LStr text; - ChatUnitKind kind; + DialogueUnitKind kind; @safe @nogc nothrow: void free() { text.free(); + this = DialogueUnit(); } } -struct ChatValue { +struct DialogueValue { LStr name; long value; @@ -49,14 +50,15 @@ struct ChatValue { void free() { name.free(); + this = DialogueValue(); } } -alias ChatCommandRunner = void function(IStr[] args); +alias DialogueCommandRunner = void function(IStr[] args); -struct Chat { - List!ChatUnit units; - List!ChatValue values; +struct Dialogue { + List!DialogueUnit units; + List!DialogueValue values; IStr text; IStr actor; Sz unitIndex; @@ -67,20 +69,20 @@ struct Chat { return units.length == 0; } - bool isKind(ChatUnitKind kind) { + bool isKind(DialogueUnitKind kind) { return unitIndex < units.length && units[unitIndex].kind == kind; } bool hasChoices() { - return isKind(ChatUnitKind.menu); + return isKind(DialogueUnitKind.menu); } bool hasArgs() { - return isKind(ChatUnitKind.command); + return isKind(DialogueUnitKind.command); } bool hasEnded() { - return isKind(ChatUnitKind.pause); + return isKind(DialogueUnitKind.pause); } bool canUpdate() { @@ -93,7 +95,7 @@ struct Chat { auto length = 0; auto temp = hasChoices ? units[unitIndex].text.items : ""; while (temp.length != 0) { - buffer[length] = temp.skipValue(ChatUnitKind.menu).trim(); + buffer[length] = temp.skipValue(DialogueUnitKind.menu).trim(); length += 1; } return buffer[0 .. length]; @@ -121,7 +123,7 @@ struct Chat { if (point.length == 0) { foreach (i; unitIndex + 1 .. units.length) { auto unit = units[i]; - if (unit.kind == ChatUnitKind.point) { + if (unit.kind == DialogueUnitKind.point) { unitIndex = i; break; } @@ -129,7 +131,7 @@ struct Chat { } else { foreach (i; 0 .. units.length) { auto unit = units[i]; - if (unit.kind == ChatUnitKind.point && unit.text.items == point) { + if (unit.kind == DialogueUnitKind.point && unit.text.items == point) { unitIndex = i; break; } @@ -140,7 +142,7 @@ struct Chat { void jump(Sz i) { auto currPoint = 0; foreach (j, unit; units.items) { - if (unit.kind == ChatUnitKind.point) { + if (unit.kind == DialogueUnitKind.point) { if (currPoint == i) { unitIndex = j; break; @@ -161,7 +163,7 @@ struct Chat { update(); } - void run(ChatCommandRunner runner) { + void run(DialogueCommandRunner runner) { runner(args); update(); } @@ -172,24 +174,24 @@ struct Chat { unitIndex += 1; text = units[unitIndex].text.items; final switch (units[unitIndex].kind) { - case ChatUnitKind.line, ChatUnitKind.menu, ChatUnitKind.command, ChatUnitKind.pause: { + case DialogueUnitKind.line, DialogueUnitKind.menu, DialogueUnitKind.command, DialogueUnitKind.pause: { break; } - case ChatUnitKind.comment, ChatUnitKind.point: { + case DialogueUnitKind.comment, DialogueUnitKind.point: { update(); break; } - case ChatUnitKind.actor: { + case DialogueUnitKind.actor: { actor = text; update(); break; } - case ChatUnitKind.jump: { + case DialogueUnitKind.jump: { jump(text); update(); break; } - case ChatUnitKind.variable: { + case DialogueUnitKind.variable: { auto variableIndex = -1; auto view = text; auto name = trim(skipValue(view, '=')); @@ -206,7 +208,7 @@ struct Chat { } // Create variable if it does not exist. if (variableIndex < 0) { - auto variable = ChatValue(); + auto variable = DialogueValue(); variable.name.append(name); values.append(variable); variableIndex = cast(int) values.length - 1; @@ -236,7 +238,7 @@ struct Chat { update(); break; } - case ChatUnitKind.plus, ChatUnitKind.minus: { + case DialogueUnitKind.plus, DialogueUnitKind.minus: { auto variableIndex = -1; auto name = text; // Find if variable exists. @@ -250,7 +252,7 @@ struct Chat { if (variableIndex < 0) { assert(0, "TODO: A variable that does not exist it an error for now."); } - if (units[unitIndex].kind == ChatUnitKind.plus) { + if (units[unitIndex].kind == DialogueUnitKind.plus) { values[variableIndex].value += 1; } else { values[variableIndex].value -= 1; @@ -268,7 +270,7 @@ struct Chat { return Fault.invalid; } - units.append(ChatUnit(LStr(), ChatUnitKind.pause)); + units.append(DialogueUnit(LStr(), DialogueUnitKind.pause)); auto isFirstLine = true; auto view = script; while (view.length != 0) { @@ -280,20 +282,20 @@ struct Chat { auto kind = line[0]; if (isFirstLine) { isFirstLine = false; - if (kind == ChatUnitKind.pause) { + if (kind == DialogueUnitKind.pause) { continue; } } - if (isValidChatUnitKind(kind)) { - auto realKind = cast(ChatUnitKind) kind; - units.append(ChatUnit(LStr(text), realKind)); + if (isValidDialogueUnitKind(kind)) { + auto realKind = cast(DialogueUnitKind) kind; + units.append(DialogueUnit(LStr(text), realKind)); } else { clear(); return Fault.invalid; } } - if (units.items[$ - 1].kind != ChatUnitKind.pause) { - units.append(ChatUnit(LStr(), ChatUnitKind.pause)); + if (units.items[$ - 1].kind != DialogueUnitKind.pause) { + units.append(DialogueUnit(LStr(), DialogueUnitKind.pause)); } return Fault.none; } @@ -323,8 +325,8 @@ struct Chat { } } -bool isValidChatUnitKind(char c) { - foreach (kind; ChatUnitKindChars) { +bool isValidDialogueUnitKind(char c) { + foreach (kind; DialogueUnitKindChars) { if (c == kind) { return true; } @@ -332,19 +334,19 @@ bool isValidChatUnitKind(char c) { return false; } -Result!Chat toChat(IStr script) { - auto value = Chat(); +Result!Dialogue toDialogue(IStr script) { + auto value = Dialogue(); auto fault = value.parse(script); if (fault) { value.free(); } - return Result!Chat(value, fault); + return Result!Dialogue(value, fault); } -Result!Chat loadChat(IStr path) { +Result!Dialogue loadDialogue(IStr path) { auto temp = loadTempText(path); if (temp.isNone) { - return Result!Chat(temp.fault); + return Result!Dialogue(temp.fault); } - return toChat(temp.unwrap()); + return toDialogue(temp.unwrap()); } diff --git a/source/popka/engine.d b/source/popka/engine.d index 7af9b87..d2962f3 100644 --- a/source/popka/engine.d +++ b/source/popka/engine.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /// The `engine` module functions as a lightweight 2D game engine. @@ -25,7 +25,7 @@ ray.Camera2D _toRay(Camera camera) { ); } -/// Returns a random integer between 0 and float.max (inclusive). +/// Returns a random integer between 0 and int.max (inclusive). @trusted int randi() { return ray.GetRandomValue(0, int.max); @@ -37,7 +37,7 @@ float randf() { return ray.GetRandomValue(0, cast(int) float.max) / cast(float) cast(int) float.max; } -/// Sets the seed for the random number generator to something specific. +/// Sets the seed of the random number generator to the given value. @trusted void randomize(int seed) { ray.SetRandomSeed(seed); @@ -48,19 +48,19 @@ void randomize() { randomize(randi); } -/// Converts a world point to a screen point based on the given camera. +/// Converts a world position to a screen position based on the given camera. @trusted -Vec2 toScreenPosition(Vec2 point, Camera camera) { - return toPopka(ray.GetWorldToScreen2D(point.toRay(), camera._toRay())); +Vec2 toScreenPosition(Vec2 position, Camera camera) { + return toPopka(ray.GetWorldToScreen2D(position.toRay(), camera._toRay())); } -/// Converts a screen point to a world point based on the given camera. +/// Converts a screen position to a world position based on the given camera. @trusted -Vec2 toWorldPosition(Vec2 point, Camera camera) { - return toPopka(ray.GetScreenToWorld2D(point.toRay(), camera._toRay())); +Vec2 toWorldPosition(Vec2 position, Camera camera) { + return toPopka(ray.GetScreenToWorld2D(position.toRay(), camera._toRay())); } -/// Returns the default font. This font should not be freed. +/// Returns the default Popka font. This font should not be freed. @trusted Font dfltFont() { auto result = ray.GetFontDefault().toPopka(); @@ -69,6 +69,7 @@ Font dfltFont() { return result; } +/// Returns an absolute path to the assets folder. IStr assetsPath() { return engineState.assetsPath.items; } @@ -78,21 +79,21 @@ IStr toAssetsPath(IStr path) { } /// Loads a text file from the assets folder and returns its contents as a list. -/// Can handle both forward slashes and backslashes in file paths, ensuring compatibility across operating systems. +/// Can handle both forward slashes and backslashes in file paths. Result!LStr loadText(IStr path) { return readText(path.toAssetsPath()); } /// Loads a text file from the assets folder and returns its contents as a slice. /// The slice can be safely used until this function is called again. -/// Can handle both forward slashes and backslashes in file paths, ensuring compatibility across operating systems. +/// Can handle both forward slashes and backslashes in file paths. Result!IStr loadTempText(IStr path) { auto fault = readTextIntoBuffer(path.toAssetsPath(), engineState.tempText); return Result!IStr(engineState.tempText.items, fault); } -/// Loads an image file from the assets folder. -/// Can handle both forward slashes and backslashes in file paths, ensuring compatibility across operating systems. +/// Loads an image file (PNG) from the assets folder. +/// Can handle both forward slashes and backslashes in file paths. @trusted Result!Texture loadTexture(IStr path) { auto value = ray.LoadTexture(path.toAssetsPath().toCStr().unwrapOr()).toPopka(); @@ -106,20 +107,21 @@ Result!Viewport loadViewport(int width, int height) { } @trusted +/// Loads a font file (TTF) from the assets folder. +/// Can handle both forward slashes and backslashes in file paths. Result!Font loadFont(IStr path, uint size, const(dchar)[] runes = []) { auto value = ray.LoadFontEx(path.toAssetsPath.toCStr().unwrapOr(), size, cast(int*) runes.ptr, cast(int) runes.length).toPopka(); return Result!Font(value, value.isEmpty.toFault(Fault.cantFind)); } /// Saves a text file to the assets folder. -/// Can handle both forward slashes and backslashes in file paths, ensuring compatibility across operating systems. +/// Can handle both forward slashes and backslashes in file paths. Fault saveText(IStr path, IStr text) { return writeText(path.toAssetsPath(), text); } -/// Opens the game window with the given size and title. -/// This function does not work if the window is already open, because Popka only works with one window. -/// Usually you should avoid calling this function manually. +/// Opens a window with the given size and title. +/// You should avoid calling this function manually. @trusted void openWindow(int width, int height, IStr title = "Popka") { if (ray.IsWindowReady) { @@ -135,7 +137,7 @@ void openWindow(int width, int height, IStr title = "Popka") { engineState.fullscreenState.lastWindowSize = Vec2(width, height); } -/// Updates the game window every frame with the specified loop function. +/// Updates the window every frame with the given loop function. /// This function will return when the loop function returns true. @trusted void updateWindow(alias loopFunc)() { @@ -229,52 +231,49 @@ void updateWindow(alias loopFunc)() { } } -/// Closes the game window. -/// Usually you should avoid calling this function manually. +/// Closes the window. +/// You should avoid calling this function manually. @trusted void closeWindow() { if (!ray.IsWindowReady) { return; } - engineState.tempText.free(); - engineState.assetsPath.free(); - engineState.viewport.free(); - + engineState.free(); ray.CloseAudioDevice(); ray.CloseWindow(); - engineState = EngineState(); } +/// Sets the window background color to the given color. void setBackgroundColor(Color color) { engineState.backgroundColor = color; } -/// Returns true if the FPS of the game is locked. +/// Returns true if the FPS is locked. bool isFpsLocked() { return engineState.flags.isFpsLocked; } -/// Locks the FPS of the game to a specific value. +/// Locks the FPS to the given value. @trusted void lockFps(int target) { engineState.flags.isFpsLocked = true; ray.SetTargetFPS(target); } -/// Unlocks the FPS of the game. +/// Unlocks the FPS. @trusted void unlockFps() { engineState.flags.isFpsLocked = false; ray.SetTargetFPS(0); } -/// Returns true if the resolution of the game is locked. +/// Returns true if the resolution is locked. bool isResolutionLocked() { return !engineState.viewport.isEmpty; } -/// Locks the resolution of the game to a specific value. +/// Locks the resolution to the given value. @trusted void lockResolution(int width, int height) { if (!engineState.flags.isUpdating) { @@ -287,7 +286,7 @@ void lockResolution(int width, int height) { } } -/// Unlocks the resolution of the game. +/// Unlocks the resolution. void unlockResolution() { if (!engineState.flags.isUpdating) { engineState.viewport.free(); @@ -311,7 +310,6 @@ bool isCursorHidden() { } /// Hides the system cursor. -/// This function works only on desktop. @trusted void hideCursor() { engineState.flags.isCursorHidden = true; @@ -319,7 +317,6 @@ void hideCursor() { } /// Shows the system cursor. -/// This function works only on desktop. @trusted void showCursor() { engineState.flags.isCursorHidden = false; @@ -327,14 +324,12 @@ void showCursor() { } /// Returns true if the window is in fullscreen mode. -/// This function works only on desktop. @trusted bool isFullscreen() { return ray.IsWindowFullscreen(); } /// Changes the state of the fullscreen mode of the window. -/// This function works only on desktop. @trusted void toggleFullscreen() { version(WebAssembly) { @@ -355,6 +350,7 @@ bool isPixelPerfect() { return engineState.flags.isPixelPerfect; } +/// Changes the state of the pixel perfect mode of the window. void togglePixelPerfect() { engineState.flags.isPixelPerfect = !engineState.flags.isPixelPerfect; } @@ -760,7 +756,7 @@ void drawDebugText(IStr text, Vec2 position = Vec2(8.0f), DrawOptions options = drawText(dfltFont, position, text, options); } -mixin template addGameStart(alias startFunc, int width, int height, IStr title = "Popka") { +mixin template callGameStart(alias startFunc, int width, int height, IStr title = "Popka") { version (D_BetterC) { pragma(msg, "Popka is using the C main function."); extern(C) diff --git a/source/popka/package.d b/source/popka/package.d index 80415bc..cdd10c0 100644 --- a/source/popka/package.d +++ b/source/popka/package.d @@ -3,13 +3,12 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- -// The `popka`` module imports all of its submodules. module popka; -public import popka.chat; +public import popka.dialogue; public import popka.engine; public import popka.tilemap; public import popka.types; diff --git a/source/popka/ray/package.d b/source/popka/ray/package.d index 79330ca..eb38891 100644 --- a/source/popka/ray/package.d +++ b/source/popka/ray/package.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /// The `ray` module provides access to the raylib library. diff --git a/source/popka/ray/raylib.d b/source/popka/ray/raylib.d index edf1f60..2a93616 100644 --- a/source/popka/ray/raylib.d +++ b/source/popka/ray/raylib.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /********************************************************************************************** diff --git a/source/popka/ray/rlgl.d b/source/popka/ray/rlgl.d index f29801b..822adae 100644 --- a/source/popka/ray/rlgl.d +++ b/source/popka/ray/rlgl.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /********************************************************************************************** diff --git a/source/popka/tilemap.d b/source/popka/tilemap.d index ede2eac..6cf79a6 100644 --- a/source/popka/tilemap.d +++ b/source/popka/tilemap.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /// The `tilemap` module provides a simple and fast tile map. diff --git a/source/popka/types.d b/source/popka/types.d index b703569..793ad7f 100644 --- a/source/popka/types.d +++ b/source/popka/types.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/popka -// Version: v0.0.14 +// Version: v0.0.15 // --- /// The `types` module defines all the types used within the `engine` module. @@ -170,6 +170,15 @@ struct EngineState { Color backgroundColor; LStr tempText; LStr assetsPath; + + @safe @nogc nothrow: + + void free() { + viewport.free(); + tempText.free(); + assetsPath.free(); + this = EngineState(); + } } struct DrawOptions {