feat: Initial bandit roaming

This commit is contained in:
2025-10-05 21:05:29 +01:00
parent b8f47b8f61
commit 635e7b1c1e
8 changed files with 104 additions and 23 deletions

View File

@@ -18,6 +18,7 @@
#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)
@@ -66,13 +67,13 @@ int main(int argc, char **argv)
World *world = M_ArenaPush(arena, World);
game->world = world;
world->random = Random_Seed(29237489723847);
world->npcCount = 100;
world->npcCount = 1;
for(int i = 0; i < world->npcCount; i++) {
NPC *npc1 = &world->npcs[i];
npc1->collision.pos.x = 15;
npc1->collision.pos.y = 15;
npc1->collision.size.x = 10;
npc1->collision.size.y = 10;
npc1->collision.size.x = 1;
npc1->collision.size.y = 1;
npc1->name = S("Matt");
npc1->mode = NPC_ACTION_WAITING;
npc1->waitTime = 0;
@@ -84,21 +85,25 @@ int main(int argc, char **argv)
npc1->collision.size.y = 10;
}
NPC *npc2 = &world->npcs[1];
npc2->collision.pos.x = 15;
npc2->collision.pos.y = 15;
npc2->collision.size.x = 10;
npc2->collision.size.y = 10;
npc2->name = S("James");
npc2->mode = NPC_ACTION_WAITING;
npc2->waitTime = 0;
npc2->maxWaitTime = 10;
npc2->currentNavNode = 0;
Bandit *badman = &world->bandit;
badman->collision.pos.x = 15;
badman->collision.pos.y = 15;
badman->collision.size.x = 10;
badman->collision.size.y = 10;
badman->name = S("Leroy Brown");
badman->mode = BANDIT_WAITING;
badman->waitTime = 0;
badman->maxWaitTime = 2;
badman->poiCount = 2;
badman->pointsOfInterest[0] = 937;
badman->pointsOfInterest[1] = 12;
world->navMesh = &TestNavMesh;
world->npcPOI[0] = 100;
world->player.pos.x = 0;
world->player.pos.y = 0;
world->player.bulletsLoaded = PLAYER_BULLET_COUNT;
world->player.reloadTimer = 0;
}
bool running = true;

View File

@@ -6,7 +6,7 @@ enum BANDIT_ACTION {
BANDIT_WAITING,
BANDIT_WALKING,
BANDIT_RUNNING,
BANDIT_SHOOTOUT,
BANDIT_SHOOTING,
};
typedef struct Bandit Bandit;
@@ -22,6 +22,7 @@ struct Bandit {
// How long they will wait in this location.
F32 maxWaitTime;
U32 poiCount;
// Places the bandit walks to / from
// E.g. hide outs, home, saloon
U32 pointsOfInterest[12];

41
code/game/impl/bandit.c Normal file
View File

@@ -0,0 +1,41 @@
#include "game/world.h"
#include "game/bandit.h"
void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
switch (bandit->mode) {
case BANDIT_WAITING:
bandit->waitTime+=delta;
if(bandit->waitTime > bandit->maxWaitTime) {
bandit->mode = BANDIT_WALKING;
do {
U32 randomChoice = Random_U32(&world->random, 0, bandit->poiCount);
bandit->targetNavNode = bandit->pointsOfInterest[randomChoice];
} while(bandit->targetNavNode == bandit->currentNavNode);
bandit->path = Nav_Path(world->navMesh, bandit->currentNavNode, bandit->targetNavNode);
bandit->walkTimer = 0;
}
break;
case BANDIT_WALKING:
bandit->walkTimer+=delta;
if(bandit->walkTimer >= NPC_SPEED){
bandit->walkTimer = 0;
if(bandit->path.nodeCount == bandit->pathIndex+1){
bandit->mode = BANDIT_WAITING;
bandit->maxWaitTime = Random_F32(&world->random, 20, 140);
bandit->waitTime = 0;
bandit->currentNavNode = bandit->targetNavNode;
bandit->pathIndex = 0;
return;
}
bandit->currentNavNode = bandit->path.indexes[bandit->pathIndex];
bandit->pathIndex+=1;
}
NavNode cNav = world->navMesh->nodes[bandit->currentNavNode];
NavNode tNav = world->navMesh->nodes[bandit->path.indexes[bandit->pathIndex]];
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;
// TODO Shooting
// TODO Running away
}
}

View File

@@ -3,7 +3,7 @@
#include "core/types.h"
#include "core/math.h"
void updateNPC(F32 delta, NPC *npc, World *world) {
void UpdateNPC(F32 delta, NPC *npc, World *world) {
switch (npc->mode) {
case NPC_ACTION_WAITING:
npc->waitTime+=delta;

View File

@@ -1,9 +1,11 @@
#include "../player.h"
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keycode.h>
#include <stdio.h>
void PlayerInput(SDL_Event *event, Player *player)
{
player->controls.shot = false;
SDL_KeyboardEvent key = event->key;
SDL_MouseButtonEvent mouseBtn = event->button;
if(event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
@@ -32,11 +34,21 @@ void PlayerInput(SDL_Event *event, Player *player)
}
}
}
if (mouseBtn.clicks == 1)
{
// shooting
player->bulletsLoaded -= 1;
}
if (
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN
&& mouseBtn.button == SDL_BUTTON_LEFT
) {
if(player->bulletsLoaded > 0) {
// shooting
player->bulletsLoaded -= 1;
player->controls.shot = true;
player->shotPos = V2F(mouseBtn.x, mouseBtn.y);
printf("shot %f %f\n", mouseBtn.x, mouseBtn.y);
} else if(player->reloadTimer == 0) {
player->reloadTimer = PLAYER_RELOAD_TIME;
printf("reloading\n");
};
}
}
void PlayerUpdate(F32 delta, Player *player) {
@@ -53,6 +65,13 @@ void PlayerUpdate(F32 delta, Player *player) {
if(player->controls.rightDown) {
dir.x += 1;
}
if(player->reloadTimer > 0) {
player->reloadTimer-=delta;
if(player->reloadTimer <= 0) {
player->bulletsLoaded = PLAYER_BULLET_COUNT;
player->reloadTimer = 0;
}
}
dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta);
player->pos.x += dir.x;
player->pos.y += dir.y;

View File

@@ -5,6 +5,7 @@
void UpdateWorld(F32 delta, World *world)
{
UpdateBandit(delta, &world->bandit, world);
UpdateNPCs(delta, world);
PlayerUpdate(delta, &world->player);
}
@@ -13,7 +14,11 @@ void UpdateNPCs(F32 delta, World *world)
{
for (U32 i = 0; i < world->npcCount; i++)
{
updateNPC(delta, &world->npcs[i], world);
UpdateNPC(delta, &world->npcs[i], world);
if(world->player.controls.shot && AABB_Point(world->npcs[i].collision, world->player.shotPos)) {
// TODO we need to unproject the mouse location !!!
printf("You shot %.*s\n", Sv(world->npcs[i].name));
}
}
}
@@ -24,7 +29,10 @@ void ProcessEvents(SDL_Event *event, World *world)
void RenderWorld(World *world, D_Context *draw) {
for(int i = 0; i < world->npcCount; i++) {
D_Rect(draw, world->npcs[i].collision.pos.x, world->npcs[i].collision.pos.y, .texture = 1);
NPC npc = world->npcs[i];
D_Rect(draw, npc.collision.pos.x, npc.collision.pos.y, .texture = 1);
D_Rect(draw, npc.collision.pos.x, npc.collision.pos.y, .texture = 0, .dim = npc.collision.size);
}
D_Rect(draw, world->bandit.collision.pos.x, world->bandit.collision.pos.y, .texture = 9);
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1);
}

View File

@@ -7,6 +7,8 @@
#include <SDL3/SDL_events.h>
#define PLAYER_SPEED 10.0f
#define PLAYER_RELOAD_TIME 1.5f
#define PLAYER_BULLET_COUNT 6
typedef struct ControlState ControlState;
struct ControlState {
@@ -14,6 +16,7 @@ struct ControlState {
bool leftDown;
bool upDown;
bool downDown;
bool shot;
};
typedef struct Player Player;
@@ -22,6 +25,9 @@ struct Player
V2f pos;
U32 bulletsLoaded;
ControlState controls;
V2f shotPos;
F32 reloadTimer;
};
function void PlayerInput(SDL_Event *event, Player *player);

View File

@@ -38,6 +38,7 @@ function void UpdateWorld(F32 delta, World *world);
function void RenderWorld(World *world, D_Context *drawContext );
function void ProcessEvents(SDL_Event *event, World *world);
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);
#endif // LD_GAME_WORLD_H_