Basic collisions

This commit is contained in:
Jan Mrna 2025-10-10 19:00:08 +02:00
parent 3d34b68133
commit 250f0963c8
6 changed files with 98 additions and 7 deletions

View File

@ -68,6 +68,25 @@ std::optional<WorldPos> Entity::GetMoveTarget()
return {}; return {};
} }
bool Entity::CollidesWith(const Entity& other) const
{
const auto& A = *this;
const auto& B = other;
auto position_A = A.GetPosition();
auto position_B = B.GetPosition();
auto distance_sq = position_A.DistanceSquared(position_B);
auto collision_distance_sq =
A.GetCollisionRadiusSquared() +
B.GetCollisionRadiusSquared() +
2 * A.GetCollisionRadius() * B.GetCollisionRadius();
if (distance_sq < collision_distance_sq)
{
return true;
}
return false;
}
Player::Player() { Player::Player() {
LOG_DEBUG("."); LOG_DEBUG(".");
if (m_Sprite == nullptr) { if (m_Sprite == nullptr) {

View File

@ -63,6 +63,10 @@ public:
void SetPath(pathfinder::Path& path) { m_Path = path; } void SetPath(pathfinder::Path& path) { m_Path = path; }
std::optional<WorldPos> GetMoveTarget(); std::optional<WorldPos> GetMoveTarget();
bool CollidesWith(const Entity& other) const;
bool IsCollisionBoxVisible() const { return m_CollisionBoxVisible; }
protected: protected:
WorldPos m_Position; WorldPos m_Position;
WorldPos m_ActualVelocity; WorldPos m_ActualVelocity;
@ -71,7 +75,7 @@ protected:
private: private:
bool m_FlagExpired = false; bool m_FlagExpired = false;
static constexpr float m_CollisionRadiusSq = 1000.0f; bool m_CollisionBoxVisible = true;
}; };
class Player final : public Entity { class Player final : public Entity {
@ -83,7 +87,7 @@ public:
constexpr Entity::Type GetType() const override { constexpr Entity::Type GetType() const override {
return Entity::Type::PLAYER; return Entity::Type::PLAYER;
} }
constexpr float GetCollisionRadius() const override { return 50.0f; } constexpr float GetCollisionRadius() const override { return 25.0f; }
bool IsMovable() const override { return true; } bool IsMovable() const override { return true; }
bool IsCollidable() const override { return true; } bool IsCollidable() const override { return true; }

View File

@ -43,8 +43,14 @@ void GameLoop::Draw() {
// draw all the entities (player etc) // draw all the entities (player etc)
for (auto &entity : m_Game->GetEntities()) { for (auto &entity : m_Game->GetEntities()) {
const auto &camera = m_Game->GetCamera(); const auto &camera = m_Game->GetCamera();
m_Window->DrawSprite(camera.WorldToWindow(entity->GetPosition()), auto entity_pos_window = camera.WorldToWindow(entity->GetPosition());
entity->GetSprite(), camera.GetZoom()); m_Window->DrawSprite(entity_pos_window,
entity->GetSprite(),
camera.GetZoom());
if (entity->IsCollisionBoxVisible())
{
m_Window->DrawCircle(entity_pos_window, entity->GetCollisionRadius());
}
} }
} }

View File

@ -165,6 +165,12 @@ public:
return (a - b).Length(); return (a - b).Length();
} }
T DistanceSquared(const vec &b) const {
const vec &a = *this;
return (a - b).LengthSquared();
}
// //
// In-place vector operations // In-place vector operations
// //

View File

@ -65,6 +65,15 @@ void PathFindingDemo::CreateMap() {
player2->SetPosition(m_Map.TileToWorld(TilePos{50, 20})); player2->SetPosition(m_Map.TileToWorld(TilePos{50, 20}));
AddEntity(player2); AddEntity(player2);
for (int i = 0; i < 1; i++)
{
for (int j = 0; j < 10; j++)
{
auto p = std::make_shared<Player>();
p->SetPosition(m_Map.TileToWorld(TilePos{10+5*i, 40+5*j}));
AddEntity(p);
}
}
// select everything - TODO this is just temporary for testing // select everything - TODO this is just temporary for testing
for (const auto& entity : m_Entities) for (const auto& entity : m_Entities)
@ -79,6 +88,30 @@ WorldPos PathFindingDemo::GetRandomPosition() const {
const std::vector<Collision>& PathFindingDemo::GetEntityCollisions()
{
static std::vector<Collision> m_Collisions;
m_Collisions.clear();
for (const auto &entity_A : m_Entities)
{
for (const auto &entity_B : m_Entities)
{
if (entity_A == entity_B)
continue;
if (!entity_A->IsCollidable() || !entity_B->IsCollidable())
continue;
if (entity_A->CollidesWith(*entity_B))
{
// handle collision logic
m_Collisions.emplace_back(Collision(entity_A, entity_B));
}
}
}
return m_Collisions;
}
// Update entity positions, handle collisions // Update entity positions, handle collisions
void PathFindingDemo::UpdateWorld() { void PathFindingDemo::UpdateWorld() {
@ -100,8 +133,26 @@ void PathFindingDemo::UpdateWorld() {
} }
entity->SetActualVelocity(velocity * tile_velocity_coeff); entity->SetActualVelocity(velocity * tile_velocity_coeff);
for (const auto& collision : GetEntityCollisions())
// handle collisions - these may modify the velocity {
// TODO this loop is quite "hot", is it good idea to use weak_ptr and promote it?
auto weak_A = std::get<0>(collision);
auto weak_B = std::get<1>(collision);
auto A = weak_A.lock();
auto B = weak_B.lock();
if (A == nullptr || B == nullptr)
{
continue;
}
if (!A->IsMovable())
continue;
// modify actual speed
// LOG_DEBUG("Collision: A is ", A, ", B is ", B);
auto AB = B->GetPosition() - A->GetPosition();
A->ZeroActualVelocityInDirection(AB);
// handle logic
// TODO
}
// update the position // update the position
entity->Update(time_delta); entity->Update(time_delta);

View File

@ -12,6 +12,8 @@
#include "pathfinder/base.hpp" #include "pathfinder/base.hpp"
#include "camera.hpp" #include "camera.hpp"
using Collision = std::pair<std::weak_ptr<Entity>, std::weak_ptr<Entity>>;
class PathFindingDemo { class PathFindingDemo {
public: public:
PathFindingDemo(int width, int height); PathFindingDemo(int width, int height);
@ -33,7 +35,10 @@ public:
void HandleActions(const std::vector<UserAction> &actions); void HandleActions(const std::vector<UserAction> &actions);
WorldPos GetRandomPosition() const; WorldPos GetRandomPosition() const;
private: private:
const std::vector<Collision>& GetEntityCollisions();
bool m_ExitRequested = false; bool m_ExitRequested = false;
Map m_Map; Map m_Map;
Camera m_Camera; Camera m_Camera;