Compare commits

2 Commits

Author SHA1 Message Date
d54b4df4c2 player health 2025-10-06 17:45:58 +01:00
fcc7adfb22 added badman shooting and reloading 2025-10-06 17:30:49 +01:00
12 changed files with 35190 additions and 233 deletions

View File

@@ -24,6 +24,7 @@
#include "game/impl/world.c" #include "game/impl/world.c"
#include "game/impl/npc.c" #include "game/impl/npc.c"
#include "game/impl/bandit.c" #include "game/impl/bandit.c"
#include "game/testnavmesh.h"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -94,22 +95,21 @@ int main(int argc, char **argv)
camera->farp = 1000.0f; camera->farp = 1000.0f;
game->draw.camera = camera; game->draw.camera = camera;
World *world = M_ArenaPush(arena, World); World *world = M_ArenaPush(arena, World);//LoadWorld(arena);
//LoadWorld(arena, world);
game->world = world; game->world = world;
world->arena = arena; world->arena = arena;
//world->navMesh = &TestNavMesh; world->navMesh = &TestNavMesh;
world->random = Random_Seed(29237489723847); world->random = Random_Seed(29237489723847);
world->npcCount = 127; world->npcCount = 2;
for(U32 i = 0; i < world->npcCount; i++) { for(U32 i = 0; i < world->npcCount; i++) {
NPC *npc1 = &world->npcs[i]; NPC *npc1 = &world->npcs[i];
npc1->collision.pos.x = 0; npc1->collision.pos.x = 15;
npc1->collision.pos.y = 0; npc1->collision.pos.y = 15;
npc1->collision.size.x = 1; npc1->collision.size.x = 1;
npc1->collision.size.y = 2; npc1->collision.size.y = 2;
npc1->name = S("Matt"); npc1->name = S("Matt");
npc1->mode = NPC_ACTION_WAITING; npc1->mode = NPC_ACTION_WAITING;
npc1->currentArea = WORLD_AREA_OUTSIDE; npc1->currentArea = i;
npc1->waitTime = 0; npc1->waitTime = 0;
npc1->maxWaitTime = 5; npc1->maxWaitTime = 5;
npc1->currentNavNode = 0; npc1->currentNavNode = 0;
@@ -125,99 +125,106 @@ int main(int argc, char **argv)
badman->waitTime = 0; badman->waitTime = 0;
badman->maxWaitTime = 2; badman->maxWaitTime = 2;
badman->poiCount = 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[0] = 937;
badman->pointsOfInterest[1] = 12; badman->pointsOfInterest[1] = 12;
world->npcPOI[0] = 100; world->npcPOI[0] = 100;
world->player.world = world; world->player.world = world;
world->player.pos.x = 0; world->player.collision.pos.x = 0;
world->player.pos.y = 0; world->player.collision.pos.y = 0;
world->player.collision.size.x = 1;
world->player.collision.size.y = 2;
world->player.bulletsLoaded = PLAYER_BULLET_COUNT; world->player.bulletsLoaded = PLAYER_BULLET_COUNT;
world->player.reloadTimer = 0; world->player.reloadTimer = 0;
world->player.health = 3;
world->player.currentArea = WORLD_AREA_OUTSIDE; world->player.currentArea = WORLD_AREA_OUTSIDE;
world->map = map; 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].rotation=0;
world->tileTypes[0].tag=S("tile_dirt_0"); world->tileTypes[0].collision=false;
world->tileTypes[0].tile=D_ImageHandle(&game->draw, S("tile_dirt_0"));
world->tileTypes[1].rotation=0, world->tileTypes[1].rotation=0,
world->tileTypes[1].tag=S("path_middle"); world->tileTypes[1].collision=false,
world->tileTypes[1].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[2].rotation=0; world->tileTypes[2].rotation=0;
world->tileTypes[2].tag=S("path_middle_edge"); world->tileTypes[2].collision=false;
world->tileTypes[2].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[3].rotation=PI_F32/2; world->tileTypes[3].rotation=PI_F32/2;
world->tileTypes[3].tag=S("path_middle_edge"); world->tileTypes[3].collision=false;
world->tileTypes[3].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[4].rotation=PI_F32; world->tileTypes[4].rotation=PI_F32;
world->tileTypes[4].tag=S("path_middle_edge"); world->tileTypes[4].collision=false;
world->tileTypes[4].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[5].rotation=-PI_F32/2; world->tileTypes[5].rotation=-PI_F32/2;
world->tileTypes[5].tag=S("path_middle_edge"); world->tileTypes[5].collision=false;
world->tileTypes[5].tile=D_ImageHandle(&game->draw, S("path_middle_edge"));
world->tileTypes[6].rotation=0; world->tileTypes[6].rotation=0;
world->tileTypes[6].tag=S("path_middle"); world->tileTypes[6].collision=false;
world->tileTypes[6].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[7].rotation=PI_F32/2; world->tileTypes[7].rotation=PI_F32/2;
world->tileTypes[7].tag=S("path_middle"); world->tileTypes[7].collision=false;
world->tileTypes[7].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[8].rotation=-PI_F32; world->tileTypes[8].rotation=-PI_F32;
world->tileTypes[8].tag=S("path_middle"); world->tileTypes[8].collision=false;
world->tileTypes[8].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[9].rotation=-PI_F32/2; world->tileTypes[9].rotation=-PI_F32/2;
world->tileTypes[9].tag=S("path_middle"); world->tileTypes[9].collision=false;
world->tileTypes[9].tile=D_ImageHandle(&game->draw, S("path_middle"));
world->tileTypes[10].rotation=0; world->tileTypes[10].rotation=0;
world->tileTypes[10].tag=S("path_corner"); world->tileTypes[10].collision=false;
world->tileTypes[10].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[11].rotation=PI_F32/2; world->tileTypes[11].rotation=PI_F32/2;
world->tileTypes[11].tag=S("path_corner"); world->tileTypes[11].collision=false;
world->tileTypes[11].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[12].rotation=-PI_F32/2; world->tileTypes[12].rotation=-PI_F32/2;
world->tileTypes[12].tag=S("path_corner"); world->tileTypes[12].collision=false;
world->tileTypes[12].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[13].rotation=PI_F32; world->tileTypes[13].rotation=PI_F32;
world->tileTypes[13].tag=S("path_corner"); world->tileTypes[13].collision=false;
world->tileTypes[13].tile=D_ImageHandle(&game->draw, S("path_corner"));
world->tileTypes[14].rotation=0; world->tileTypes[14].rotation=0;
world->tileTypes[14].tag=S("tile_dirt_1"); world->tileTypes[14].collision=false;
world->tileTypes[14].tile=D_ImageHandle(&game->draw, S("tile_dirt_1"));
world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX); world->propTypes[0].assetHandle=D_ImageHandle(&game->draw, S("rug0"));
world->propTypes[0].tag=S("rug0");
world->propTypes[0].scale=1; world->propTypes[0].scale=1;
world->propTypes[1].tag=S("rug1"); world->propTypes[1].assetHandle=D_ImageHandle(&game->draw, S("rug1"));
world->propTypes[1].scale=1; world->propTypes[1].scale=1;
world->propTypes[2].tag=S("skull"); world->propTypes[2].assetHandle=D_ImageHandle(&game->draw, S("skull"));
world->propTypes[2].scale=1; world->propTypes[2].scale=1;
world->propTypes[3].tag = S("table"); world->propTypes[3].assetHandle=D_ImageHandle(&game->draw, S("table"));
world->propTypes[3].scale=2; world->propTypes[3].scale=1;
world->propTypes[4].tag = S("barrel"); world->propTypes[4].assetHandle=D_ImageHandle(&game->draw, S("barrel"));
world->propTypes[4].scale=1; world->propTypes[4].scale=1;
world->propTypes[5].tag = S("can"); world->propTypes[5].assetHandle=D_ImageHandle(&game->draw, S("can"));
world->propTypes[5].scale=1; world->propTypes[5].scale=1;
world->propTypes[6].tag = S("candle"); world->propTypes[6].assetHandle=D_ImageHandle(&game->draw, S("candle"));
world->propTypes[6].scale=1; world->propTypes[6].scale=1;
world->propTypes[7].tag = S("clock"); world->propTypes[7].assetHandle=D_ImageHandle(&game->draw, S("clock"));
world->propTypes[7].scale=1; world->propTypes[7].scale=1;
world->propTypes[8].tag = S("log_pile"); world->propTypes[8].assetHandle=D_ImageHandle(&game->draw, S("log_pile"));
world->propTypes[8].scale=1; world->propTypes[8].scale=1;
world->propTypes[9].tag = S("nightstand"); world->propTypes[9].assetHandle=D_ImageHandle(&game->draw, S("nightstand"));
world->propTypes[9].scale=1; world->propTypes[9].scale=1;
world->propTypes[10].tag = S("pool_table"); world->propTypes[10].assetHandle=D_ImageHandle(&game->draw, S("pool_table"));
world->propTypes[10].scale=2; world->propTypes[10].scale=1;
world->propTypes[11].tag = S("saloon_ext"); world->propTypes[11].assetHandle=D_ImageHandle(&game->draw, S("saloon_ext"));
world->propTypes[11].scale=6.875f; world->propTypes[11].scale=6.875f;
world->propTypes[12].tag = S("saloon_int"); world->propTypes[12].assetHandle=D_ImageHandle(&game->draw, S("saloon_int"));
world->propTypes[12].scale=2*6.875f; world->propTypes[12].scale=6.875f;
world->propTypes[13].tag = S("house"); world->propTypes[11].assetHandle=D_ImageHandle(&game->draw, S("house"));
world->propTypes[13].scale=6.875f; world->propTypes[11].scale=6.875f;
world->propTypes[14].tag = S("house_int"); world->propTypes[12].assetHandle=D_ImageHandle(&game->draw, S("house_int"));
world->propTypes[14].scale=6.875f; world->propTypes[12].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.enabled = false;
game->editor.mode = G_EDITOR_MODE_TILE; game->editor.mode = G_EDITOR_MODE_TILE;
@@ -232,6 +239,8 @@ int main(int argc, char **argv)
bool running = true; bool running = true;
printf("%zu size in bytes\n", sizeof(TestNavMesh));
const int width = 1280; const int width = 1280;
const int height = 720; const int height = 720;
@@ -329,7 +338,6 @@ int main(int argc, char **argv)
} }
case SDLK_SPACE: { case SDLK_SPACE: {
game->editor.mode = (game->editor.mode + 1) % 4; game->editor.mode = (game->editor.mode + 1) % 4;
printf("EDITOR MODE %d\n", game->editor.mode);
break; break;
} }
case SDLK_U: { case SDLK_U: {
@@ -345,8 +353,8 @@ int main(int argc, char **argv)
if(!game->editor.enabled) { if(!game->editor.enabled) {
UpdateWorld(1.0f / 60.0f, game->world); UpdateWorld(1.0f / 60.0f, game->world);
game->camera.p.x = game->world->player.pos.x; game->camera.p.x = game->world->player.collision.pos.x;
game->camera.p.y = game->world->player.pos.y; game->camera.p.y = game->world->player.collision.pos.y;
} }
D_AnimationUpdate(&animation, 1.0f / 250.0f); D_AnimationUpdate(&animation, 1.0f / 250.0f);
@@ -398,26 +406,18 @@ int main(int argc, char **argv)
switch(game->editor.mode) { switch(game->editor.mode) {
case G_EDITOR_MODE_TILE: { case G_EDITOR_MODE_TILE: {
World_Tile asset = game->world->tileTypes[editor.currentAsset]; World_Tile asset = game->world->tileTypes[editor.currentAsset];
D_Rect(&game->draw, tilex, tiley, .texture=D_ImageHandle(&game->draw, asset.tag), .angle=asset.rotation); D_Rect(&game->draw, tilex, tiley, .texture=asset.tile, .angle=asset.rotation);
break; break;
} }
case G_EDITOR_MODE_PROP: { case G_EDITOR_MODE_PROP: {
World_PropType prop = game->world->propTypes[editor.currentAsset]; World_PropType prop = game->world->propTypes[editor.currentAsset];
D_Rect(&game->draw, editor.cursor.x, editor.cursor.y, .texture=D_ImageHandle(&game->draw, prop.tag), .scale=prop.scale); D_Rect(&game->draw, editor.cursor.x, editor.cursor.y, .texture=prop.assetHandle, .scale=prop.scale);
break; break;
} }
case G_EDITOR_MODE_HITBOX: { case G_EDITOR_MODE_HITBOX: {
for(int i = 0; i < game->world->hitboxCount; i++) { for(int i = 0; i < game->world->hitboxCount; i++) {
V2f centre = AABB_Centre(game->world->hitboxes[i]); V2f centre = AABB_Centre(game->world->hitboxes[i]);
D_Rect( D_Rect(&game->draw, centre.x, centre.y, .texture=0, .dim=game->world->hitboxes[i].size, .flags=D_RECT_IGNORE_ASPECT);
&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; break;
} }

View File

@@ -14,5 +14,6 @@ function bool AABB_Collide(AABB a, AABB b);
function bool AABB_Point(AABB a, V2f v); function bool AABB_Point(AABB a, V2f v);
function bool AABB_Slab(V2f origin, V2f point, AABB a); function bool AABB_Slab(V2f origin, V2f point, AABB a);
function V2f AABB_Centre(AABB a); function V2f AABB_Centre(AABB a);
function bool AABB_Circle(F32 rad, V2f radOrigin, AABB a);
#endif // LD_GAME_AABB_H_ #endif // LD_GAME_AABB_H_

View File

@@ -2,11 +2,13 @@
#define LD_GAME_BANDIT_H_ #define LD_GAME_BANDIT_H_
typedef enum BANDIT_ACTION BANDIT_ACTION; typedef enum BANDIT_ACTION BANDIT_ACTION;
enum BANDIT_ACTION { enum BANDIT_ACTION
{
BANDIT_WAITING, BANDIT_WAITING,
BANDIT_WALKING, BANDIT_WALKING,
BANDIT_RUNNING, BANDIT_RUNNING,
BANDIT_SHOOTING, BANDIT_SHOOTING,
BANDIT_SHOOTOUT,
}; };
typedef struct Bandit Bandit; typedef struct Bandit Bandit;
@@ -50,12 +52,18 @@ struct Bandit {
F32 shootDelay; F32 shootDelay;
// After each shot this is set to shootDelay; // After each shot this is set to shootDelay;
F32 shootCooldownTimer; F32 shootCooldownTimer;
// Countdown to shootout
F32 shootoutTimer;
// How long it takes them to reload. // How long it takes them to reload.
F32 reloadTime; F32 reloadTime;
// When gun is empty this is set to reloadTime.
F32 reloadTimer;
// Accuracy, their shots can vary between this angle either side (rads) // Accuracy, their shots can vary between this angle either side (rads)
F32 accuracyRange; F32 accuracyRange;
// A the circle around the bandit where they will trigger the quicktime reaction scene // A the circle around the bandit where they will trigger the quicktime reaction scene
F32 agroRadius; F32 agroRadius;
}; };
function V2f shootTowards(Bandit* bandit, V2f target, Random* r);
#endif // LD_GAME_BANDIT_H_ #endif // LD_GAME_BANDIT_H_

View File

@@ -38,3 +38,11 @@ bool AABB_Slab(V2f origin, V2f point, AABB a)
V2f AABB_Centre(AABB a) { V2f AABB_Centre(AABB a) {
return V2F(a.pos.x + a.size.x/2, a.pos.y + a.size.y/2); 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;
}

View File

@@ -1,13 +1,27 @@
#include "game/world.h" #include "game/world.h"
#include "game/bandit.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) { void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
if ( if (
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea) world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea)
{ {
printf("You shot the bandit %*.s\n", Sv(bandit->name)); printf("You shot the bandit %*.s\n", Sv(bandit->name));
bandit->health--; 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) { switch (bandit->mode) {
case BANDIT_WAITING: case BANDIT_WAITING:
bandit->waitTime+=delta; bandit->waitTime+=delta;
@@ -41,7 +55,33 @@ 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.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; bandit->collision.pos.y = cNav.pos.y * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.y * bandit->walkTimer/NPC_SPEED;
break; break;
// TODO Shooting 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 Running away // TODO Running away
} }
} }

View File

@@ -53,6 +53,10 @@ void PlayerInput(SDL_Event *event, Player *player)
void PlayerUpdate(F32 delta, Player *player) { void PlayerUpdate(F32 delta, Player *player) {
player->controls.shot = false; player->controls.shot = false;
V2f dir = V2F(0, 0); V2f dir = V2F(0, 0);
if(player->health == 0){
printf("dead :(");
player->health = 3;
}
if(player->controls.upDown) { if(player->controls.upDown) {
dir.y -= 1; dir.y -= 1;
} }
@@ -73,6 +77,6 @@ void PlayerUpdate(F32 delta, Player *player) {
} }
} }
dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta); dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta);
player->pos.x += dir.x; player->collision.pos.x += dir.x;
player->pos.y += dir.y; player->collision.pos.y += dir.y;
} }

View File

@@ -9,6 +9,9 @@
void UpdateWorld(F32 delta, World *world) void UpdateWorld(F32 delta, World *world)
{ {
if(world->bandit.mode == BANDIT_SHOOTOUT){
delta = delta/4;
}
UpdateBandit(delta, &world->bandit, world); UpdateBandit(delta, &world->bandit, world);
UpdateNPCs(delta, world); UpdateNPCs(delta, world);
PlayerUpdate(delta, &world->player); PlayerUpdate(delta, &world->player);
@@ -21,7 +24,7 @@ void UpdateNPCs(F32 delta, World *world)
NPC *npc = &world->npcs[i]; NPC *npc = &world->npcs[i];
UpdateNPC(delta, npc, world); UpdateNPC(delta, npc, world);
if ( if (
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea) world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea)
{ {
printf("You shot %*.s\n", Sv(world->npcs[i].name)); printf("You shot %*.s\n", Sv(world->npcs[i].name));
} }
@@ -34,9 +37,6 @@ void ProcessEvents(SDL_Event *event, World *world)
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){ if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){
SaveWorld(world->arena, world); 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) { void RenderWorld(World *world, D_Context *draw) {
@@ -45,7 +45,7 @@ void RenderWorld(World *world, D_Context *draw) {
D_Rect( D_Rect(
draw, draw,
(F32) (i % 96), (F32) (i / 96), (F32) (i % 96), (F32) (i / 96),
.texture = D_ImageHandle(draw,world->tileTypes[world->map[i]].tag), .texture = world->tileTypes[world->map[i]].tile,
.angle = (F32) world->tileTypes[world->map[i]].rotation, .angle = (F32) world->tileTypes[world->map[i]].rotation,
); );
} }
@@ -56,21 +56,11 @@ void RenderWorld(World *world, D_Context *draw) {
draw, draw,
world->props[i].pos.x, world->props[i].pos.x,
world->props[i].pos.y, world->props[i].pos.y,
.texture = D_ImageHandle(draw,world->propTypes[world->props[i].propType].tag), .texture = world->propTypes[world->props[i].propType].assetHandle,
.scale = world->propTypes[world->props[i].propType].scale, .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++) { for(U32 i = 0; i < world->npcCount; i++) {
NPC npc = world->npcs[i]; NPC npc = world->npcs[i];
if(npc.currentArea == world->player.currentArea) { if(npc.currentArea == world->player.currentArea) {
@@ -82,129 +72,29 @@ void RenderWorld(World *world, D_Context *draw) {
V2f drawPos = AABB_Centre(world->bandit.collision); V2f drawPos = AABB_Centre(world->bandit.collision);
D_Rect(draw, drawPos.x, drawPos.y, .texture = 9); D_Rect(draw, drawPos.x, drawPos.y, .texture = 9);
} }
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1); D_Rect(draw, world->player.collision.pos.x, world->player.collision.pos.y, .texture = 1);
} }
void SaveWorld(M_Arena *arena, World *world) { void SaveWorld(M_Arena *arena, World *world) {
printf("Saving world\n"); printf("Saving world\n");
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE); OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE);
U32 offset = 0; FS_FileWrite(file, world, sizeof(World)+sizeof(NavMesh), 0);
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) { FS_FileWrite(file, world->navMesh, sizeof(World)+sizeof(NavMesh), sizeof(World));
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); FS_FileClose(file);
printf("Saved world :)\n"); printf("Saved world :)\n");
} }
void LoadWorld(M_Arena *arena, World *world) { World *LoadWorld(M_Arena *arena) {
printf("loading world\n"); printf("loading world\n");
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_READ); OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_READ);
U32 offset = 0; World *world = M_ArenaPush(arena, World);
NavMesh *navMesh = M_ArenaPush(arena, NavMesh);
world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX); FS_FileRead(file, world, sizeof(World), 0);
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) { FS_FileRead(file, navMesh, sizeof(NavMesh), sizeof(World));
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); FS_FileClose(file);
world->navMesh = navMesh;
world->arena = arena;
world->player.world = world;
printf("loaded world\n"); 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++;
}
} }

View File

@@ -6,7 +6,7 @@
#define NAV_MAX_PATH 1024 #define NAV_MAX_PATH 1024
#define NAV_MAX_CONNECTIONS 8 #define NAV_MAX_CONNECTIONS 8
#define NAV_MAX_NODES 4800 #define NAV_MAX_NODES 4096
typedef struct NavNode NavNode; typedef struct NavNode NavNode;

View File

@@ -5,6 +5,7 @@
#include "../core/macros.h" #include "../core/macros.h"
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include "aabb.h"
#define PLAYER_SPEED 10.0f #define PLAYER_SPEED 10.0f
#define PLAYER_RELOAD_TIME 1.5f #define PLAYER_RELOAD_TIME 1.5f
@@ -23,12 +24,12 @@ typedef struct Player Player;
struct Player struct Player
{ {
World *world; World *world;
V2f pos; AABB collision;
World_Area currentArea; World_Area currentArea;
U32 bulletsLoaded; U32 bulletsLoaded;
ControlState controls; ControlState controls;
V2f shotPos; V2f shotPos;
U32 health;
F32 reloadTimer; F32 reloadTimer;
}; };

35012
code/game/testnavmesh.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,12 +3,6 @@
#include "../core/math.h" #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 // Areas are which
typedef U32 World_Area; typedef U32 World_Area;
enum World_Area enum World_Area
@@ -19,13 +13,14 @@ enum World_Area
typedef struct World_Tile World_Tile; typedef struct World_Tile World_Tile;
struct World_Tile { struct World_Tile {
Str8 tag; U32 tile;
F32 rotation; double rotation;
bool collision;
}; };
typedef struct World_PropType World_PropType; typedef struct World_PropType World_PropType;
struct World_PropType { struct World_PropType {
Str8 tag; U32 assetHandle;
F32 scale; F32 scale;
}; };
@@ -49,15 +44,14 @@ struct World {
NavMesh *navMesh; NavMesh *navMesh;
Random random; Random random;
V2f mouseProjected; V2f mouseProjected;
//// Loaded from world file World_Tile tileTypes[64];
World_Tile *tileTypes; U32 map[4800];
World_PropType *propTypes;
World_Prop *props;
AABB *hitboxes;
U32 *map;
World_PropType propTypes[64];
U32 propCount; U32 propCount;
World_Prop props[256];
U32 hitboxCount; U32 hitboxCount;
AABB hitboxes[4096];
//// Player //// Player
Player player; Player player;
@@ -81,8 +75,7 @@ function void UpdateNPCs(F32 delta, World *world);
function void UpdateNPC(F32 delta, NPC *npc, World *world); function void UpdateNPC(F32 delta, NPC *npc, World *world);
function void UpdateBandit(F32 delta, Bandit *bandit, World *world); function void UpdateBandit(F32 delta, Bandit *bandit, World *world);
function void LoadWorld(M_Arena *arena, World *world); function World *LoadWorld(M_Arena *arena);
function void SaveWorld(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_ #endif // LD_GAME_WORLD_H_

Binary file not shown.