Working HTML5 version
This commit is contained in:
@@ -50,5 +50,5 @@ target_link_libraries(PixelDefense LINK_PRIVATE Breeze)
|
|||||||
if (EMSCRIPTEN)
|
if (EMSCRIPTEN)
|
||||||
set_target_properties(PixelDefense
|
set_target_properties(PixelDefense
|
||||||
PROPERTIES SUFFIX ".html"
|
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()
|
endif()
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ set(BreezeHeaders
|
|||||||
|
|
||||||
breeze/util/array.h
|
breeze/util/array.h
|
||||||
breeze/util/heap.h
|
breeze/util/heap.h
|
||||||
breeze/util/lambda.h
|
|
||||||
breeze/util/object_pool.h
|
breeze/util/object_pool.h
|
||||||
breeze/util/spatial_grid.h
|
breeze/util/spatial_grid.h
|
||||||
breeze/util/string.h
|
breeze/util/string.h
|
||||||
@@ -111,7 +110,7 @@ target_include_directories(Breeze
|
|||||||
|
|
||||||
file(COPY ${BreezeHeaders} DESTINATION "include")
|
file(COPY ${BreezeHeaders} DESTINATION "include")
|
||||||
|
|
||||||
if (${BUILD_BREEZE_TESTS})
|
if (${BUILD_BREEZE_TESTS} AND NOT EMSCRIPTEN)
|
||||||
MESSAGE(STATUS "Building breeze tests is enabled")
|
MESSAGE(STATUS "Building breeze tests is enabled")
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include "breeze/util/array.h"
|
#include "breeze/util/array.h"
|
||||||
#include "breeze/util/heap.h"
|
#include "breeze/util/heap.h"
|
||||||
#include "breeze/util/lambda.h"
|
|
||||||
#include "breeze/util/object_pool.h"
|
#include "breeze/util/object_pool.h"
|
||||||
#include "breeze/util/spatial_grid.h"
|
#include "breeze/util/spatial_grid.h"
|
||||||
#include "breeze/util/string.h"
|
#include "breeze/util/string.h"
|
||||||
|
|||||||
@@ -194,14 +194,14 @@ BzBTStatus aiDepositRes(AIBlackboard *data, f32 dt) {
|
|||||||
|
|
||||||
return BZ_BT_SUCCESS;
|
return BZ_BT_SUCCESS;
|
||||||
}
|
}
|
||||||
BzBTStatus aiCarryCapacityFull(AIBlackboard *data) {
|
BzBTStatus aiCarryCapacityFull(AIBlackboard *data, f32 dt) {
|
||||||
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
|
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
|
||||||
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
|
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
|
||||||
if (worker->carry >= worker->carryCapacity)
|
if (worker->carry >= worker->carryCapacity)
|
||||||
return BZ_BT_SUCCESS;
|
return BZ_BT_SUCCESS;
|
||||||
return BZ_BT_FAIL;
|
return BZ_BT_FAIL;
|
||||||
}
|
}
|
||||||
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data) {
|
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data, f32 dt) {
|
||||||
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
|
BZ_ASSERT(ecs_has(ECS, data->entity, Worker));
|
||||||
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
|
Worker *worker = ecs_get_mut(ECS, data->entity, Worker);
|
||||||
if (worker->carry == 0)
|
if (worker->carry == 0)
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ BzBTStatus aiFindNextHarvestable(AIBlackboard *data, f32 dt);
|
|||||||
BzBTStatus aiFindNearestStorage(AIBlackboard *data, f32 dt);
|
BzBTStatus aiFindNearestStorage(AIBlackboard *data, f32 dt);
|
||||||
BzBTStatus aiHarvestRes(AIBlackboard *data, f32 dt);
|
BzBTStatus aiHarvestRes(AIBlackboard *data, f32 dt);
|
||||||
BzBTStatus aiDepositRes(AIBlackboard *data, f32 dt);
|
BzBTStatus aiDepositRes(AIBlackboard *data, f32 dt);
|
||||||
BzBTStatus aiCarryCapacityFull(AIBlackboard *data);
|
BzBTStatus aiCarryCapacityFull(AIBlackboard *data, f32 dt);
|
||||||
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data);
|
BzBTStatus aiCarryCapacityEmpty(AIBlackboard *data, f32 dt);
|
||||||
//BzBTStatus aiIsTargetHarvestable(AIBlackboard *data);
|
//BzBTStatus aiIsTargetHarvestable(AIBlackboard *data);
|
||||||
//BzBTStatus aiIsTargetStorage(AIBlackboard *data);
|
//BzBTStatus aiIsTargetStorage(AIBlackboard *data);
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
|
|||||||
case BUILDING_WHEAT_1:
|
case BUILDING_WHEAT_1:
|
||||||
hasCollision = false;
|
hasCollision = false;
|
||||||
ecs_add_id(ECS, building, Harvestable);
|
ecs_add_id(ECS, building, Harvestable);
|
||||||
ecs_set(ECS, building, Resource, {RES_FOOD, INFINITY});
|
ecs_set(ECS, building, Resource, {RES_FOOD, INT32_MAX});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -13,5 +13,9 @@ typedef enum Player {
|
|||||||
PLAYER_COUNT
|
PLAYER_COUNT
|
||||||
} Player;
|
} Player;
|
||||||
|
|
||||||
|
// defined in main.c
|
||||||
|
|
||||||
|
extern const char *SETTINGS_PATH;
|
||||||
|
|
||||||
|
|
||||||
#endif //PIXELDEFENSE_CONSTANTS_H
|
#endif //PIXELDEFENSE_CONSTANTS_H
|
||||||
|
|||||||
112
game/main.c
112
game/main.c
@@ -17,6 +17,9 @@
|
|||||||
#include "pathfinding.h"
|
#include "pathfinding.h"
|
||||||
#include "sounds.h"
|
#include "sounds.h"
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const char *SETTINGS_PATH = "settings.ini";
|
||||||
|
// Constants end
|
||||||
|
|
||||||
ECS_COMPONENT_DECLARE(Game);
|
ECS_COMPONENT_DECLARE(Game);
|
||||||
ECS_COMPONENT_DECLARE(InputState);
|
ECS_COMPONENT_DECLARE(InputState);
|
||||||
@@ -32,7 +35,20 @@ void update(float dt, void *userData);
|
|||||||
void render(float dt, void *userData);
|
void render(float dt, void *userData);
|
||||||
void imguiRender(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) {
|
bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
|
||||||
appDesc->width = 1280;
|
appDesc->width = 1280;
|
||||||
appDesc->height = 720;
|
appDesc->height = 720;
|
||||||
@@ -48,6 +64,25 @@ bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
|
|||||||
appDesc->userData = NULL;
|
appDesc->userData = NULL;
|
||||||
|
|
||||||
//SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
//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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -63,14 +98,42 @@ int cmpDrawData(const void *a, const void *b) {
|
|||||||
return cmpVal;
|
return cmpVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool serializeOptions(const char *path, const Options *opts) {
|
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");
|
FILE *f = fopen(path, "w");
|
||||||
|
if (!f) return false;
|
||||||
size_t numWritten = fwrite(opts, sizeof(*opts), 1, f);
|
size_t numWritten = fwrite(opts, sizeof(*opts), 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
// Sync FS
|
||||||
|
EM_ASM(
|
||||||
|
FS.syncfs(false, function (err) {
|
||||||
|
});
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
return numWritten == 1;
|
return numWritten == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deserializeOptions(const char *path, Options *optsOut) {
|
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");
|
FILE *f = fopen(path, "r");
|
||||||
|
bzLogInfo("start reading");
|
||||||
|
if (!f) return false;
|
||||||
|
bzLogInfo("reading");
|
||||||
Options opts;
|
Options opts;
|
||||||
size_t numRead = fread(&opts, sizeof(opts), 1, f);
|
size_t numRead = fread(&opts, sizeof(opts), 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@@ -143,7 +206,7 @@ bool init(void *userData) {
|
|||||||
}
|
}
|
||||||
setScreen(game, SCREEN_MAIN_MENU);
|
setScreen(game, SCREEN_MAIN_MENU);
|
||||||
|
|
||||||
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
|
game->stackAlloc = bzStackAllocCreate(1 * 1000 * 1000); // 1 MB
|
||||||
// init pools
|
// init pools
|
||||||
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
.objectSize = sizeof(PathData),
|
.objectSize = sizeof(PathData),
|
||||||
@@ -252,22 +315,12 @@ bool init(void *userData) {
|
|||||||
loadMap(game, "assets/maps/main_menu_01.tmj");
|
loadMap(game, "assets/maps/main_menu_01.tmj");
|
||||||
|
|
||||||
|
|
||||||
game->debug.drawMapColliders = true;
|
game->debug.drawMapColliders = false;
|
||||||
game->debug.drawSpatialGrid = true;
|
game->debug.drawSpatialGrid = false;
|
||||||
game->debug.drawPath = true;
|
game->debug.drawPath = false;
|
||||||
game->debug.inspecting = bzArrayCreate(ecs_entity_t, 10);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -277,10 +330,7 @@ void deinit(void *userData) {
|
|||||||
InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
||||||
SoundState *sounds = ecs_singleton_get_mut(ECS, SoundState);
|
SoundState *sounds = ecs_singleton_get_mut(ECS, SoundState);
|
||||||
|
|
||||||
const char *workDir = GetApplicationDirectory();
|
serializeOptions(SETTINGS_PATH, &game->options);
|
||||||
char buf[FILENAME_MAX];
|
|
||||||
snprintf(buf, sizeof(buf), "%s%s", workDir, "settings");
|
|
||||||
serializeOptions(buf, &game->options);
|
|
||||||
|
|
||||||
unloadMap(game);
|
unloadMap(game);
|
||||||
|
|
||||||
@@ -320,6 +370,8 @@ void deinit(void *userData) {
|
|||||||
|
|
||||||
|
|
||||||
void update(float dt, void *userData) {
|
void update(float dt, void *userData) {
|
||||||
|
if (loopPaused)
|
||||||
|
return;
|
||||||
BZ_UNUSED(userData);
|
BZ_UNUSED(userData);
|
||||||
|
|
||||||
char titleBuf[32];
|
char titleBuf[32];
|
||||||
@@ -329,6 +381,22 @@ void update(float dt, void *userData) {
|
|||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
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;
|
game->screenPrevFrame = game->screen;
|
||||||
if (game->screen != game->nextScreen)
|
if (game->screen != game->nextScreen)
|
||||||
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) {
|
void render(float dt, void *userData) {
|
||||||
|
if (loopPaused)
|
||||||
|
return;
|
||||||
BZ_UNUSED(userData);
|
BZ_UNUSED(userData);
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
|
|
||||||
@@ -600,9 +670,9 @@ void imguiRender(float dt, void *userData) {
|
|||||||
|
|
||||||
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
|
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
|
||||||
igBegin("Debug Menu", NULL, 0);
|
igBegin("Debug Menu", NULL, 0);
|
||||||
igText("PathData pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
|
igText("PathData pool available: %lu", bzObjectPoolGetNumFree(game->pools.pathData));
|
||||||
igText("BTNode pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNode));
|
igText("BTNode pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNode));
|
||||||
igText("BTNodeState pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNodeState));
|
igText("BTNodeState pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNodeState));
|
||||||
const char *inputState = "NONE";
|
const char *inputState = "NONE";
|
||||||
switch (input->state) {
|
switch (input->state) {
|
||||||
case INPUT_NONE:
|
case INPUT_NONE:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "../map_init.h"
|
#include "../map_init.h"
|
||||||
#include "../ui_widgets.h"
|
#include "../ui_widgets.h"
|
||||||
#include "../buildings.h"
|
#include "../buildings.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
void drawGameUI(Game *game, f32 dt) {
|
void drawGameUI(Game *game, f32 dt) {
|
||||||
// UI
|
// UI
|
||||||
@@ -303,6 +304,7 @@ void drawSettingsUI(Game *game, f32 dt) {
|
|||||||
opts = game->options;
|
opts = game->options;
|
||||||
}
|
}
|
||||||
if (uiSettingsButton("Apply")) {
|
if (uiSettingsButton("Apply")) {
|
||||||
|
serializeOptions(SETTINGS_PATH, &opts);
|
||||||
game->options = opts;
|
game->options = opts;
|
||||||
setScreen(game, SCREEN_MAIN_MENU);
|
setScreen(game, SCREEN_MAIN_MENU);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,4 +18,8 @@ static Rectangle getCameraBounds(Camera2D camera) {
|
|||||||
return bounds;
|
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
|
#endif //PIXELDEFENSE_UTILS_H
|
||||||
|
|||||||
BIN
settings.ini
Normal file
BIN
settings.ini
Normal file
Binary file not shown.
Reference in New Issue
Block a user