From e8f0b0c63a2dcde0bfb2bb6b38415ae8f6381afd Mon Sep 17 00:00:00 2001 From: Edgaru089 Date: Thu, 29 Feb 2024 16:17:55 +0800 Subject: [PATCH] Initial work on physics --- Component_Physics.c | 86 +++++++++++++++++++++++++++++++++++++ Component_Physics.h | 36 +++++++++++++--- Entity.h | 10 +++-- JacksEscape.vcxproj | 3 +- JacksEscape.vcxproj.filters | 5 ++- Types.h | 8 ++++ util/assert.h | 21 +++++++++ util/vector.c | 12 ++++++ util/vector.h | 9 ++++ 9 files changed, 179 insertions(+), 11 deletions(-) create mode 100644 Component_Physics.c create mode 100644 util/assert.h diff --git a/Component_Physics.c b/Component_Physics.c new file mode 100644 index 0000000..54d08b5 --- /dev/null +++ b/Component_Physics.c @@ -0,0 +1,86 @@ + +#include "Component_Physics.h" +#include "Entity.h" +#include "Types.h" +#include "util/tree.h" +#include "util/vector.h" +#include "util/assert.h" + +#include +#include + +double physics_Gravity = 5.0; + + +System_Physics *physics_NewSystem() { + System_Physics *sys = malloc(sizeof(System_Physics)); + + sys->pos = tree_Create(sizeof(uintptr_t)); + sys->hit = tree_Create(sizeof(uintptr_t)); + sys->flaggedDelete = vector_Create(sizeof(uintptr_t)); + + return sys; +} + +void physics_DeleteSystem(System_Physics *sys) { + tree_Destroy(sys->pos); + tree_Destroy(sys->hit); + vector_Destroy(sys->flaggedDelete); +} + + +void physics_AddEntity(System_Physics *sys, Entity *e) { + if (e->position) + memcpy(tree_Insert(sys->pos, e->id, NULL), &e->position, sizeof(uintptr_t)); + if (e->hitbox) { + ASSERT(!e->hitbox->fixed && !e->position && "Entity has non-Fixed Hitbox but no position"); + memcpy(tree_Insert(sys->hit, e->id, NULL), &e->hitbox, sizeof(uintptr_t)); + } +} + +void physics_DeleteEntity(System_Physics *sys, uintptr_t id) { + vector_Push(sys->flaggedDelete, &id); +} + + +inline void _physics_AdvanceEntity(Entity *e, Duration deltaTime) { + if (!e->position) + return; + + // Short path + if (!e->hitbox || e->hitbox->fixed) { + e->position->position = + vec2_Add( + e->position->position, + vec2_Scale( + e->position->velocity, + duration_Seconds(deltaTime))); + return; + } + + // Long path +} + + +void physics_Advance(System_Physics *sys, Duration deltaTime) { + // Delete flagged entities + while (vector_Size(sys->flaggedDelete)) { + uintptr_t id; + vector_Pop(sys->flaggedDelete, &id); + + tree_Node *n; + n = tree_FindNode(sys->pos, id); + if (n) + tree_Delete(sys->pos, n); + n = tree_FindNode(sys->hit, id); + if (n) + tree_Delete(sys->hit, n); + } + + for (tree_Node *i = tree_FirstNode(sys->pos); + i != NULL; + i = tree_Node_Next(i)) { + Component_Position *pos = *((Component_Position **)i->data); + _physics_AdvanceEntity(pos->super, deltaTime); + } +} diff --git a/Component_Physics.h b/Component_Physics.h index c05337e..8c6028c 100644 --- a/Component_Physics.h +++ b/Component_Physics.h @@ -1,5 +1,7 @@ #pragma once +#include "util/tree.h" +#include "util/vector.h" #include "Types.h" #include #include @@ -9,14 +11,15 @@ extern "C" { #endif -typedef struct Entity; -extern double Physics_Gravity; +typedef struct _Entity Entity; + +extern double physics_Gravity; typedef struct { Entity *super; - double x, y; - double vecX, vecY; + Vec2 position; + Vec2 velocity; } Component_Position; @@ -26,11 +29,32 @@ typedef struct { // Moving hitboxes only hits fixed hitboxes typedef struct { Entity *super; - Box2 box; - bool fixed; + Box2 box; + bool fixed; } Component_Hitbox; +// Physics manager +typedef struct { + // Every Position & Hitbox components + tree_Tree *pos, *hit; + vector_Vector *flaggedDelete; +} System_Physics; + +// Returns an empty physics system. +System_Physics *physics_NewSystem(); +// Frees a physics system. +void physics_DeleteSystem(System_Physics *sys); + +// Adds an entity. +void physics_AddEntity(System_Physics *sys, Entity *e); +// Deletes an entity. +void physics_DeleteEntity(System_Physics *sys, uintptr_t id); + +// Advance is called on every frame. +void physics_Advance(System_Physics *sys, Duration deltaTime); + + #ifdef __cplusplus } #endif diff --git a/Entity.h b/Entity.h index f4d9d52..c1b28d8 100644 --- a/Entity.h +++ b/Entity.h @@ -2,6 +2,7 @@ #include #include "util/vector.h" +#include "Component_Physics.h" #ifdef __cplusplus @@ -10,12 +11,15 @@ extern "C" { // Entity. -typedef struct { - uintptr_t type; +typedef struct _Entity { + uintptr_t id; + uintptr_t type; const char *name; -} Entity; + Component_Position *position; + Component_Hitbox *hitbox; +} Entity; #ifdef __cplusplus diff --git a/JacksEscape.vcxproj b/JacksEscape.vcxproj index d5f2d30..b72ed88 100644 --- a/JacksEscape.vcxproj +++ b/JacksEscape.vcxproj @@ -138,6 +138,7 @@ + @@ -145,4 +146,4 @@ - \ No newline at end of file + diff --git a/JacksEscape.vcxproj.filters b/JacksEscape.vcxproj.filters index d714b85..4c430f8 100644 --- a/JacksEscape.vcxproj.filters +++ b/JacksEscape.vcxproj.filters @@ -55,6 +55,9 @@ 源文件 + + + 源文件 - \ No newline at end of file + diff --git a/Types.h b/Types.h index 91a9890..a306d44 100644 --- a/Types.h +++ b/Types.h @@ -29,6 +29,14 @@ typedef struct { bool box2_Intersects(const Box2 x, const Box2 y, Box2 *out_intersection); +typedef struct { + uint64_t microseconds; +} Duration; + +static inline double duration_Seconds(const Duration t) { return ((double)t.microseconds) / 1000.0 / 1000.0; } +static inline double duration_Milliseconds(const Duration t) { return ((double)t.microseconds) / 1000.0; } + + #ifdef __cplusplus } #endif diff --git a/util/assert.h b/util/assert.h new file mode 100644 index 0000000..a0f86ba --- /dev/null +++ b/util/assert.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + + +inline static void __panicf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int ret = vfprintf(stderr, fmt, args); + va_end(args); + abort(); +} + + +#define ASSERT(expr) \ + do { \ + if (!(expr)) \ + __panicf("Assertion failed: " __FILE__ ":%d[%s]\n Expression: %s", __LINE__, __func__, #expr); \ + } while (0) diff --git a/util/vector.c b/util/vector.c index 5ae0b16..e64975a 100644 --- a/util/vector.c +++ b/util/vector.c @@ -36,6 +36,18 @@ void *vector_Push(vector_Vector *vec, const void *data) { return vec->data + vec->size - vec->objectSize; } +bool vector_Pop(vector_Vector *vec, void *out_data) { + if (!vector_Size(vec)) + return false; + + if (out_data) + memcpy(out_data, vec->data + (vec->size - vec->objectSize), vec->objectSize); + + vector_Resize(vec, vector_Size(vec) - 1); + + return true; +} + void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) { uintptr_t oldsize = vec->size, addsize = vec->objectSize * n; vector_Resize(vec, oldsize + addsize); diff --git a/util/vector.h b/util/vector.h index 7a812ca..d59d61f 100644 --- a/util/vector.h +++ b/util/vector.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -27,6 +28,14 @@ void vector_Destroy(vector_Vector *vec); // Returns a pointer to data. void *vector_Push(vector_Vector *vec, const void *data); +// Pop pops one object at the back of the vector. +// +// If out_data is not NULL, the popped data is copied. +// +// If the vector is already empty, return false. +// Returns true otherwise. +bool vector_Pop(vector_Vector *vec, void *out_data); + // Append pushes multiple objects at the back of the buffer. // // If data is NULL, the data is zeroed.