Working HTML5 version

This commit is contained in:
2024-01-29 00:10:31 +01:00
parent 410c3d217e
commit 409d9027ef
11 changed files with 108 additions and 30 deletions

View File

@@ -50,5 +50,5 @@ target_link_libraries(PixelDefense LINK_PRIVATE Breeze)
if (EMSCRIPTEN)
set_target_properties(PixelDefense
PROPERTIES SUFFIX ".html"
LINK_FLAGS " --bind -s WASM=1 -s ALLOW_MEMORY_GROWTH -s STACK_SIZE=2048kb -s ASSERTIONS=2 -s MIN_WEBGL_VERSION=1 --preload-file ../assets -g2 -gseparate-dwarf -gsource-map -s USE_GLFW=3")
LINK_FLAGS "-lidbfs.js -sEXPORTED_FUNCTIONS=_loopPause,_loopResume,_main -sEXTRA_EXPORTED_RUNTIME_METHODS=ccall -sFORCE_FILESYSTEM=1 -sWASM=1 -sSTACK_OVERFLOW_CHECK=2 -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=10MB -sASSERTIONS=2 -sMIN_WEBGL_VERSION=1 --preload-file ../assets -g2 -gseparate-dwarf -gsource-map -sUSE_GLFW=3")
endif()

View File

@@ -73,7 +73,6 @@ set(BreezeHeaders
breeze/util/array.h
breeze/util/heap.h
breeze/util/lambda.h
breeze/util/object_pool.h
breeze/util/spatial_grid.h
breeze/util/string.h
@@ -111,7 +110,7 @@ target_include_directories(Breeze
file(COPY ${BreezeHeaders} DESTINATION "include")
if (${BUILD_BREEZE_TESTS})
if (${BUILD_BREEZE_TESTS} AND NOT EMSCRIPTEN)
MESSAGE(STATUS "Building breeze tests is enabled")
add_subdirectory(tests)
endif()

View File

@@ -15,7 +15,6 @@
#include "breeze/util/array.h"
#include "breeze/util/heap.h"
#include "breeze/util/lambda.h"
#include "breeze/util/object_pool.h"
#include "breeze/util/spatial_grid.h"
#include "breeze/util/string.h"

View File

@@ -194,14 +194,14 @@ BzBTStatus aiDepositRes(AIBlackboard *data, f32 dt) {
return BZ_BT_SUCCESS;
}
BzBTStatus aiCarryCapacityFull(AIBlackboard *data) {
BzBTStatus aiCarryCapacityFull(AIBlackboard *data, f32 dt) {
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
if (worker->carry >= worker->carryCapacity)
return BZ_BT_SUCCESS;
return BZ_BT_FAIL;
}
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data) {
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data, f32 dt) {
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
if (worker->carry == 0)

View File

@@ -37,8 +37,8 @@ BzBTStatus aiFindNextHarvestable(AIBlackboard *data, f32 dt);
BzBTStatus aiFindNearestStorage(AIBlackboard *data, f32 dt);
BzBTStatus aiHarvestRes(AIBlackboard *data, f32 dt);
BzBTStatus aiDepositRes(AIBlackboard *data, f32 dt);
BzBTStatus aiCarryCapacityFull(AIBlackboard *data);
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data);
BzBTStatus aiCarryCapacityFull(AIBlackboard *data, f32 dt);
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data, f32 dt);
//BzBTStatus aiIsTargetHarvestable(AIBlackboard *data);
//BzBTStatus aiIsTargetStorage(AIBlackboard *data);

View File

@@ -99,7 +99,7 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
case BUILDING_WHEAT_1:
hasCollision = false;
ecs_add_id(ECS, building, Harvestable);
ecs_set(ECS, building, Resource, {RES_FOOD, INFINITY});
ecs_set(ECS, building, Resource, {RES_FOOD, INT32_MAX});
break;
default:
break;

View File

@@ -13,5 +13,9 @@ typedef enum Player {
PLAYER_COUNT
} Player;
// defined in main.c
extern const char *SETTINGS_PATH;
#endif //PIXELDEFENSE_CONSTANTS_H

View File

@@ -17,6 +17,9 @@
#include "pathfinding.h"
#include "sounds.h"
// Constants
const char *SETTINGS_PATH = "settings.ini";
// Constants end
ECS_COMPONENT_DECLARE(Game);
ECS_COMPONENT_DECLARE(InputState);
@@ -32,7 +35,20 @@ void update(float dt, void *userData);
void render(float dt, void *userData);
void imguiRender(float dt, void *userData);
static bool loopPaused = true;
extern void loopPause(void) {
loopPaused = true;
}
extern void loopResume(void) {
loopPaused = false;
}
#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif
bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
appDesc->width = 1280;
appDesc->height = 720;
@@ -48,6 +64,25 @@ bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
appDesc->userData = NULL;
//SetConfigFlags(FLAG_WINDOW_RESIZABLE);
#ifdef EMSCRIPTEN
EM_ASM(
FS.mkdir('/game');
FS.mount(IDBFS, {}, '/game');
FS.syncfs(true, function (err) {
console.log("resumed");
Module.ccall('loopResume', 'void', ['void']);
});
console.log('/game mounted');
/*
* Note: FS.syncfs is async so we need to pause the
* main loop until it finishes :/
*/
Module.ccall('loopPause', 'void', ['void']);
);
loopPaused = true;
#else
loopPaused = false;
#endif
return true;
}
@@ -63,14 +98,42 @@ int cmpDrawData(const void *a, const void *b) {
return cmpVal;
}
bool serializeOptions(const char *path, const Options *opts) {
#ifdef EMSCRIPTEN
char buf[4096];
snprintf(buf, sizeof(buf), "%s%s", "/game/", path);
path = buf;
#endif
bzLogInfo("write path: %s", path);
FILE *f = fopen(path, "w");
if (!f) return false;
size_t numWritten = fwrite(opts, sizeof(*opts), 1, f);
fclose(f);
#ifdef EMSCRIPTEN
// Sync FS
EM_ASM(
FS.syncfs(false, function (err) {
});
);
#endif
return numWritten == 1;
}
bool deserializeOptions(const char *path, Options *optsOut) {
#ifdef EMSCRIPTEN
char buf[4096];
snprintf(buf, sizeof(buf), "%s%s", "/game/", path);
path = buf;
#endif
bzLogInfo("read path: %s", path);
FILE *f = fopen(path, "r");
bzLogInfo("start reading");
if (!f) return false;
bzLogInfo("reading");
Options opts;
size_t numRead = fread(&opts, sizeof(opts), 1, f);
fclose(f);
@@ -143,7 +206,7 @@ bool init(void *userData) {
}
setScreen(game, SCREEN_MAIN_MENU);
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
game->stackAlloc = bzStackAllocCreate(1 * 1000 * 1000); // 1 MB
// init pools
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
.objectSize = sizeof(PathData),
@@ -252,22 +315,12 @@ bool init(void *userData) {
loadMap(game, "assets/maps/main_menu_01.tmj");
game->debug.drawMapColliders = true;
game->debug.drawSpatialGrid = true;
game->debug.drawPath = true;
game->debug.drawMapColliders = false;
game->debug.drawSpatialGrid = false;
game->debug.drawPath = false;
game->debug.inspecting = bzArrayCreate(ecs_entity_t, 10);
// Load settings
const char *workDir = GetApplicationDirectory();
char buf[FILENAME_MAX];
snprintf(buf, sizeof(buf), "%s%s", workDir, "settings");
Options opts;
if (deserializeOptions(buf, &opts)) {
game->options = opts;
} else {
game->options = getDefaultOptions();
}
return true;
}
@@ -277,10 +330,7 @@ void deinit(void *userData) {
InputState *input = ecs_singleton_get_mut(ECS, InputState);
SoundState *sounds = ecs_singleton_get_mut(ECS, SoundState);
const char *workDir = GetApplicationDirectory();
char buf[FILENAME_MAX];
snprintf(buf, sizeof(buf), "%s%s", workDir, "settings");
serializeOptions(buf, &game->options);
serializeOptions(SETTINGS_PATH, &game->options);
unloadMap(game);
@@ -320,6 +370,8 @@ void deinit(void *userData) {
void update(float dt, void *userData) {
if (loopPaused)
return;
BZ_UNUSED(userData);
char titleBuf[32];
@@ -329,6 +381,22 @@ void update(float dt, void *userData) {
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
{
static bool optsLoaded = false;
if (!optsLoaded) {
// Load settings
const char *path = SETTINGS_PATH;
Options opts;
if (deserializeOptions(path, &opts)) {
game->options = opts;
} else {
game->options = getDefaultOptions();
}
optsLoaded = true;
}
}
game->screenPrevFrame = game->screen;
if (game->screen != game->nextScreen)
game->screen = game->nextScreen;
@@ -487,6 +555,8 @@ static void renderGame(Game *game, float dt) {
}
void render(float dt, void *userData) {
if (loopPaused)
return;
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
@@ -600,9 +670,9 @@ void imguiRender(float dt, void *userData) {
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
igBegin("Debug Menu", NULL, 0);
igText("PathData pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
igText("BTNode pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNode));
igText("BTNodeState pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNodeState));
igText("PathData pool available: %lu", bzObjectPoolGetNumFree(game->pools.pathData));
igText("BTNode pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNode));
igText("BTNodeState pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNodeState));
const char *inputState = "NONE";
switch (input->state) {
case INPUT_NONE:

View File

@@ -5,6 +5,7 @@
#include "../map_init.h"
#include "../ui_widgets.h"
#include "../buildings.h"
#include "../utils.h"
void drawGameUI(Game *game, f32 dt) {
// UI
@@ -303,6 +304,7 @@ void drawSettingsUI(Game *game, f32 dt) {
opts = game->options;
}
if (uiSettingsButton("Apply")) {
serializeOptions(SETTINGS_PATH, &opts);
game->options = opts;
setScreen(game, SCREEN_MAIN_MENU);
}

View File

@@ -18,4 +18,8 @@ static Rectangle getCameraBounds(Camera2D camera) {
return bounds;
}
// Implemented in main.c
bool serializeOptions(const char *path, const Options *opts);
bool deserializeOptions(const char *path, Options *optsOut);
#endif //PIXELDEFENSE_UTILS_H

BIN
settings.ini Normal file

Binary file not shown.