Setup is better and small changes.

This commit is contained in:
Kapendev 2024-11-15 00:52:05 +02:00
parent 8f084526e1
commit ec4e7d2eb0
7 changed files with 141 additions and 122 deletions

View file

@ -14,13 +14,11 @@ bool update(float dt) {
// Move the camera.
cameraTarget += wasd * Vec2(cameraSpeed * dt);
camera.followPositionWithSlowdown(cameraTarget, 0.15);
// Draw the game world.
camera.attach();
drawDebugText("Move with arrow keys.", Vec2(8));
drawRect(camera.area.subAll(3), Color(50, 50, 40, 130));
camera.detach();
// Draw the game UI.
drawDebugText("I am UI!", Vec2(8));
drawDebugText("+", resolution * Vec2(0.5));

View file

@ -24,12 +24,10 @@ bool update(float dt) {
mapOptions.scale = Vec2(2);
auto tileOptions = mapOptions;
tileOptions.flip = tileLookDirection > 0 ? Flip.x : Flip.none;
// Move the tile and camera.
tile.position += wasd * Vec2(tileSpeed * dt);
camera.position = tile.position;
if (wasd.x != 0) tileLookDirection = cast(int) wasd.normalize.round.x;
// Check for collisions.
auto collisionArea = Rect();
foreach (gridPosition; map.gridPositions(camera.area, mapOptions)) {

View file

@ -13,8 +13,11 @@ bool update(float dt) {
// Resize the viewport when the window is resized.
if (isWindowResized) viewport.resize(resolutionWidth / 2, resolutionHeight / 2);
// Draw the mouse position inside the viewport.
auto viewportCenter = viewport.size * Vec2(0.5);
auto viewportMousePosition = mouseScreenPosition - Rect(resolution * Vec2(0.5), viewport.size).centerArea.position;
viewport.attach();
drawVec2(mouseScreenPosition - Rect(resolution * Vec2(0.5), viewport.size).centerArea.position, 24);
drawVec2(viewportCenter, 20);
drawVec2(viewportMousePosition, 20);
viewport.detach();
// Draw the viewport and other things inside the window.
drawViewport(viewport, resolution * Vec2(0.5), DrawOptions(Hook.center));

View file

@ -6,13 +6,38 @@ import std;
enum assetsDir = buildPath(".", "assets");
enum webDir = buildPath(".", "web");
enum appFile = buildPath(".", "source", "app.d");
enum dubFile = buildPath(".", "dub.json");
enum dubCopyFile = buildPath(".", ".__dub_copy__.json");
enum dubLockFile = buildPath(".", "dub.selections.json");
enum dubLockCopyFile = buildPath(".", ".__dub_selections_copy__.json");
enum readmeFile = buildPath(".", "README.md");
enum gitignoreFile = buildPath(".", ".gitignore");
enum dubFile = buildPath(".", "dub.json");
enum dubLockFile = buildPath(".", "dub.selections.json");
enum readmeFileContent = "# Game Title
This game was created using [Parin](https://github.com/Kapendev/parin).
To compile the game, run:
```sh
command arg1 arg2 ...
```
";
enum gitignoreFileContent = `.dub
game
lib*
test*
*.wasm
*.so
*.dylib
*.dll
*.a
*.lib
*.exe
*.pdb
*.o
*.obj
*.lst
`;
enum appFileContent = `import parin;
@ -86,94 +111,99 @@ enum dubFileContent = `{
}
`;
enum gitignoreFileContent = `.dub
game
web
lib*
*.so
*.dylib
*.dll
*.a
*.lib
*.exe
*.pdb
*.o
*.obj
*.lst
`;
/// Creates the assets and web folders inside the current folder.
void makeFolders() {
if (!exists(assetsDir)) std.file.mkdir(assetsDir);
if (!exists(webDir)) std.file.mkdir(webDir);
std.file.write(buildPath(assetsDir, ".gitkeep"), "");
std.file.write(buildPath(webDir, ".gitkeep"), "");
}
int main(string[] args) {
auto isDubProject = exists(dubFile);
auto isFirstRun = !exists(assetsDir);
auto canDownloadLibs = true;
/// Creates the basic project setup of a parin project inside the current folder.
void makeBasicSetup() {
makeFolders();
if (!exists(readmeFile)) std.file.write(readmeFile, readmeFileContent);
if (!exists(gitignoreFile)) std.file.write(gitignoreFile, gitignoreFileContent);
}
// Sometimes I remove the app.d file and this makes a new one lol.
// Also raylib-d:install does not like it when you don't have one.
if (isDubProject) {
if (!exists(appFile)) std.file.write(appFile, appFileContent);
if (!isFirstRun) {
std.file.write(dubCopyFile, std.file.readText(dubFile));
/// The setup code for simple standalone projects.
int runSimpSetup(string[] args, bool isFirstRun) {
makeBasicSetup();
return 0;
}
/// The setup code for dub projects.
int runDubSetup(string[] args, bool isFirstRun) {
// Create the backup copies.
auto dubCopyFile = buildPath(".", "._dub_copy");
auto dubLockCopyFile = buildPath(".", "._dub_lock_copy");
if (exists(dubFile)) std.file.write(dubCopyFile, std.file.readText(dubFile));
if (exists(dubLockFile)) std.file.write(dubLockCopyFile, std.file.readText(dubLockFile));
}
// Create the basic files and folders.
// NOTE: An empty dub project has a gitignore file and we don't want that file.
if (isFirstRun && exists(gitignoreFile)) std.file.remove(gitignoreFile);
makeBasicSetup();
// Find the app file.
auto appDir = buildPath(".", "src");
if (!exists(appDir)) appDir = buildPath(".", "source");
auto appFile = buildPath(appDir, "main.d");
if (!exists(appFile)) appFile = buildPath(appDir, "app.d");
// Replace the app file content if needed.
if (exists(appFile)) {
if (isFirstRun) std.file.write(appFile, appFileContent);
} else {
std.file.write(appFile, appFileContent);
}
// User input stuff.
if (isDubProject) {
auto arg = (args.length == 2) ? args[1] : "";
if (arg.length == 0) {
// Get a yes or no from the user and download the raylib libraries if the user said yes.
auto arg = (args.length != 0) ? args[0] : "?";
while (true) {
if (arg.length == 0) arg = "Y";
foreach (c; "YyNn") {
if (arg.length != 1) break;
if (arg[0] == c) goto whileExit;
}
write("Would you like to download the raylib libraries? [Y/n] ");
arg = readln().strip();
}
canDownloadLibs = arg != "N" && arg != "n";
}
// Use the raylib-d script to download the raylib library files.
if (isDubProject && canDownloadLibs) {
writeln("Say \"yes\" to all prompts.\n");
whileExit:
if (arg == "Y" || arg == "y") {
auto dub1 = spawnProcess(["dub", "add", "raylib-d"]).wait();
if (dub1 != 0) {
if (!isFirstRun) {
std.file.remove(dubCopyFile);
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
}
return dub1;
}
auto dub2 = spawnProcess(["dub", "run", "raylib-d:install"]).wait();
if (dub2 != 0) {
if (!isFirstRun) {
std.file.remove(dubCopyFile);
// Remove the backup copies if something failed.
if (dub1 != 0 || dub2 != 0) {
if (exists(dubCopyFile)) std.file.remove(dubCopyFile);
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
}
return dub2;
return 1;
}
}
// Remove old files.
if (isDubProject) {
if (isFirstRun && exists(appFile)) std.file.remove(appFile);
if (exists(dubFile)) std.file.remove(dubFile);
if (exists(dubLockFile)) std.file.remove(dubLockFile);
}
if (isFirstRun && exists(gitignoreFile)) std.file.remove(gitignoreFile);
// Create new files.
if (isDubProject) {
if (isFirstRun) std.file.write(appFile, appFileContent);
// Replace the dub file content if needed.
if (isFirstRun) {
std.file.write(dubFile, dubFileContent);
std.file.remove(dubLockFile);
// Remove the backup copies.
if (exists(dubCopyFile)) std.file.remove(dubCopyFile);
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
} else {
// Replace the "dirty" files with the backup copies.
// NOTE: raylib-d will change the content of the dub file and this is considered dirty.
if (exists(dubCopyFile)) {
std.file.write(dubFile, std.file.readText(dubCopyFile));
std.file.remove(dubCopyFile);
if (exists(dubLockCopyFile)) std.file.write(dubLockFile, std.file.readText(dubLockCopyFile));
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
} else {
std.file.write(dubFile, dubFileContent);
}
if (exists(dubLockCopyFile)) {
std.file.write(dubLockFile, std.file.readText(dubLockCopyFile));
std.file.remove(dubLockCopyFile);
}
}
if (isFirstRun) std.file.write(gitignoreFile, gitignoreFileContent);
// Create folders.
if (!exists(assetsDir)) std.file.mkdir(assetsDir);
if (!exists(webDir)) std.file.mkdir(webDir);
writeln("\nHappy hacking!");
return 0;
}
int main(string[] args) {
auto isSimpProject = !exists(dubFile);
auto isFirstRun = !exists(assetsDir);
if (isSimpProject) return runSimpSetup(args[1 .. $], isFirstRun);
else return runDubSetup(args[1 .. $], isFirstRun);
}

View file

@ -883,7 +883,6 @@ struct EngineState {
LStr assetsPath;
LStr tempText;
Font debugFont;
Color borderColor;
Filter defaultFilter;
@ -1236,7 +1235,6 @@ void openWindow(int width, int height, IStr appPath, IStr title = "Parin") {
engineState.viewport.color = gray;
engineState.fullscreenState.lastWindowWidth = width;
engineState.fullscreenState.lastWindowHeight = height;
engineState.debugFont = engineFont;
engineState.assetsPath.append(pathConcat(appPath.pathDir, "assets"));
engineState.tempText.reserve(8192);
// NOTE: This line is used for fixing an alpha bug with render textures.
@ -1469,16 +1467,6 @@ Font engineFont() {
return result;
}
/// Returns the current debug font. This font should not be freed.
Font debugFont() {
return engineState.debugFont;
}
/// Sets the debug font to the specified value.
void setDebugFont(Font font) {
engineState.debugFont = font;
}
/// Returns the default filter mode for textures.
Filter defaultFilter() {
return engineState.defaultFilter;
@ -2109,7 +2097,7 @@ void drawText(FontId font, IStr text, Vec2 position, DrawOptions options = DrawO
/// Draws debug text at the given position with the provided draw options.
void drawDebugText(IStr text, Vec2 position, DrawOptions options = DrawOptions()) {
drawText(engineState.debugFont, text, position, options);
drawText(engineFont, text, position, options);
}
/// Mixes in a game loop template with specified functions for initialization, update, and cleanup, and sets window size and title.

View file

@ -65,8 +65,8 @@ struct Tile {
struct TileMap {
Grid!short data;
Sz estimatedMaxRowCount;
Sz estimatedMaxColCount;
Sz softMaxRowCount;
Sz softMaxColCount;
int tileWidth = 16;
int tileHeight = 16;
Vec2 position;
@ -77,8 +77,8 @@ struct TileMap {
this(int tileWidth, int tileHeight, Vec2 position = Vec2()) {
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.estimatedMaxRowCount = maxRowCount;
this.estimatedMaxColCount = maxColCount;
this.softMaxRowCount = maxRowCount;
this.softMaxColCount = maxColCount;
this.position = position;
this.data.fill(-1);
}
@ -89,11 +89,11 @@ struct TileMap {
}
int width() {
return cast(int) (estimatedMaxColCount * tileWidth);
return cast(int) (softMaxColCount * tileWidth);
}
int height() {
return cast(int) (estimatedMaxRowCount * tileHeight);
return cast(int) (softMaxRowCount * tileHeight);
}
/// Returns the size of the tile map.
@ -110,21 +110,21 @@ struct TileMap {
if (csv.length == 0) return Fault.invalid;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.estimatedMaxRowCount = 0;
this.estimatedMaxColCount = 0;
this.softMaxRowCount = 0;
this.softMaxColCount = 0;
this.data.fill(-1);
auto view = csv;
while (view.length != 0) {
estimatedMaxRowCount += 1;
estimatedMaxColCount = 0;
if (estimatedMaxRowCount > maxRowCount) return Fault.invalid;
softMaxRowCount += 1;
softMaxColCount = 0;
if (softMaxRowCount > maxRowCount) return Fault.invalid;
auto line = view.skipLine();
while (line.length != 0) {
estimatedMaxColCount += 1;
if (estimatedMaxColCount > maxColCount) return Fault.invalid;
softMaxColCount += 1;
if (softMaxColCount > maxColCount) return Fault.invalid;
auto tile = line.skipValue(',').toSigned();
if (tile.isNone) return Fault.invalid;
data[estimatedMaxRowCount - 1, estimatedMaxColCount - 1] = cast(short) tile.get();
data[softMaxRowCount - 1, softMaxColCount - 1] = cast(short) tile.get();
}
}
return Fault.none;
@ -162,8 +162,8 @@ struct TileMap {
auto result = IVec2();
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
result.y = cast(int) floor(clamp((topLeftWorldPosition.y - position.y) / targetTileHeight, 0, estimatedMaxRowCount));
result.x = cast(int) floor(clamp((topLeftWorldPosition.x - position.x) / targetTileWidth, 0, estimatedMaxColCount));
result.y = cast(int) floor(clamp((topLeftWorldPosition.y - position.y) / targetTileHeight, 0, softMaxRowCount));
result.x = cast(int) floor(clamp((topLeftWorldPosition.x - position.x) / targetTileWidth, 0, softMaxColCount));
return result;
}
@ -172,8 +172,8 @@ struct TileMap {
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
auto extraTileCount = options.hook == Hook.topLeft ? 1 : 2;
result.y = cast(int) floor(clamp((bottomRightWorldPosition.y - position.y) / targetTileHeight + extraTileCount, 0, estimatedMaxRowCount));
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, estimatedMaxColCount));
result.y = cast(int) floor(clamp((bottomRightWorldPosition.y - position.y) / targetTileHeight + extraTileCount, 0, softMaxRowCount));
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, softMaxColCount));
return result;
}

View file

@ -4,6 +4,8 @@
import std;
// TODO: Clean it! Well... Not right now, but do it.
enum dflags = ["-betterC", "-i", "--release"]; // The compiler flags passed to ldc. Local dependencies can be added here.
enum output = buildPath(".", "web", "index.html"); // The output file that can be run with emrun.