Basic collisions
This commit is contained in:
parent
3d34b68133
commit
250f0963c8
@ -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) {
|
||||||
|
@ -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; }
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
//
|
//
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user