From e01edd3c8327be32649e663cf5512e09151dfd02 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 27 Jan 2025 00:39:53 +0100 Subject: [PATCH] feat: removed box collision too much work for this project --- src/core/collidable_node.cpp | 21 +------- src/core/collidable_node.hpp | 4 -- src/core/collision.cpp | 14 ++--- src/core/collision.hpp | 2 +- src/core/collision_shape.cpp | 100 ++++++++++++----------------------- src/core/collision_shape.hpp | 31 ++++------- 6 files changed, 54 insertions(+), 118 deletions(-) diff --git a/src/core/collidable_node.cpp b/src/core/collidable_node.cpp index b2beab3..a20faf4 100644 --- a/src/core/collidable_node.cpp +++ b/src/core/collidable_node.cpp @@ -1,5 +1,6 @@ #include "collidable_node.hpp" #include "collision_shape.hpp" +#include namespace ce { CollidableNode::CollidableNode(std::string const &name, CollisionMask layers, CollisionMask mask) @@ -8,26 +9,8 @@ CollidableNode::CollidableNode(std::string const &name, CollisionMask layers, Co this->mask = mask; } -void CollidableNode::_tick(double const &delta) { - // find nodes that were overlapping last frame but not this frame - std::map::iterator iterator{this->overlapped_nodes.begin()}; - while(iterator != this->overlapped_nodes.end()) { - std::pair pair{*iterator}; - if(pair.second == 0) { - this->overlap_exit.invoke(pair.first); - this->overlapped_nodes.erase(iterator); - iterator = this->overlapped_nodes.begin(); - } - } - this->shape_overlaps.clear(); -} - void CollidableNode::add_overlap(CollisionShape *shape, CollisionShape *other_shape) { - if(this->overlapped_nodes.count(other_shape->get_owner()) != 0) { - this->overlap_enter.invoke(shape, other_shape->get_owner(), other_shape); - } - this->shape_overlaps.insert(other_shape); - ++this->overlapped_nodes[other_shape->get_owner()]; + this->overlap_enter.invoke(shape, other_shape->get_owner(), other_shape); } void CollidableNode::set_mask(CollisionMask mask) { diff --git a/src/core/collidable_node.hpp b/src/core/collidable_node.hpp index 6fc81a6..a5695a9 100644 --- a/src/core/collidable_node.hpp +++ b/src/core/collidable_node.hpp @@ -11,17 +11,13 @@ typedef uint64_t CollisionMask; class CollisionShape; class CollidableNode : public Node2D { - std::set shape_overlaps{}; - std::map overlapped_nodes{}; CollisionMask mask{~0x0u /* all layers by default */}; CollisionMask layers{0x1u /* only the first layer is enabled by default */}; public: // collision(local_shape, other_node, other_shape) Signal overlap_enter{}; - Signal overlap_exit{}; public: CollidableNode(std::string const &name, CollisionMask layers, CollisionMask mask); - virtual void _tick(double const &delta) override; void add_overlap(CollisionShape *shape, CollisionShape *other); void set_mask(CollisionMask mask); diff --git a/src/core/collision.cpp b/src/core/collision.cpp index b256b92..a76de27 100644 --- a/src/core/collision.cpp +++ b/src/core/collision.cpp @@ -10,6 +10,7 @@ void CollisionWorld::add_collision_shape(CollisionShape *shape) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Invalid attempt to add nullptr as collision shape to collision system"); return; } + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "adding collision shape %s", shape->get_name().c_str()); std::vector::iterator found{std::find(this->shapes.begin(), this->shapes.end(), shape)}; if(found != this->shapes.end()) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Attempted to add shape that is already in collision system."); @@ -19,6 +20,7 @@ void CollisionWorld::add_collision_shape(CollisionShape *shape) { } void CollisionWorld::remove_collision_shape(CollisionShape *shape) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "removing collision shape %s", shape->get_name().c_str()); std::vector::iterator found{std::find(this->shapes.begin(), this->shapes.end(), shape)}; if(found == this->shapes.end()) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Attempted to remove shape that is not in collision system"); @@ -28,17 +30,17 @@ void CollisionWorld::remove_collision_shape(CollisionShape *shape) { } void CollisionWorld::check_collisions() { - for(std::vector::iterator iter{this->shapes.begin()}; iter != this->shapes.end();) { - CollisionShape *shape{*iter}; - this->check_collisions_for(shape, ++iter); + for(int i{0}; i < this->shapes.size(); ++i) { + CollisionShape *shape{this->shapes[i]}; + this->check_collisions_for(shape, i); } } -void CollisionWorld::check_collisions_for(CollisionShape *shape, std::vector::iterator begin) { +void CollisionWorld::check_collisions_for(CollisionShape *shape, size_t begin) { // check all shapes *after* this one in the shapes list. // (As the shapes *before* have already been checked, guaranteeing that each pair will only be checked once) - for(std::vector::iterator iter{begin}; iter != this->shapes.end(); ++iter) { - CollisionShape *other{*iter}; + for(size_t i{begin+1}; i < this->shapes.size(); ++i) { + CollisionShape *other{this->shapes[i]}; if(other != shape && other->get_owner() != shape->get_owner() && CollisionShape::shapes_overlap(shape, other)) { if((shape->get_mask() & other->get_layers()) != 0x0u) shape->get_owner()->add_overlap(shape, other); diff --git a/src/core/collision.hpp b/src/core/collision.hpp index 6d74e31..3719b66 100644 --- a/src/core/collision.hpp +++ b/src/core/collision.hpp @@ -13,7 +13,7 @@ public: void remove_collision_shape(CollisionShape *shape); void check_collisions(); private: - void check_collisions_for(CollisionShape *shape, std::vector::iterator begin); + void check_collisions_for(CollisionShape *shape, size_t begin); }; } diff --git a/src/core/collision_shape.cpp b/src/core/collision_shape.cpp index 3b96849..0ff62bb 100644 --- a/src/core/collision_shape.cpp +++ b/src/core/collision_shape.cpp @@ -2,32 +2,14 @@ #include "collidable_node.hpp" #include "core/canvas_engine.hpp" #include -#include +#include namespace ce { -Shape Shape::make_circle(float radius) { - return Shape { - .shape=Shape::CIRCLE, - .circle={ - .radius=radius - } - }; -} - -Shape Shape::make_box(float h_extent, float v_extent) { - return Shape { - .shape=Shape::AABB, - .box={ - .h_extent=h_extent, - .v_extent=v_extent - } - }; -} - -CollisionShape::CollisionShape(std::string const &name, Shape shape) +CollisionShape::CollisionShape(std::string const &name, float radius, float bounce) : Node2D(name) , world{CanvasEngine::get_singleton()->get_collision_world()} -, shape{shape} {} +, radius{radius} +, bounce{bounce} {} void CollisionShape::_added() { this->ce::Node2D::_added(); @@ -57,6 +39,22 @@ void CollisionShape::_removed() { } } +void CollisionShape::_draw(SDL_Renderer *render, ce::Transform const &view_transform) { + static const size_t points_c{17}; + SDL_FPoint points[points_c]; + Vecf point{this->radius, 0.f}; + for(size_t i{0}; i < points_c-1; ++i) { + points[i] = ((point + .rotated(float(i)/float(points_c-1) * M_PI * 2.f) + + this->get_global_transform().position + ).scaled(view_transform.scale) + + view_transform.position + ).operator SDL_FPoint(); + } + points[points_c-1] = points[0]; + SDL_RenderDrawLinesF(render, points, points_c); +} + bool CollisionShape::can_collide(CollisionShape const *lhs, CollisionShape const *rhs) { return lhs->owner != nullptr && rhs->owner != nullptr && lhs->owner != rhs->owner @@ -65,58 +63,24 @@ bool CollisionShape::can_collide(CollisionShape const *lhs, CollisionShape const } bool CollisionShape::shapes_overlap(CollisionShape const *lhs, CollisionShape const *rhs) { - if(!can_collide(lhs, rhs)) - return false; - Shape const &lshape{lhs->get_shape()}; - Shape const &rshape{rhs->get_shape()}; - Transform const &lhst{lhs->get_global_transform()}; - Transform const &rhst{rhs->get_global_transform()}; - if(lhs->shape.shape == Shape::CIRCLE) { - return rhs->shape.shape == Shape::CIRCLE - ? overlap_circle_circle(lshape.circle, lhst, rshape.circle, rhst) - : overlap_circle_aabb(lshape.circle, lhst, rshape.box, rhst); - } else if(lhs->shape.shape == Shape::AABB) { - return rhs->shape.shape == Shape::AABB - ? overlap_aabb_aabb(lshape.box, lhst, rshape.box, rhst) - : overlap_circle_aabb(lshape.circle, lhst, rshape.box, rhst); - } else { - SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Attempt to compare shapes with a shape that is not of a valid shape. This should never happen."); - #ifdef DEBUG - abort(); - #endif - return false; - } + float const rad_sum{lhs->radius + rhs->radius}; + return (lhs->get_global_transform().position - rhs->get_global_transform().position).sqr_magnitude() < rad_sum * rad_sum; } -bool CollisionShape::overlap_circle_circle(ShapeCircle lhs, Transform lhst, ShapeCircle rhs, Transform rhst) { - float const min_dist{lhs.radius + rhs.radius}; - return Vecf::sqr_distance(lhst.position, rhst.position) <= min_dist * min_dist; -} - -bool CollisionShape::overlap_circle_aabb(ShapeCircle lhs, Transform lhst, ShapeAABB rhs, Transform rhst) { - Vecf const closest{ - std::clamp(lhst.position.x, rhst.position.x - rhs.h_extent, rhst.position.x + rhs.h_extent), - std::clamp(lhst.position.y, rhst.position.y - rhs.v_extent, rhst.position.y + rhs.v_extent) - }; - return Vecf::sqr_distance(lhst.position, closest) <= lhs.radius * lhs.radius; -} - -bool CollisionShape::overlap_aabb_aabb(ShapeAABB lhs, Transform lhst, ShapeAABB rhs, Transform rhst) { - ce::Vecf const diff{lhst.position - rhst.position}; - return std::abs(diff.x) <= (lhs.h_extent + rhs.h_extent) - && std::abs(diff.y) <= (lhs.v_extent + rhs.v_extent); +Vecf CollisionShape::get_escape_vector(CollisionShape const *lhs, CollisionShape const *rhs) { + Vecf const difference{lhs->get_global_transform().position - rhs->get_global_transform().position}; + float const diff_mag{difference.magnitude()}; + return diff_mag < (lhs->radius + rhs->radius) + ? (difference / diff_mag) * (lhs->radius + rhs->radius - diff_mag) + : Vecf::ZERO; } CollidableNode *CollisionShape::get_owner() const { return this->owner; } -void CollisionShape::set_shape(Shape const &shape) { - this->shape = shape; -} - -Shape const &CollisionShape::get_shape() const { - return this->shape; +float CollisionShape::get_radius() const { + return this->radius; } CollisionMask CollisionShape::get_layers() const { @@ -127,6 +91,10 @@ CollisionMask CollisionShape::get_mask() const { return this->owner ? this->owner->get_mask() : 0x0u; } +float CollisionShape::get_bounce() const { + return this->bounce; +} + void CollisionShape::register_with_world() { this->world.add_collision_shape(this); this->is_registered = true; diff --git a/src/core/collision_shape.hpp b/src/core/collision_shape.hpp index 80c80b1..8dd25c2 100644 --- a/src/core/collision_shape.hpp +++ b/src/core/collision_shape.hpp @@ -8,43 +8,30 @@ namespace ce { class CollisionWorld; -struct ShapeCircle { float radius; }; -struct ShapeAABB { float h_extent, v_extent; }; - -struct Shape { - enum ShapeType { CIRCLE, AABB }; - static Shape make_circle(float radius); - static Shape make_box(float h_extent, float v_extent); - - ShapeType shape; - union { - ShapeCircle circle; - ShapeAABB box; - }; -}; - class CollisionShape : public Node2D { CollidableNode *owner{nullptr}; - Shape shape{.shape=Shape::CIRCLE, .circle={.radius=1.f}}; + float radius; CollisionWorld &world; bool is_registered{false}; + float bounce{0.5f}; public: - CollisionShape(std::string const &name, Shape shape); + CollisionShape(std::string const &name, float radius, float bounce); virtual void _added() override; virtual void _removed() override; + virtual void _draw(SDL_Renderer *render, ce::Transform const &view_transform) override; static bool can_collide(CollisionShape const *lhs, CollisionShape const *rhs); static bool shapes_overlap(CollisionShape const *lhs, CollisionShape const *rhs); - static bool overlap_circle_circle(ShapeCircle lhs, Transform lhst, ShapeCircle rhs, Transform rhst); - static bool overlap_circle_aabb(ShapeCircle lhs, Transform lhst, ShapeAABB rhs, Transform rhst); - static bool overlap_aabb_aabb(ShapeAABB lhs, Transform lhst, ShapeAABB rhs, Transform rhst); + + static Vecf get_escape_vector(CollisionShape const *lhs, CollisionShape const *rhs); + CollidableNode *get_owner() const; - void set_shape(Shape const &shape); - Shape const &get_shape() const; + float get_radius() const; CollisionMask get_layers() const; CollisionMask get_mask() const; + float get_bounce() const; private: void register_with_world(); void deregister_with_world();