diff --git a/App.h b/App.h new file mode 100644 index 0000000..9ddb249 --- /dev/null +++ b/App.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Entity.h" +#include "Physics_Component.h" +#include "Player_Component.h" +#include "Input.h" + + +typedef struct _App { + System_Physics *physics; + System_Player *player; + System_Input *input; +} App; diff --git a/Entity.h b/Entity.h index 8b4669c..f61cd18 100644 --- a/Entity.h +++ b/Entity.h @@ -3,6 +3,7 @@ #include #include "util/vector.h" #include "Physics_Component.h" +#include "Player_Component.h" #ifdef __cplusplus @@ -12,13 +13,12 @@ extern "C" { // Entity. typedef struct _Entity { - uintptr_t id; - uintptr_t type; - const char *name; + uintptr_t id; + char *name; Component_Position *position; Component_Hitbox *hitbox; - + Component_Player *player; } Entity; diff --git a/Input.c b/Input.c index ee2a478..00660bf 100644 --- a/Input.c +++ b/Input.c @@ -1,5 +1,6 @@ #include "Input.h" +#include "App.h" #include #include @@ -16,8 +17,9 @@ void input_SetDefaultKeymap(System_Input *sys) { sys->systemKeymap[input_Key_Use] = 'L'; } -System_Input *input_NewSystem() { +System_Input *input_NewSystem(App *super) { System_Input *sys = malloc(sizeof(System_Input)); + sys->super = super; return sys; } diff --git a/Input.h b/Input.h index ed90adf..c30d414 100644 --- a/Input.h +++ b/Input.h @@ -46,7 +46,11 @@ static inline bool input_IsPressed(input_KeyState state) { return state == Press static inline bool input_IsReleased(input_KeyState state) { return state == Released || state == JustReleased; } +typedef struct _App App; + typedef struct { + App *super; + input_KeyState keys[input_Key_Count]; // States of keys unsigned int systemKeymap[input_Key_Count]; // Which system key (VK code) this function uses // https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes @@ -55,7 +59,7 @@ typedef struct { // Creates a new input system. // Uses a default keymap -System_Input *input_NewSystem(); +System_Input *input_NewSystem(App *super); void input_DeleteSystem(System_Input *sys); // Sets the keymaps to default. diff --git a/Physics_Component.c b/Physics_Component.c index 8d876bc..89eff94 100644 --- a/Physics_Component.c +++ b/Physics_Component.c @@ -24,8 +24,9 @@ Box2 physics_HitboxAbsolute(Component_Hitbox *hitbox) { } -System_Physics *physics_NewSystem() { +System_Physics *physics_NewSystem(App *super) { System_Physics *sys = malloc(sizeof(System_Physics)); + sys->super = super; sys->pos = tree_Create(sizeof(uintptr_t)); sys->hit = tree_Create(sizeof(uintptr_t)); diff --git a/Physics_Component.h b/Physics_Component.h index b06356a..362485d 100644 --- a/Physics_Component.h +++ b/Physics_Component.h @@ -27,7 +27,8 @@ typedef struct { // Handler called when hitboxes are hit -typedef void (*physics_HitHandler)(Entity *me, Entity *other, Vec2 triedDelta); +typedef void (*physics_HitHandler)(Entity *me, Entity *other, Vec2 triedDelta, void *data); + // Box is relative to Position if exists // if not, Box is absolute @@ -39,21 +40,25 @@ typedef struct { bool fixed; physics_HitHandler onHit; + void *onHitData; } Component_Hitbox; // Returns the absolute version of the hitbox. Box2 physics_HitboxAbsolute(Component_Hitbox *hitbox); +typedef struct _App App; + // Physics manager typedef struct { + App *super; // Every Position & Hitbox components tree_Tree *pos, *hit; vector_Vector *flaggedDelete; } System_Physics; // Returns an empty physics system. -System_Physics *physics_NewSystem(); +System_Physics *physics_NewSystem(App *super); // Frees a physics system. void physics_DeleteSystem(System_Physics *sys); diff --git a/Physics_Move.c b/Physics_Move.c index 46b60ed..080d158 100644 --- a/Physics_Move.c +++ b/Physics_Move.c @@ -7,15 +7,13 @@ #include -static const double EPS = 1e-6; - static inline double dabs(double x) { return x < 0 ? -x : x; } -static inline void call_hithandler(Entity *me, Entity *other, Vec2 triedDelta) { +static inline void call_hithandler(Entity *me, Entity *other, Vec2 triedDelta, void *data) { if (me->hitbox->onHit) - me->hitbox->onHit(me, other, triedDelta); + me->hitbox->onHit(me, other, triedDelta, data); } @@ -34,7 +32,7 @@ void _physics_MoveX(System_Physics *sys, Entity *e, Duration deltaTime) { continue; if (box2_Intersects(tohit, box2_OffsetX(mybox, delta), NULL)) { - call_hithandler(e, tohit_comp->super, vec2(delta, 0)); + call_hithandler(e, tohit_comp->super, vec2(delta, 0), e->hitbox->onHitData); if (delta > 0) { // Moves right, hits left edge double maxdelta = tohit.lefttop.x - mybox.lefttop.x - mybox.size.x; diff --git a/Player_Component.c b/Player_Component.c new file mode 100644 index 0000000..77e347a --- /dev/null +++ b/Player_Component.c @@ -0,0 +1,80 @@ + +#include "Player_Component.h" +#include "Entity.h" +#include "App.h" +#include "Input.h" + +#include "util/assert.h" +#include + + +static inline double dabs(double x) { + return x < 0.0 ? -x : x; +} + + +System_Player *player_NewSystem(App *super) { + System_Player *sys = malloc(sizeof(System_Player)); + sys->super = super; + return sys; +} +void player_DeleteSystem(System_Player *sys) { + free(sys); +} + +static void _player_OnHit(Entity *me, Entity *other, Vec2 triedDelta, void *data) { + ASSERT(me->player && "_player_OnHit called with ME as non-player"); + // Moving down + if (triedDelta.y > 0) + me->player->onGround = true; +} + + +void player_AddEntity(System_Player *sys, Entity *e) { + if (e->player) { + ASSERT(!sys->player && "Two player entities are added! Did you forget to DeleteEntity for player?"); + sys->player = e->player; + + ASSERT(e->hitbox && "Player does not have Hitbox component"); + e->hitbox->onHit = &_player_OnHit; + } +} +void player_DeleteEntity(System_Player *sys, uintptr_t id) { + if (sys->player && sys->player->super->id == id) + sys->player = NULL; +} + + +static double walkSpeed = 2.0, jumpSpeed = 5.0; +static int airjumpCount = 1; + +void player_Advance(System_Player *sys, Duration deltaTime) { + if (!sys->player) + return; + // The bulk of player logic right here + System_Input *input = sys->super->input; + + double targetVecX = 0.0; + // Move left/right + if (input_IsPressed(input->keys[input_Key_Left])) + targetVecX += -walkSpeed; + if (input_IsPressed(input->keys[input_Key_Right])) + targetVecX += walkSpeed; + + sys->player->super->position->velocity.x = targetVecX; + + if (sys->player->onGround) + sys->player->jumpCount = 0; + + // Jump + if (sys->super->input->keys[input_Key_Jump] == JustPressed) { + if (sys->player->onGround || sys->player->jumpCount < airjumpCount) + sys->player->super->position->velocity.x = jumpSpeed; + if (!sys->player->onGround) // Took the second clause, airjumped + sys->player->jumpCount++; + } + + // Check OnGround again + if (dabs(sys->player->super->position->velocity.y) > EPS) + sys->player->onGround = false; +} diff --git a/Player_Component.h b/Player_Component.h index 90dbcfb..6e0f872 100644 --- a/Player_Component.h +++ b/Player_Component.h @@ -1,5 +1,6 @@ #pragma once +#include "Types.h" #include #include @@ -14,21 +15,36 @@ typedef struct _Entity Entity; // Only one entity should have this. typedef struct { Entity *super; - int jumpCount; // Number of times the player has jumped since leaving ground + + int jumpCount; // Number of times the player has jumped since leaving ground // (Initial jump does not count) bool onGround; // If the player is on the ground? bool moveLeft, moveRight; // If the player is moving left/right? } Component_Player; +typedef struct _App App; + // Player controller instance. // Reads input from the app. typedef struct { + App *super; // The player in the world. // Control is paused if equals NULL. Component_Player *player; } System_Player; +System_Player *player_NewSystem(App *super); +void player_DeleteSystem(System_Player *sys); + +// Adds an entity. +void player_AddEntity(System_Player *sys, Entity *e); +// Deletes an entity. +void player_DeleteEntity(System_Player *sys, uintptr_t id); + +// Called on every frame. +void player_Advance(System_Player *sys, Duration deltaTime); + #ifdef __cplusplus } diff --git a/Types.c b/Types.c index abfa066..5e7413a 100644 --- a/Types.c +++ b/Types.c @@ -9,6 +9,8 @@ static inline double dmax(double x, double y) { return x > y ? x : y; } +const double EPS = 1e-6; + Vec2 vec2_Add(Vec2 x, Vec2 y) { Vec2 result = { diff --git a/Types.h b/Types.h index 122db42..0232303 100644 --- a/Types.h +++ b/Types.h @@ -55,6 +55,9 @@ TimePoint time_Now(); Duration time_Since(TimePoint prev); Duration time_Difference(TimePoint now, TimePoint prev); +// 1e-6 +extern const double EPS; + #ifdef __cplusplus }