Multiple entities + pathfinding
This commit is contained in:
parent
2f80129dce
commit
3d34b68133
@ -46,6 +46,28 @@ void Entity::Update(float time_delta) {
|
||||
m_Position += m_ActualVelocity * time_delta;
|
||||
}
|
||||
|
||||
std::optional<WorldPos> Entity::GetMoveTarget()
|
||||
{
|
||||
auto& path = GetPath();
|
||||
if (path.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
WorldPos current_pos = GetPosition();
|
||||
WorldPos next_pos = path.front();
|
||||
|
||||
if (current_pos.DistanceTo(next_pos) > 1.0) {
|
||||
// target not reached yet
|
||||
return next_pos;
|
||||
}
|
||||
// target reached, pop it
|
||||
//m_MoveQueue.pop();
|
||||
path.erase(path.begin());
|
||||
// return nothing - if there's next point in the queue,
|
||||
// we'll get it in the next iteration
|
||||
return {};
|
||||
}
|
||||
|
||||
Player::Player() {
|
||||
LOG_DEBUG(".");
|
||||
if (m_Sprite == nullptr) {
|
||||
|
@ -5,10 +5,12 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
|
||||
#include "log.hpp"
|
||||
#include "math.hpp"
|
||||
#include "sprite.hpp"
|
||||
#include "pathfinder/base.hpp"
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
@ -56,10 +58,16 @@ public:
|
||||
|
||||
void ZeroActualVelocityInDirection(WorldPos direction);
|
||||
|
||||
const pathfinder::Path& GetPath() const { return m_Path; }
|
||||
pathfinder::Path& GetPath() { return m_Path; }
|
||||
void SetPath(pathfinder::Path& path) { m_Path = path; }
|
||||
std::optional<WorldPos> GetMoveTarget();
|
||||
|
||||
protected:
|
||||
WorldPos m_Position;
|
||||
WorldPos m_ActualVelocity;
|
||||
WorldPos m_RequestedVelocity;
|
||||
pathfinder::Path m_Path;
|
||||
|
||||
private:
|
||||
bool m_FlagExpired = false;
|
||||
|
@ -27,12 +27,17 @@ void GameLoop::Draw() {
|
||||
}
|
||||
|
||||
// draw the path, if it exists
|
||||
WorldPos start_pos = m_Game->GetPlayer()->GetPosition();
|
||||
for (const auto &next_pos : m_Game->GetPath()) {
|
||||
const auto &camera = m_Game->GetCamera();
|
||||
m_Window->DrawLine(camera.WorldToWindow(start_pos),
|
||||
camera.WorldToWindow(next_pos));
|
||||
start_pos = next_pos;
|
||||
|
||||
for (const auto& entity : m_Game->GetEntities())
|
||||
{
|
||||
WorldPos start_pos = entity->GetPosition();
|
||||
for (const auto &next_pos : entity->GetPath())
|
||||
{
|
||||
const auto &camera = m_Game->GetCamera();
|
||||
m_Window->DrawLine(camera.WorldToWindow(start_pos),
|
||||
camera.WorldToWindow(next_pos));
|
||||
start_pos = next_pos;
|
||||
}
|
||||
}
|
||||
|
||||
// draw all the entities (player etc)
|
||||
@ -49,9 +54,10 @@ void GameLoop::Run() {
|
||||
LOG_INFO("Running the game");
|
||||
while (!m_Game->IsExitRequested()) {
|
||||
m_Game->HandleActions(m_UserInput->GetActions());
|
||||
m_Game->UpdatePlayerVelocity();
|
||||
m_Game->UpdateWorld();
|
||||
|
||||
// TODO measure fps, draw only if delay for target fps was reached
|
||||
// or create a separate thread for drawing
|
||||
m_Window->ClearWindow();
|
||||
Draw();
|
||||
m_Window->Flush();
|
||||
|
@ -55,54 +55,57 @@ void PathFindingDemo::CreateMap() {
|
||||
m_Map.PaintLine(TilePos{84,81}, TilePos{84,96}, 1.0, TileType::WALL);
|
||||
m_Map.PaintLine(TilePos{78,87}, TilePos{78,100}, 1.0, TileType::WALL);
|
||||
|
||||
// add player
|
||||
// add some controllable entities
|
||||
m_Entities.clear();
|
||||
m_Player = std::make_shared<Player>();
|
||||
m_Player->SetPosition(m_Map.TileToWorld(TilePos{25, 20}));
|
||||
m_Entities.push_back(m_Player);
|
||||
auto player = std::make_shared<Player>();
|
||||
player->SetPosition(m_Map.TileToWorld(TilePos{25, 20}));
|
||||
AddEntity(player);
|
||||
|
||||
auto player2 = std::make_shared<Player>();
|
||||
player2->SetPosition(m_Map.TileToWorld(TilePos{50, 20}));
|
||||
AddEntity(player2);
|
||||
|
||||
|
||||
// select everything - TODO this is just temporary for testing
|
||||
for (const auto& entity : m_Entities)
|
||||
{
|
||||
m_SelectedEntities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPos PathFindingDemo::GetRandomPosition() const {
|
||||
return WorldPos{0.0f, 0.0f}; // totally random!
|
||||
}
|
||||
|
||||
std::optional<WorldPos> PathFindingDemo::GetMoveTarget() {
|
||||
WorldPos player_current_pos = GetPlayer()->GetPosition();
|
||||
|
||||
if (m_Path.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
WorldPos player_next_pos = m_Path.front();
|
||||
|
||||
if (player_current_pos.DistanceTo(player_next_pos) > 1.0) {
|
||||
// target not reached yet
|
||||
return player_next_pos;
|
||||
}
|
||||
// target reached, pop it
|
||||
//m_MoveQueue.pop();
|
||||
m_Path.erase(m_Path.begin());
|
||||
// return nothing - if there's next point in the queue,
|
||||
// we'll get it in the next iteration
|
||||
return {};
|
||||
}
|
||||
|
||||
void PathFindingDemo::UpdatePlayerVelocity() {
|
||||
auto player = GetPlayer();
|
||||
auto current_pos = player->GetPosition();
|
||||
double tile_velocity_coeff = m_Map.GetTileVelocityCoeff(current_pos);
|
||||
auto next_pos = GetMoveTarget();
|
||||
WorldPos velocity = WorldPos{};
|
||||
if (next_pos)
|
||||
{
|
||||
velocity = next_pos.value() - current_pos;
|
||||
velocity.Normalize();
|
||||
//LOG_DEBUG("I want to move to: ", next_pos.value(),
|
||||
// ", velocity: ", velocity);
|
||||
}
|
||||
player->SetActualVelocity(velocity * tile_velocity_coeff);
|
||||
// Update entity positions, handle collisions
|
||||
void PathFindingDemo::UpdateWorld() {
|
||||
|
||||
float time_delta = 1.0f;
|
||||
player->Update(time_delta);
|
||||
|
||||
for (auto& entity : m_Entities)
|
||||
{
|
||||
// calculate the velocity
|
||||
auto current_pos = entity->GetPosition();
|
||||
double tile_velocity_coeff = m_Map.GetTileVelocityCoeff(current_pos);
|
||||
auto next_pos = entity->GetMoveTarget();
|
||||
WorldPos velocity = WorldPos{};
|
||||
if (next_pos)
|
||||
{
|
||||
velocity = next_pos.value() - current_pos;
|
||||
velocity.Normalize();
|
||||
//LOG_DEBUG("I want to move to: ", next_pos.value(),
|
||||
// ", velocity: ", velocity);
|
||||
}
|
||||
entity->SetActualVelocity(velocity * tile_velocity_coeff);
|
||||
|
||||
|
||||
// handle collisions - these may modify the velocity
|
||||
|
||||
// update the position
|
||||
entity->Update(time_delta);
|
||||
}
|
||||
}
|
||||
|
||||
void PathFindingDemo::HandleActions(const std::vector<UserAction> &actions)
|
||||
@ -116,10 +119,19 @@ void PathFindingDemo::HandleActions(const std::vector<UserAction> &actions)
|
||||
}
|
||||
else if (action.type == UserAction::Type::SET_MOVE_TARGET)
|
||||
{
|
||||
WorldPos wp = m_Camera.WindowToWorld(action.Argument.position);
|
||||
LOG_INFO("Calculating path to target: ", wp);
|
||||
m_Path = m_PathFinder->CalculatePath(m_Player->GetPosition(), wp);
|
||||
LOG_INFO("Done, path node count: ", m_Path.size());
|
||||
WorldPos target_pos = m_Camera.WindowToWorld(action.Argument.position);
|
||||
for (auto& selected_entity : m_SelectedEntities)
|
||||
{
|
||||
LOG_INFO("Calculating path to target: ", target_pos);
|
||||
if (auto sp = selected_entity.lock())
|
||||
{
|
||||
auto path = m_PathFinder->CalculatePath(sp->GetPosition(), target_pos);
|
||||
sp->SetPath(path);
|
||||
LOG_INFO("Done, path node count: ", path.size());
|
||||
} else {
|
||||
LOG_INFO("Cannot calculate path for destroyed entity (weak_ptr.lock() failed)");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (action.type == UserAction::Type::SELECT_PATHFINDER)
|
||||
{
|
||||
|
@ -22,17 +22,14 @@ public:
|
||||
PathFindingDemo &operator=(const PathFindingDemo &) = delete;
|
||||
PathFindingDemo &operator=(PathFindingDemo &&) = delete;
|
||||
|
||||
std::shared_ptr<Player> GetPlayer() { return m_Player; }
|
||||
std::vector<std::shared_ptr<Entity>>& GetEntities() { return m_Entities; }
|
||||
const Map& GetMap() const { return m_Map; }
|
||||
const Camera& GetCamera() const { return m_Camera; }
|
||||
const pathfinder::Path& GetPath() const { return m_Path; }
|
||||
bool IsExitRequested() const { return m_ExitRequested; }
|
||||
|
||||
void AddEntity(std::shared_ptr<Entity> e);
|
||||
void CreateMap();
|
||||
std::optional<WorldPos> GetMoveTarget();
|
||||
void UpdatePlayerVelocity();
|
||||
void UpdateWorld();
|
||||
void HandleActions(const std::vector<UserAction> &actions);
|
||||
WorldPos GetRandomPosition() const;
|
||||
|
||||
@ -41,7 +38,6 @@ private:
|
||||
Map m_Map;
|
||||
Camera m_Camera;
|
||||
std::vector<std::shared_ptr<Entity>> m_Entities;
|
||||
std::shared_ptr<Player> m_Player;
|
||||
pathfinder::Path m_Path;
|
||||
std::unique_ptr<pathfinder::PathFinderBase> m_PathFinder;
|
||||
std::vector<std::weak_ptr<Entity>> m_SelectedEntities;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user