diff --git a/Component_Physics.c b/Component_Physics.c index 54d08b5..8bfb826 100644 --- a/Component_Physics.c +++ b/Component_Physics.c @@ -12,6 +12,18 @@ double physics_Gravity = 5.0; +Box2 physics_HitboxAbsolute(Component_Hitbox *hitbox) { + Entity *super = hitbox->super; + if (!super->position) + return hitbox->box; + else { + Box2 box = hitbox->box; + box.lefttop = vec2_Add(box.lefttop, super->position->position); + return box; + } +} + + System_Physics *physics_NewSystem() { System_Physics *sys = malloc(sizeof(System_Physics)); @@ -43,9 +55,13 @@ void physics_DeleteEntity(System_Physics *sys, uintptr_t id) { } -inline void _physics_AdvanceEntity(Entity *e, Duration deltaTime) { - if (!e->position) - return; +// Defined in Physics_Move.c +void _physics_MoveX(System_Physics *sys, Entity *e, Duration deltaTime); +void _physics_MoveY(System_Physics *sys, Entity *e, Duration deltaTime); + + +inline void _physics_AdvanceEntity(System_Physics *sys, Entity *e, Duration deltaTime) { + ASSERT(e->position && "_physics_AdvanceEntity() called on entity with no position"); // Short path if (!e->hitbox || e->hitbox->fixed) { @@ -59,6 +75,8 @@ inline void _physics_AdvanceEntity(Entity *e, Duration deltaTime) { } // Long path + _physics_MoveX(sys, e, deltaTime); + _physics_MoveY(sys, e, deltaTime); } @@ -81,6 +99,6 @@ void physics_Advance(System_Physics *sys, Duration deltaTime) { i != NULL; i = tree_Node_Next(i)) { Component_Position *pos = *((Component_Position **)i->data); - _physics_AdvanceEntity(pos->super, deltaTime); + _physics_AdvanceEntity(sys, pos->super, deltaTime); } } diff --git a/Component_Physics.h b/Component_Physics.h index 8c6028c..f197ff1 100644 --- a/Component_Physics.h +++ b/Component_Physics.h @@ -33,6 +33,9 @@ typedef struct { bool fixed; } Component_Hitbox; +// Returns the absolute version of the hitbox. +Box2 physics_HitboxAbsolute(Component_Hitbox *hitbox); + // Physics manager typedef struct { diff --git a/JacksEscape.vcxproj b/JacksEscape.vcxproj index b72ed88..d27a7cf 100644 --- a/JacksEscape.vcxproj +++ b/JacksEscape.vcxproj @@ -139,6 +139,7 @@ + diff --git a/JacksEscape.vcxproj.filters b/JacksEscape.vcxproj.filters index 4c430f8..34f0bc6 100644 --- a/JacksEscape.vcxproj.filters +++ b/JacksEscape.vcxproj.filters @@ -58,6 +58,9 @@ 源文件 + + + 源文件 diff --git a/Physics_Move.c b/Physics_Move.c new file mode 100644 index 0000000..91aaf51 --- /dev/null +++ b/Physics_Move.c @@ -0,0 +1,79 @@ + +#include "Component_Physics.h" +#include "Entity.h" +#include "Types.h" +#include "util/tree.h" + +#include + + +static const double EPS = 1e-6; + +static inline double dabs(double x) { + return x < 0 ? -x : x; +} + + +void _physics_MoveX(System_Physics *sys, Entity *e, Duration deltaTime) { + double delta = e->position->velocity.x * duration_Seconds(deltaTime); + if (dabs(delta) < EPS) + return; + + for (tree_Node *i = tree_FirstNode(sys->hit); + i != NULL; + i = tree_Node_Next(i)) { + Component_Hitbox *tohit = *((Component_Hitbox **)i->data); + if (!tohit->fixed) + continue; + + if (box2_Intersects(tohit->box, box2_OffsetX(e->hitbox->box, delta), NULL)) { + if (delta > 0) { + // Moves right, hits left edge + double maxdelta = tohit->box.lefttop.x - e->hitbox->box.lefttop.x - e->hitbox->box.size.x; + delta = maxdelta - EPS; + } else { + // Moves left, hits right edge + double maxdelta = tohit->box.lefttop.x - e->hitbox->box.lefttop.x + tohit->box.size.x; + delta = maxdelta + EPS; + } + } + + if (dabs(delta) < EPS) + break; + } + + if (dabs(delta) > EPS) + e->position->position.x += delta; +} + +void _physics_MoveY(System_Physics *sys, Entity *e, Duration deltaTime) { + double delta = e->position->velocity.y * duration_Seconds(deltaTime); + if (dabs(delta) < EPS) + return; + + for (tree_Node *i = tree_FirstNode(sys->hit); + i != NULL; + i = tree_Node_Next(i)) { + Component_Hitbox *tohit = *((Component_Hitbox **)i->data); + if (!tohit->fixed) + continue; + + if (box2_Intersects(tohit->box, box2_OffsetY(e->hitbox->box, delta), NULL)) { + if (delta > 0) { + // Moves down, hits top edge + double maxdelta = tohit->box.lefttop.y - e->hitbox->box.lefttop.y - e->hitbox->box.size.y; + delta = maxdelta - EPS; + } else { + // Moves up, hits bottom edge + double maxdelta = tohit->box.lefttop.y - e->hitbox->box.lefttop.y + tohit->box.size.y; + delta = maxdelta + EPS; + } + } + + if (dabs(delta) < EPS) + break; + } + + if (dabs(delta) > EPS) + e->position->position.y += delta; +} diff --git a/Types.c b/Types.c index 75553b6..f6d19d8 100644 --- a/Types.c +++ b/Types.c @@ -55,3 +55,16 @@ bool box2_Intersects(const Box2 x, const Box2 y, Box2 *out_intersection) { return false; } } + +Box2 box2_Offset(Box2 box, Vec2 offset) { + box.lefttop = vec2_Add(box.lefttop, offset); + return box; +} +Box2 box2_OffsetX(Box2 box, double offsetX) { + box.lefttop.x += offsetX; + return box; +} +Box2 box2_OffsetY(Box2 box, double offsetY) { + box.lefttop.y += offsetY; + return box; +} diff --git a/Types.h b/Types.h index a306d44..8c11316 100644 --- a/Types.h +++ b/Types.h @@ -28,6 +28,10 @@ typedef struct { // Intersection test. bool box2_Intersects(const Box2 x, const Box2 y, Box2 *out_intersection); +Box2 box2_Offset(Box2 box, Vec2 offset); +Box2 box2_OffsetX(Box2 box, double offsetX); +Box2 box2_OffsetY(Box2 box, double offsetY); + typedef struct { uint64_t microseconds;