Basic collisions
This commit is contained in:
parent
3d34b68133
commit
250f0963c8
@ -68,6 +68,25 @@ std::optional<WorldPos> Entity::GetMoveTarget()
|
||||
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() {
|
||||
LOG_DEBUG(".");
|
||||
if (m_Sprite == nullptr) {
|
||||
|
@ -63,6 +63,10 @@ public:
|
||||
void SetPath(pathfinder::Path& path) { m_Path = path; }
|
||||
std::optional<WorldPos> GetMoveTarget();
|
||||
|
||||
bool CollidesWith(const Entity& other) const;
|
||||
|
||||
bool IsCollisionBoxVisible() const { return m_CollisionBoxVisible; }
|
||||
|
||||
protected:
|
||||
WorldPos m_Position;
|
||||
WorldPos m_ActualVelocity;
|
||||
@ -71,7 +75,7 @@ protected:
|
||||
|
||||
private:
|
||||
bool m_FlagExpired = false;
|
||||
static constexpr float m_CollisionRadiusSq = 1000.0f;
|
||||
bool m_CollisionBoxVisible = true;
|
||||
};
|
||||
|
||||
class Player final : public Entity {
|
||||
@ -83,7 +87,7 @@ public:
|
||||
constexpr Entity::Type GetType() const override {
|
||||
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 IsCollidable() const override { return true; }
|
||||
|
||||
|
@ -43,8 +43,14 @@ void GameLoop::Draw() {
|
||||
// draw all the entities (player etc)
|
||||
for (auto &entity : m_Game->GetEntities()) {
|
||||
const auto &camera = m_Game->GetCamera();
|
||||
m_Window->DrawSprite(camera.WorldToWindow(entity->GetPosition()),
|
||||
entity->GetSprite(), camera.GetZoom());
|
||||
auto entity_pos_window = camera.WorldToWindow(entity->GetPosition());
|
||||
m_Window->DrawSprite(entity_pos_window,
|
||||
entity->GetSprite(),
|
||||
camera.GetZoom());
|
||||
if (entity->IsCollisionBoxVisible())
|
||||
{
|
||||
m_Window->DrawCircle(entity_pos_window, entity->GetCollisionRadius());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,12 @@ public:
|
||||
return (a - b).Length();
|
||||
}
|
||||
|
||||
T DistanceSquared(const vec &b) const {
|
||||
const vec &a = *this;
|
||||
return (a - b).LengthSquared();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// In-place vector operations
|
||||
//
|
||||
|
@ -65,6 +65,15 @@ void PathFindingDemo::CreateMap() {
|
||||
player2->SetPosition(m_Map.TileToWorld(TilePos{50, 20}));
|
||||
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
|
||||
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
|
||||
void PathFindingDemo::UpdateWorld() {
|
||||
|
||||
@ -100,8 +133,26 @@ void PathFindingDemo::UpdateWorld() {
|
||||
}
|
||||
entity->SetActualVelocity(velocity * tile_velocity_coeff);
|
||||
|
||||
|
||||
// handle collisions - these may modify the velocity
|
||||
for (const auto& collision : GetEntityCollisions())
|
||||
{
|
||||
// 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
|
||||
entity->Update(time_delta);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "pathfinder/base.hpp"
|
||||
#include "camera.hpp"
|
||||
|
||||
using Collision = std::pair<std::weak_ptr<Entity>, std::weak_ptr<Entity>>;
|
||||
|
||||
class PathFindingDemo {
|
||||
public:
|
||||
PathFindingDemo(int width, int height);
|
||||
@ -33,7 +35,10 @@ public:
|
||||
void HandleActions(const std::vector<UserAction> &actions);
|
||||
WorldPos GetRandomPosition() const;
|
||||
|
||||
|
||||
private:
|
||||
const std::vector<Collision>& GetEntityCollisions();
|
||||
|
||||
bool m_ExitRequested = false;
|
||||
Map m_Map;
|
||||
Camera m_Camera;
|
||||
|
Loading…
x
Reference in New Issue
Block a user