Compare commits

..
Author SHA1 Message Date
matt d9957eead1 feat: Nav mesh generation 2025-10-06 18:23:47 +01:00
matt c4cf8f532b feat: World loading that's broken 2025-10-06 16:35:22 +01:00
69 changed files with 297 additions and 35412 deletions

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 B

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

-1
View File
@@ -3,7 +3,6 @@
#define S(x) Str8_Wrap(sizeof(x) - sizeof(*(x)), (U8 *) (x))
#define Sz(x) Str8_WrapZ((U8 *) (x))
#define Sl(x) { sizeof(x) - sizeof(*(x)), (U8 *) (x) }
#define Sv(x) (int) (x).count, (x).data
#define Sf(arena, fmt, ...) Str8_Format(arena, fmt, ##__VA_ARGS__)
+41 -44
View File
@@ -151,8 +151,6 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
rect->texture = opts->texture;
F32 w, h;
rect->x = opts->p.x;
rect->y = opts->p.y;
@@ -179,19 +177,11 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
}
if (opts->flags & D_RECT_IGNORE_ASPECT) {
w = opts->dim.w;
h = opts->dim.h;
rect->w = opts->dim.w;
rect->h = opts->dim.h;
}
else {
Vk_Image *image = 0;
if (opts->texture >= draw->n_images) {
// @hack: first font texture
//
image = &draw->fonts->image;
}
else {
image = &draw->images[opts->texture].image;
}
Vk_Image *image = &draw->images[opts->texture].image;
F32 width = cast(F32) image->width;
F32 height = cast(F32) image->height;
@@ -201,42 +191,53 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
height *= (opts->uv.max.y - opts->uv.min.y);
}
F32 aspect_w = (width > height) ? 1.0f : (width / height);
F32 aspect_h = (width > height) ? (height / width) : 1.0f;
F32 aspect_w = (width > height) ? (width / height) : 1.0f;
F32 aspect_h = (width > height) ? 1.0f : (height / width);
w = opts->scale * aspect_w;
h = opts->scale * aspect_h;
rect->w = opts->scale * aspect_w;
rect->h = opts->scale * aspect_h;
}
if (opts->flags & D_RECT_FLIP_X) { w *= -1.0f; }
if (opts->flags & D_RECT_FLIP_Y) { h *= -1.0f; }
rect->w = w;
rect->h = h;
draw->n_rects += 1;
}
}
void D_Text(D_Context *draw, D_Font *font, Str8 text, F32 x, F32 y) {
F32 xoff = x;
// @Todo: control scale
F32 scale = 1.0f / (font->ascent - font->descent);
local_persist B32 done = 0;
for (S64 it = 0; it < text.count; ++it) {
if (text.data[it] >= ' ' && text.data[it] <= '~') {
D_Glyph *glyph = &font->glyphs[text.data[it] - ' '];
F32 image_scale = scale * Max(glyph->dim.w, glyph->dim.h);
F32 advance = scale * glyph->advance;
V2f size;
size.w = (glyph->box.max.x - glyph->box.min.x);
size.h = (glyph->box.max.y - glyph->box.min.y);
V2f offset = V2f_Scale(glyph->offset, scale);
V2f dim;
D_Rect(draw, xoff + offset.x, y + offset.y, .texture = font->id, .uv = glyph->box, .scale = image_scale, .flags = D_RECT_UV_ASPECT);
xoff += advance;
F32 scale = 150.0f / (font->ascent - font->descent);
if (size.w > size.h) {
dim.w = scale * (size.w / size.h);
dim.h = scale;
}
else {
dim.w = scale;
dim.h = scale * (size.h / size.w);
}
// @Hardcode: need font index in font struct
D_Rect(draw, xoff, y, .texture = 0, .c = V4F(0, 1, 1, 1), .dim = dim, .flags = D_RECT_IGNORE_ASPECT);
D_Rect(draw, xoff, y, .texture = draw->n_images, .uv = glyph->box, .dim = dim, .flags = D_RECT_IGNORE_ASPECT);
xoff += (1.05f * dim.w); // glyph->advance; //+ glyph->offset.x;
if (!done) { printf(" %f (%f, %f)", xoff, dim.w, dim.h); }
}
}
if (!done) { printf("\n"); }
done = true;
}
void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
@@ -251,7 +252,7 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
stbtt_fontinfo info = { 0 };
stbtt_InitFont(&info, font_data.data, 0);
F32 scale = stbtt_ScaleForPixelHeight(&info, 256);
F32 scale = stbtt_ScaleForPixelHeight(&info, 20);
U32 w = 512;
U32 h = 512;
@@ -267,12 +268,14 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
D_Font *font = M_ArenaPush(draw->arena, D_Font);
font->px = size;
S32 asc, desc, line;
stbtt_GetFontVMetrics(&info, &asc, &desc, &line);
font->line_advance = cast(F32) (scale * line);
font->ascent = cast(F32) (scale * asc);
font->descent = cast(F32) (scale * desc);
font->line_advance = cast(F32) line;
font->ascent = cast(F32) asc;
font->descent = cast(F32) desc;
font->glyphs = M_ArenaPush(draw->arena, D_Glyph, .count = count);
@@ -283,14 +286,10 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
S32 left, width;
stbtt_GetCodepointHMetrics(&info, ' ' + it, &width, &left);
glyph->box.min = V2F(chr->x0 / (F32) w, chr->y0 / (F32) h);
glyph->box.max = V2F(chr->x1 / (F32) w, chr->y1 / (F32) h);
glyph->box = R2F(V2F(chr->x0 / (F32) w, chr->y0 / (F32) h), V2F(chr->x1 / (F32) w, chr->y1 / (F32) h));
glyph->advance = chr->xadvance;
glyph->dim.w = cast(F32) (chr->x1 - chr->x0);
glyph->dim.h = cast(F32) (chr->y1 - chr->y0);
glyph->offset.x = (0.5f * glyph->dim.w) + chr->xoff;
glyph->offset.y = (0.5f * glyph->dim.h) + chr->yoff;
glyph->advance = glyph->box.max.x - glyph->box.min.x; //chr->xadvance * scale;
glyph->offset = V2F(chr->xoff * scale, chr->yoff * scale);
}
Vk_Buffer *staging = &draw->staging;
@@ -303,8 +302,6 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
Vk_CommandBuffer *cmds = Vk_CommandBufferPush();
font->id = draw->n_images + draw->n_fonts;
font->image.width = w;
font->image.height = h;
+2 -7
View File
@@ -6,10 +6,7 @@
typedef struct D_Glyph D_Glyph;
struct D_Glyph {
F32 advance;
V2f offset;
V2f dim;
R2f box;
};
@@ -17,13 +14,13 @@ typedef struct D_Font D_Font;
struct D_Font {
D_Font *next;
U32 id;
F32 px;
F32 line_advance;
F32 ascent;
F32 descent;
F32 *kerning; // @incomplete: we don't load this
F32 *kerning;
D_Glyph *glyphs;
Vk_Image image;
@@ -111,8 +108,6 @@ enum D_RectFlags {
D_RECT_IGNORE_ASPECT = (1 << 0), // by default only width is used as a "dimension"
D_RECT_PER_VERTEX_COLOUR = (1 << 1), // split colours per vertex
D_RECT_UV_ASPECT = (1 << 2), // get the aspect from the uv rect rather than the full image
D_RECT_FLIP_X = (1 << 3),
D_RECT_FLIP_Y = (1 << 4)
};
typedef struct D_RectOpts D_RectOpts;
+100 -93
View File
@@ -24,7 +24,6 @@
#include "game/impl/world.c"
#include "game/impl/npc.c"
#include "game/impl/bandit.c"
#include "game/testnavmesh.h"
int main(int argc, char **argv)
{
@@ -79,8 +78,6 @@ int main(int argc, char **argv)
game->draw.arena = arena;
G_ImagesLoad(game);
D_FontLoad(&game->draw, S("ubuntu"), 60);
G_PipelinesLoad(game);
G_AudioLoad(game);
@@ -89,7 +86,7 @@ int main(int argc, char **argv)
camera->x = V3F(1, 0, 0);
camera->y = V3F(0, 1, 0);
camera->z = V3F(0, 0, 1);
camera->p = V3F(0, 0, 16);
camera->p = V3F(0, 0, 48);
camera->fov = 60.0f;
@@ -97,21 +94,22 @@ int main(int argc, char **argv)
camera->farp = 1000.0f;
game->draw.camera = camera;
World *world = M_ArenaPush(arena, World);//LoadWorld(arena);
World *world = M_ArenaPush(arena, World);
//LoadWorld(arena, world);
game->world = world;
world->arena = arena;
world->navMesh = &TestNavMesh;
//world->navMesh = &TestNavMesh;
world->random = Random_Seed(29237489723847);
world->npcCount = 2;
world->npcCount = 127;
for(U32 i = 0; i < world->npcCount; i++) {
NPC *npc1 = &world->npcs[i];
npc1->collision.pos.x = 15;
npc1->collision.pos.y = 15;
NPC *npc1 = &world->npcs[i];
npc1->collision.pos.x = 0;
npc1->collision.pos.y = 0;
npc1->collision.size.x = 1;
npc1->collision.size.y = 2;
npc1->name = S("Matt");
npc1->mode = NPC_ACTION_WAITING;
npc1->currentArea = i;
npc1->currentArea = WORLD_AREA_OUTSIDE;
npc1->waitTime = 0;
npc1->maxWaitTime = 5;
npc1->currentNavNode = 0;
@@ -127,105 +125,111 @@ int main(int argc, char **argv)
badman->waitTime = 0;
badman->maxWaitTime = 2;
badman->poiCount = 2;
badman->shootoutTimer = 1.5;
badman->agroRadius = 600.0;
badman->bullets = 6;
badman->shootDelay = 1;
badman->accuracyRange = 0.25;
badman->reloadTime = 2.5;
badman->reloadTimer = 0;
badman->pointsOfInterest[0] = 937;
badman->pointsOfInterest[1] = 12;
world->npcPOI[0] = 100;
world->player.world = world;
world->player.pos.x = 0;
world->player.pos.y = 0;
world->player.bulletsLoaded = PLAYER_BULLET_COUNT;
world->player.reloadTimer = 0;
world->player.currentArea = WORLD_AREA_OUTSIDE;
world->map = map;
PlayerInit(game, &world->player);
for(int i =0; i< 4200; i++) {
world->map[i] = map[i];
}
world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX);
world->tileTypes[0].rotation=0;
world->tileTypes[0].collision=false;
world->tileTypes[0].tile=D_ImageHandle(&game->draw, S("tile_dirt_0"));
world->tileTypes[0].tag=S("tile_dirt_0");
world->tileTypes[1].rotation=0,
world->tileTypes[1].collision=false,
world->tileTypes[1].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[1].tag=S("path_middle");
world->tileTypes[2].rotation=0;
world->tileTypes[2].collision=false;
world->tileTypes[2].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[2].tag=S("path_middle_edge");
world->tileTypes[3].rotation=PI_F32/2;
world->tileTypes[3].collision=false;
world->tileTypes[3].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[3].tag=S("path_middle_edge");
world->tileTypes[4].rotation=PI_F32;
world->tileTypes[4].collision=false;
world->tileTypes[4].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[4].tag=S("path_middle_edge");
world->tileTypes[5].rotation=-PI_F32/2;
world->tileTypes[5].collision=false;
world->tileTypes[5].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[5].tag=S("path_middle_edge");
world->tileTypes[6].rotation=0;
world->tileTypes[6].collision=false;
world->tileTypes[6].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[6].tag=S("path_middle");
world->tileTypes[7].rotation=PI_F32/2;
world->tileTypes[7].collision=false;
world->tileTypes[7].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[7].tag=S("path_middle");
world->tileTypes[8].rotation=-PI_F32;
world->tileTypes[8].collision=false;
world->tileTypes[8].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[8].tag=S("path_middle");
world->tileTypes[9].rotation=-PI_F32/2;
world->tileTypes[9].collision=false;
world->tileTypes[9].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[9].tag=S("path_middle");
world->tileTypes[10].rotation=0;
world->tileTypes[10].collision=false;
world->tileTypes[10].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[10].tag=S("path_corner");
world->tileTypes[11].rotation=PI_F32/2;
world->tileTypes[11].collision=false;
world->tileTypes[11].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[11].tag=S("path_corner");
world->tileTypes[12].rotation=-PI_F32/2;
world->tileTypes[12].collision=false;
world->tileTypes[12].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[12].tag=S("path_corner");
world->tileTypes[13].rotation=PI_F32;
world->tileTypes[13].collision=false;
world->tileTypes[13].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[13].tag=S("path_corner");
world->tileTypes[14].rotation=0;
world->tileTypes[14].collision=false;
world->tileTypes[14].tile=D_ImageHandle(&game->draw, S("tile_dirt_1"));
world->tileTypes[14].tag=S("tile_dirt_1");
world->propTypes[0].assetHandle=D_ImageHandle(&game->draw, S("rug0"));
world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX);
world->propTypes[0].tag=S("rug0");
world->propTypes[0].scale=1;
world->propTypes[1].assetHandle=D_ImageHandle(&game->draw, S("rug1"));
world->propTypes[1].tag=S("rug1");
world->propTypes[1].scale=1;
world->propTypes[2].assetHandle=D_ImageHandle(&game->draw, S("skull"));
world->propTypes[2].tag=S("skull");
world->propTypes[2].scale=1;
world->propTypes[3].assetHandle=D_ImageHandle(&game->draw, S("table"));
world->propTypes[3].scale=1;
world->propTypes[4].assetHandle=D_ImageHandle(&game->draw, S("barrel"));
world->propTypes[3].tag = S("table");
world->propTypes[3].scale=2;
world->propTypes[4].tag = S("barrel");
world->propTypes[4].scale=1;
world->propTypes[5].assetHandle=D_ImageHandle(&game->draw, S("can"));
world->propTypes[5].tag = S("can");
world->propTypes[5].scale=1;
world->propTypes[6].assetHandle=D_ImageHandle(&game->draw, S("candle"));
world->propTypes[6].tag = S("candle");
world->propTypes[6].scale=1;
world->propTypes[7].assetHandle=D_ImageHandle(&game->draw, S("clock"));
world->propTypes[7].tag = S("clock");
world->propTypes[7].scale=1;
world->propTypes[8].assetHandle=D_ImageHandle(&game->draw, S("log_pile"));
world->propTypes[8].tag = S("log_pile");
world->propTypes[8].scale=1;
world->propTypes[9].assetHandle=D_ImageHandle(&game->draw, S("nightstand"));
world->propTypes[9].tag = S("nightstand");
world->propTypes[9].scale=1;
world->propTypes[10].assetHandle=D_ImageHandle(&game->draw, S("pool_table"));
world->propTypes[10].scale=1;
world->propTypes[11].assetHandle=D_ImageHandle(&game->draw, S("saloon_ext"));
world->propTypes[10].tag = S("pool_table");
world->propTypes[10].scale=2;
world->propTypes[11].tag = S("saloon_ext");
world->propTypes[11].scale=6.875f;
world->propTypes[12].assetHandle=D_ImageHandle(&game->draw, S("saloon_int"));
world->propTypes[12].scale=6.875f;
world->propTypes[11].assetHandle=D_ImageHandle(&game->draw, S("house"));
world->propTypes[11].scale=6.875f;
world->propTypes[12].assetHandle=D_ImageHandle(&game->draw, S("house_int"));
world->propTypes[12].scale=6.875f;
world->propTypes[12].tag = S("saloon_int");
world->propTypes[12].scale=2*6.875f;
world->propTypes[13].tag = S("house");
world->propTypes[13].scale=6.875f;
world->propTypes[14].tag = S("house_int");
world->propTypes[14].scale=6.875f;
world->propTypes[15].tag=S("tile_detail_0");
world->propTypes[15].scale=1;
world->propTypes[16].tag = S("tile_detail_1");
world->propTypes[16].scale=1;
world->propTypes[17].tag = S("tile_detail_2");
world->propTypes[17].scale=1;
world->propTypes[18].tag= S("tile_detail_3");
world->propTypes[18].scale=1;
world->propTypes[19].tag= S("tile_detail_4");
world->propTypes[19].scale=1;
world->propTypes[20].tag=S("tile_detail_5");
world->propTypes[20].scale=1;
world->propTypes[21].tag=S("tile_detail_6");
world->propTypes[21].scale=1;
world->propCount = 0;
world->props = M_ArenaPush(arena, World_Prop, .count=WORLD_PROP_MAX);
world->hitboxes = M_ArenaPush(arena, AABB, .count=WORLD_HITBOX_MAX);
GenerateNavMesh(arena, world);
}
game->editor.enabled = false;
game->editor.mode = G_EDITOR_MODE_TILE;
game->editor.currentLevel = WORLD_AREA_OUTSIDE;
D_Animation animation;
{
U32 id = D_ImageHandle(&game->draw, S("npc_front_base_white"));
D_AnimationInit(&animation, id, 1, 4, 1.0f / 20.0f);
}
bool running = true;
const int width = 1280;
@@ -240,13 +244,6 @@ int main(int argc, char **argv)
{
running = false;
}
else if (e.type == SDL_EVENT_KEY_DOWN) {
Player *player = &game->world->player;
switch (e.key.key) {
case SDLK_R: { PlayerInit(game, player); } break;
}
}
V3f projection = G_CameraUnproject(&game->camera, V2f_Clip(
V2F(e.button.x, e.button.y),
V2F((F32) width, (F32) height)
@@ -261,8 +258,8 @@ int main(int argc, char **argv)
if(e.type==SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
switch(game->editor.mode){
case G_EDITOR_MODE_TILE: {
F32 tilex = (F32) (S32)(game->editor.cursor.x+TILE_SIZE/2);
F32 tiley = (F32) (S32)(game->editor.cursor.y+TILE_SIZE/2);
F32 tilex = (S32)(game->editor.cursor.x+TILE_SIZE/2);
F32 tiley = (S32)(game->editor.cursor.y+TILE_SIZE/2);
game->world->map[(S32)tilex + (S32)tiley * 96] = game->editor.currentAsset;
break;
}
@@ -332,6 +329,7 @@ int main(int argc, char **argv)
}
case SDLK_SPACE: {
game->editor.mode = (game->editor.mode + 1) % 4;
printf("EDITOR MODE %d\n", game->editor.mode);
break;
}
case SDLK_U: {
@@ -347,10 +345,10 @@ int main(int argc, char **argv)
if(!game->editor.enabled) {
UpdateWorld(1.0f / 60.0f, game->world);
game->camera.p.x = game->world->player.collision.pos.x;
game->camera.p.y = game->world->player.collision.pos.y;
game->camera.p.x = game->world->player.pos.x;
game->camera.p.y = game->world->player.pos.y;
}
D_AnimationUpdate(&animation, 1.0f / 250.0f);
int w, h;
SDL_GetWindowSizeInPixels(window, &w, &h);
@@ -390,27 +388,36 @@ int main(int argc, char **argv)
RenderWorld(game->world, &game->draw);
D_Text(&game->draw, game->draw.fonts, S("Small Test"), 0, 0);
R2f aframe = D_AnimationFrame(&animation);
D_Rect(&game->draw, 0, 0, .texture = animation.id, .uv = aframe, .flags = D_RECT_UV_ASPECT);
if(game->editor.enabled) {
G_Editor editor = game->editor;
F32 tilex = cast(F32) floor(editor.cursor.x+TILE_SIZE/2);
F32 tiley = cast(F32) floor(editor.cursor.y+TILE_SIZE/2);
F32 tilex = floor(editor.cursor.x+TILE_SIZE/2);
F32 tiley = floor(editor.cursor.y+TILE_SIZE/2);
switch(game->editor.mode) {
case G_EDITOR_MODE_TILE: {
World_Tile asset = game->world->tileTypes[editor.currentAsset];
D_Rect(&game->draw, tilex, tiley, .texture=asset.tile, .angle=(F32) asset.rotation);
D_Rect(&game->draw, tilex, tiley, .texture=D_ImageHandle(&game->draw, asset.tag), .angle=asset.rotation);
break;
}
case G_EDITOR_MODE_PROP: {
World_PropType prop = game->world->propTypes[editor.currentAsset];
D_Rect(&game->draw, editor.cursor.x, editor.cursor.y, .texture=prop.assetHandle, .scale=prop.scale);
D_Rect(&game->draw, editor.cursor.x, editor.cursor.y, .texture=D_ImageHandle(&game->draw, prop.tag), .scale=prop.scale);
break;
}
case G_EDITOR_MODE_HITBOX: {
for(U32 i = 0; i < game->world->hitboxCount; i++) {
for(int i = 0; i < game->world->hitboxCount; i++) {
V2f centre = AABB_Centre(game->world->hitboxes[i]);
D_Rect(&game->draw, centre.x, centre.y, .texture=0, .dim=game->world->hitboxes[i].size, .flags=D_RECT_IGNORE_ASPECT);
D_Rect(
&game->draw,
centre.x,
centre.y,
.texture=0,
.dim=game->world->hitboxes[i].size,
.flags=D_RECT_IGNORE_ASPECT,
.c=V4F(100,0,0,0.7),
);
}
break;
}
-1
View File
@@ -14,6 +14,5 @@ function bool AABB_Collide(AABB a, AABB b);
function bool AABB_Point(AABB a, V2f v);
function bool AABB_Slab(V2f origin, V2f point, AABB a);
function V2f AABB_Centre(AABB a);
function bool AABB_Circle(F32 rad, V2f radOrigin, AABB a);
#endif // LD_GAME_AABB_H_
+1 -9
View File
@@ -2,13 +2,11 @@
#define LD_GAME_BANDIT_H_
typedef enum BANDIT_ACTION BANDIT_ACTION;
enum BANDIT_ACTION
{
enum BANDIT_ACTION {
BANDIT_WAITING,
BANDIT_WALKING,
BANDIT_RUNNING,
BANDIT_SHOOTING,
BANDIT_SHOOTOUT,
};
typedef struct Bandit Bandit;
@@ -52,18 +50,12 @@ struct Bandit {
F32 shootDelay;
// After each shot this is set to shootDelay;
F32 shootCooldownTimer;
// Countdown to shootout
F32 shootoutTimer;
// How long it takes them to reload.
F32 reloadTime;
// When gun is empty this is set to reloadTime.
F32 reloadTimer;
// Accuracy, their shots can vary between this angle either side (rads)
F32 accuracyRange;
// A the circle around the bandit where they will trigger the quicktime reaction scene
F32 agroRadius;
};
function V2f shootTowards(Bandit* bandit, V2f target, Random* r);
#endif // LD_GAME_BANDIT_H_
+1 -45
View File
@@ -1,7 +1,6 @@
#if !defined(LD_GAME_CORE_H_)
#define LD_GAME_CORE_H_
typedef struct World World;
#include "world.h"
typedef struct G_Camera G_Camera;
struct G_Camera {
@@ -45,48 +44,6 @@ struct G_State {
World *world;
};
typedef U32 G_OutfitDirection;
enum {
G_OUTFIT_DIR_FRONT = 0,
G_OUTFIT_DIR_SIDE,
G_OUTFIT_DIR_BACK,
G_OUTFIT_DIR_FLIPPED = (1 << 16)
};
typedef union G_OutfitSet G_OutfitSet;
union G_OutfitSet {
struct {
U32 base;
U32 eyes;
U32 face;
U32 hair;
U32 hat;
U32 shirt;
U32 shoes;
U32 trousers;
};
U32 e[8];
};
typedef struct G_Outfit G_Outfit;
struct G_Outfit {
D_Animation state; // .id in here isn't used for drawing
G_OutfitDirection dir;
union {
struct {
G_OutfitSet front;
G_OutfitSet side;
G_OutfitSet back;
};
G_OutfitSet e[3];
};
};
function void G_ImagesLoad(G_State *game);
function void G_PipelinesLoad(G_State *game);
function void G_AudioLoad(G_State *game);
@@ -99,7 +56,6 @@ function V3f G_CameraUnproject(G_Camera *camera, V2f clip);
function R3f G_CameraBounds(G_Camera *camera);
#include "world.h"
#include "aabb.h"
#include "player.h"
#include "nav.h"
-8
View File
@@ -38,11 +38,3 @@ bool AABB_Slab(V2f origin, V2f point, AABB a)
V2f AABB_Centre(AABB a) {
return V2F(a.pos.x + a.size.x/2, a.pos.y + a.size.y/2);
}
bool AABB_Circle(F32 rad, V2f radOrigin, AABB a)
{
V2f aCentre = AABB_Centre(a);
F32 xSq = (Abs(aCentre.x) - Abs(radOrigin.x)) * (Abs(aCentre.x) - Abs(radOrigin.x));
F32 ySq = (Abs(aCentre.y) - Abs(radOrigin.y)) * (Abs(aCentre.y) - Abs(radOrigin.y));
return SDL_sqrt(xSq + ySq) < rad;
}
+2 -42
View File
@@ -1,27 +1,13 @@
#include "game/world.h"
#include "game/bandit.h"
V2f shootTowards(Bandit *bandit, V2f target, Random* r)
{
V2f shooterV2 = bandit->collision.pos;
F32 randX = Random_F32(r, -bandit->accuracyRange, bandit->accuracyRange);
F32 randY = Random_F32(r, -bandit->accuracyRange, bandit->accuracyRange);
return V2F(shooterV2.x + (target.x - shooterV2.x) * (1 + randX), shooterV2.x + (target.y - shooterV2.y) * (1 + randY));
}
void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
if (
world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea)
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea)
{
printf("You shot the bandit %*.s\n", Sv(bandit->name));
bandit->health--;
}
if (AABB_Circle(bandit->agroRadius, AABB_Centre(bandit->collision), world->player.collision) && !(bandit->mode == BANDIT_SHOOTING || bandit->mode == BANDIT_SHOOTOUT))
{
printf("begin shootout");
// shootout time o.o
bandit->mode = BANDIT_SHOOTOUT;
}
switch (bandit->mode) {
case BANDIT_WAITING:
bandit->waitTime+=delta;
@@ -55,33 +41,7 @@ void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
bandit->collision.pos.x = cNav.pos.x * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.x * bandit->walkTimer/NPC_SPEED;
bandit->collision.pos.y = cNav.pos.y * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.y * bandit->walkTimer/NPC_SPEED;
break;
case BANDIT_SHOOTOUT:
bandit->shootoutTimer-=delta;
if(bandit->shootoutTimer < 0){
bandit->mode=BANDIT_SHOOTING;
}
break;
case BANDIT_SHOOTING:
bandit->shootCooldownTimer -= delta;
bandit->reloadTimer -= delta;
if (bandit->shootCooldownTimer < 0 && bandit->reloadTimer < 0)
{
printf("shoot at player");
bandit->bullets--;
bandit->shootCooldownTimer = bandit->shootDelay;
V2f banditShot = shootTowards(bandit, world->player.collision.pos, &world->random);
if(AABB_Slab(bandit->collision.pos, banditShot, world->player.collision)){
// gets shot lmao
printf("hit");
world->player.health--;
}
if(bandit->bullets == 0){
printf("enemy reload");
bandit->bullets = 6;
bandit->reloadTimer = bandit->reloadTime;
}
}
break;
// TODO Shooting
// TODO Running away
}
}
+2 -109
View File
@@ -3,80 +3,6 @@
#include <SDL3/SDL_keycode.h>
#include <stdio.h>
// @Todo: move/extern these so the npc/bandit can use them
//
#define G_OUTFIT_COMPONENT_COUNT 8
global_var Str8 __outfit_names[] = {
Sl("npc_%s_base_%d"),
Sl("npc_%s_eyes_%d"),
Sl("npc_%s_face_%d"),
Sl("npc_%s_hair_%d"),
Sl("npc_%s_hat_%d"),
Sl("npc_%s_shirt_%d"),
Sl("npc_%s_shoes_%d"),
Sl("npc_%s_trousers_%d")
};
global_var U32 __outfit_counts[] = {
2, // base
3, // eyes
5, // face
4, // hair
3, // hat
2, // shirt
1, // shoes
2 // trousers
};
global_var U32 __outfit_back_counts[] = {
2, // base
0, // eyes
3, // face
4, // hair
3, // hat
2, // shirt
1, // shoes
2 // trousers
};
StaticAssert(ArraySize(__outfit_names) == ArraySize(__outfit_counts));
#define OUTFIT_IMG(dir, n) D_ImageHandle(&game->draw, Sf(temp.arena, (const char *) __outfit_names[it].data, #dir, n))
void PlayerInit(G_State *game, Player *player) {
World *world = game->world;
player->world = world;
player->bulletsLoaded = PLAYER_BULLET_COUNT;
player->currentArea = WORLD_AREA_OUTSIDE;
player->health = 3;
player->collision.size.x = 1;
player->collision.size.x = 2;
G_Outfit *outfit = &player->outfit;
D_AnimationInit(&outfit->state, 0, 1, 4, 1.0f / 6.0f);
M_TempScope(0, 0) {
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
U32 idx = Random_Next(&world->random) % __outfit_counts[it];
// We just allow face, hair and hat to default to 0 meaning the player doesn't have one
if (idx != 0 || it < 2 || it > 4) {
outfit->front.e[it] = OUTFIT_IMG(front, idx);
outfit->side.e[it] = OUTFIT_IMG(side, idx);
if ((idx + 1) <= __outfit_counts[it]) {
outfit->back.e[it] = OUTFIT_IMG(back, idx);
}
}
}
}
}
void PlayerInput(SDL_Event *event, Player *player)
{
SDL_KeyboardEvent key = event->key;
@@ -127,34 +53,18 @@ void PlayerInput(SDL_Event *event, Player *player)
void PlayerUpdate(F32 delta, Player *player) {
player->controls.shot = false;
V2f dir = V2F(0, 0);
if(player->health == 0){
printf("dead :(");
player->health = 3;
}
if(player->controls.upDown) {
dir.y -= 1;
player->outfit.dir = G_OUTFIT_DIR_BACK;
}
if(player->controls.downDown) {
dir.y += 1;
player->outfit.dir = G_OUTFIT_DIR_FRONT;
}
if(player->controls.leftDown) {
dir.x -= 1;
player->outfit.dir = G_OUTFIT_DIR_SIDE | G_OUTFIT_DIR_FLIPPED;
}
if(player->controls.rightDown) {
dir.x += 1;
player->outfit.dir = G_OUTFIT_DIR_SIDE;
}
if (dir.x != 0 || dir.y != 0) {
D_AnimationUpdate(&player->outfit.state, delta);
}
else {
player->outfit.state.index = 0;
}
if(player->reloadTimer > 0) {
player->reloadTimer-=delta;
if(player->reloadTimer <= 0) {
@@ -163,23 +73,6 @@ void PlayerUpdate(F32 delta, Player *player) {
}
}
dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta);
player->collision.pos.x += dir.x;
player->collision.pos.y += dir.y;
}
void PlayerDraw(D_Context *draw, Player *player) {
G_Outfit *outfit = &player->outfit;
R2f pframe = D_AnimationFrame(&outfit->state);
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
U32 flipped = (outfit->dir & G_OUTFIT_DIR_FLIPPED) != 0;
U32 dir = (outfit->dir & ~G_OUTFIT_DIR_FLIPPED);
U32 tid = outfit->e[dir].e[it];
if (tid != 0) {
U32 flags = D_RECT_UV_ASPECT | (flipped ? D_RECT_FLIP_X : 0);
D_Rect(draw, player->collision.pos.x, player->collision.pos.y, .texture = tid, .uv = pframe, .flags = flags);
}
}
player->pos.x += dir.x;
player->pos.y += dir.y;
}
+129 -22
View File
@@ -9,9 +9,6 @@
void UpdateWorld(F32 delta, World *world)
{
if(world->bandit.mode == BANDIT_SHOOTOUT){
delta = delta/4;
}
UpdateBandit(delta, &world->bandit, world);
UpdateNPCs(delta, world);
PlayerUpdate(delta, &world->player);
@@ -24,7 +21,7 @@ void UpdateNPCs(F32 delta, World *world)
NPC *npc = &world->npcs[i];
UpdateNPC(delta, npc, world);
if (
world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea)
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea)
{
printf("You shot %*.s\n", Sv(world->npcs[i].name));
}
@@ -37,6 +34,9 @@ void ProcessEvents(SDL_Event *event, World *world)
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){
SaveWorld(world->arena, world);
}
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F6){
LoadWorld(world->arena, world);
}
}
void RenderWorld(World *world, D_Context *draw) {
@@ -45,22 +45,32 @@ void RenderWorld(World *world, D_Context *draw) {
D_Rect(
draw,
(F32) (i % 96), (F32) (i / 96),
.texture = world->tileTypes[world->map[i]].tile,
.texture = D_ImageHandle(draw,world->tileTypes[world->map[i]].tag),
.angle = (F32) world->tileTypes[world->map[i]].rotation,
);
}
}
for (U32 i = 0; i < world->propCount; i++) {
for (int i = 0; i < world->propCount; i++) {
if(world->props[i].area == world->player.currentArea) {
D_Rect(
draw,
world->props[i].pos.x,
world->props[i].pos.y,
.texture = world->propTypes[world->props[i].propType].assetHandle,
.texture = D_ImageHandle(draw,world->propTypes[world->props[i].propType].tag),
.scale = world->propTypes[world->props[i].propType].scale,
);
}
}
for (int i = 0; i < world->navMesh->nodeCount; i++) {
NavNode n = world->navMesh->nodes[i];
D_Rect(
draw,
n.pos.x,
n.pos.y,
.texture = 0,
.scale = 0.2f,
);
}
for(U32 i = 0; i < world->npcCount; i++) {
NPC npc = world->npcs[i];
if(npc.currentArea == world->player.currentArea) {
@@ -72,32 +82,129 @@ void RenderWorld(World *world, D_Context *draw) {
V2f drawPos = AABB_Centre(world->bandit.collision);
D_Rect(draw, drawPos.x, drawPos.y, .texture = 9);
}
PlayerDraw(draw, &world->player);
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1);
}
void SaveWorld(M_Arena *arena, World *world) {
(void) arena;
printf("Saving world\n");
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE);
FS_FileWrite(file, world, sizeof(World)+sizeof(NavMesh), 0);
FS_FileWrite(file, world->navMesh, sizeof(World)+sizeof(NavMesh), sizeof(World));
U32 offset = 0;
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
FS_FileWrite(file, &world->tileTypes[i].tag.count, sizeof(S64), offset);
offset += sizeof(S64);
FS_FileWrite(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset);
offset += sizeof(U8) * world->tileTypes[i].tag.count;
FS_FileWrite(file, &world->tileTypes[i].rotation, sizeof(F32), offset);
offset += sizeof(F32);
}
for(int i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
FS_FileWrite(file, &world->propTypes[i].tag.count, sizeof(S64), offset);
offset += sizeof(S64);
FS_FileWrite(file, world->propTypes[i].tag.data, world->propTypes[i].tag.count, offset);
offset += sizeof(U8) * world->propTypes[i].tag.count;
FS_FileWrite(file, &world->propTypes[i].scale, sizeof(F32), offset);
offset += sizeof(F32);
}
FS_FileWrite(file, world->propTypes, sizeof(World_PropType)*WORLD_PROP_TYPE_MAX, offset);
offset += sizeof(World_PropType)*WORLD_PROP_TYPE_MAX;
FS_FileWrite(file, &world->propCount, sizeof(U32), offset);
offset += sizeof(U32);
FS_FileWrite(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset);
offset += sizeof(World_Prop)*WORLD_PROP_MAX;
FS_FileWrite(file, &world->hitboxCount, sizeof(U32), offset);
offset += sizeof(U32);
FS_FileWrite(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset);
offset += sizeof(AABB)*WORLD_HITBOX_MAX;
FS_FileWrite(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset);
offset += sizeof(U32)*WORLD_MAP_MAX;
FS_FileClose(file);
printf("Saved world :)\n");
}
World *LoadWorld(M_Arena *arena) {
void LoadWorld(M_Arena *arena, World *world) {
printf("loading world\n");
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_READ);
World *world = M_ArenaPush(arena, World);
NavMesh *navMesh = M_ArenaPush(arena, NavMesh);
FS_FileRead(file, world, sizeof(World), 0);
FS_FileRead(file, navMesh, sizeof(NavMesh), sizeof(World));
U32 offset = 0;
world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX);
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
FS_FileRead(file, &world->tileTypes[i].tag.count, sizeof(S64), offset);
offset += sizeof(S64);
world->tileTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->tileTypes[i].tag.count);
FS_FileRead(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset);
offset += sizeof(U8) * world->tileTypes[i].tag.count;
FS_FileRead(file, &world->tileTypes[i].rotation, sizeof(F32), offset);
offset += sizeof(F32);
}
world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX);
for(int i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
FS_FileRead(file, &world->propTypes[i].tag.count, sizeof(S64), offset);
offset += sizeof(S64);
world->propTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->propTypes[i].tag.count);
FS_FileRead(file, world->propTypes[i].tag.data, world->propTypes[i].tag.count, offset);
offset += sizeof(U8) * world->propTypes[i].tag.count;
FS_FileRead(file, &world->propTypes[i].scale, sizeof(F32), offset);
offset += sizeof(F32);
}
FS_FileRead(file, &world->propCount, sizeof(U32), offset);
offset += sizeof(U32);
world->props = M_ArenaPush(arena, World_Prop, .count=WORLD_PROP_MAX);
FS_FileRead(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset);
offset += sizeof(World_Prop)*world->propCount;
FS_FileRead(file, &world->hitboxCount, sizeof(U32), offset);
offset += sizeof(U32);
world->hitboxes = M_ArenaPush(arena, AABB, .count=WORLD_HITBOX_MAX);
FS_FileRead(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset);
offset += sizeof(AABB)*world->hitboxCount;
world->map = M_ArenaPush(arena, U32, .count=WORLD_MAP_MAX);
FS_FileRead(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset);
offset += sizeof(U32)*WORLD_MAP_MAX;
FS_FileClose(file);
world->navMesh = navMesh;
world->arena = arena;
world->player.world = world;
printf("loaded world\n");
return world;
}
void GenerateNavMesh(M_Arena *arena, World *world) {
world->navMesh = M_ArenaPush(arena, NavMesh);
world->navMesh->nodeCount = 0;
for(int i = 0; i < WORLD_MAP_MAX; i++) {
U32 x = (i % 96);
U32 y = (i / 96);
world->navMesh->nodes[world->navMesh->nodeCount].pos.x = x;
world->navMesh->nodes[world->navMesh->nodeCount].pos.y = y;
U32 cost = 20;
if(Str8_Equal(world->tileTypes[world->map[i]].tag, S("path_middle"), STR8_EQUAL_IGNORE_CASE)) {
cost = 10;
}
world->navMesh->nodes[world->navMesh->nodeCount].connectionCount = 0;
for(int nx = -1; nx < 2; nx++){
for(int ny = -1; ny < 2; ny++){
if((nx==ny) && nx==0) {continue;}
if(x+nx < 0 || x+nx > 95) {
continue;
}
if(y+ny < 0 || y+ny > 49) {
continue;
}
U32 index = x+nx + (y+ny)*96;
U32 nCount = world->navMesh->nodeCount;
world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].NodeIndex = index;
world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].Cost = cost;
world->navMesh->nodes[nCount].connectionCount++;
}
}
world->navMesh->nodeCount++;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
#define NAV_MAX_PATH 1024
#define NAV_MAX_CONNECTIONS 8
#define NAV_MAX_NODES 4096
#define NAV_MAX_NODES 4800
typedef struct NavNode NavNode;
+1 -8
View File
@@ -5,7 +5,6 @@
#include "../core/macros.h"
#include <SDL3/SDL_events.h>
#include "aabb.h"
#define PLAYER_SPEED 10.0f
#define PLAYER_RELOAD_TIME 1.5f
@@ -24,21 +23,15 @@ typedef struct Player Player;
struct Player
{
World *world;
AABB collision;
V2f pos;
World_Area currentArea;
U32 bulletsLoaded;
ControlState controls;
V2f shotPos;
G_Outfit outfit;
U32 health;
F32 reloadTimer;
};
function void PlayerInit(G_State *game, Player *player);
function void PlayerDraw(D_Context *draw, Player *player);
function void PlayerInput(SDL_Event *event, Player *player);
function void PlayerUpdate(F32 delta, Player *player);
File diff suppressed because it is too large. Load diff
+17 -10
View File
@@ -3,6 +3,12 @@
#include "../core/math.h"
#define WORLD_HITBOX_MAX 4096
#define WORLD_PROP_MAX 2048
#define WORLD_PROP_TYPE_MAX 64
#define WORLD_TILE_TYPE_MAX 64
#define WORLD_MAP_MAX 4800
// Areas are which
typedef U32 World_Area;
enum World_Area
@@ -13,14 +19,13 @@ enum World_Area
typedef struct World_Tile World_Tile;
struct World_Tile {
U32 tile;
double rotation;
bool collision;
Str8 tag;
F32 rotation;
};
typedef struct World_PropType World_PropType;
struct World_PropType {
U32 assetHandle;
Str8 tag;
F32 scale;
};
@@ -44,14 +49,15 @@ struct World {
NavMesh *navMesh;
Random random;
V2f mouseProjected;
World_Tile tileTypes[64];
U32 map[4800];
//// Loaded from world file
World_Tile *tileTypes;
World_PropType *propTypes;
World_Prop *props;
AABB *hitboxes;
U32 *map;
World_PropType propTypes[64];
U32 propCount;
World_Prop props[256];
U32 hitboxCount;
AABB hitboxes[4096];
//// Player
Player player;
@@ -75,7 +81,8 @@ function void UpdateNPCs(F32 delta, World *world);
function void UpdateNPC(F32 delta, NPC *npc, World *world);
function void UpdateBandit(F32 delta, Bandit *bandit, World *world);
function World *LoadWorld(M_Arena *arena);
function void LoadWorld(M_Arena *arena, World *world);
function void SaveWorld(M_Arena *arena, World *world);
function void GenerateNavMesh(M_Arena *arena, World *world);
#endif // LD_GAME_WORLD_H_
BIN
View File
Binary file not shown.