Skip to content

Commit

Permalink
feat: Add MovingAI pathing for NPCs without combatAI (#1509)
Browse files Browse the repository at this point in the history
* remove goto

* Update MovementAIComponent.cpp

* convert to PathWaypoint

Easier for usage with paths

* add path parsing

* ref removal, simplification of work

* it works

* Update MovementAIComponent.cpp

* disable pathing for combat

we just need it for npcs for now, combat ai can be done later

* fixed stuttery enemies

wow

* start at ramped up speed

* add pausing and resuming

* Update MovementAIComponent.cpp

* Update MovementAIComponent.h

* Update CMakeLists.txt
  • Loading branch information
EmosewaMC authored Mar 27, 2024
1 parent 39b81b6 commit bd9b790
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 85 deletions.
20 changes: 13 additions & 7 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,15 +731,21 @@ void Entity::Initialize() {
// if we have a moving platform path, then we need a moving platform component
if (path->pathType == PathType::MovingPlatform) {
AddComponent<MovingPlatformComponent>(pathName);
// else if we are a movement path
} /*else if (path->pathType == PathType::Movement) {
auto movementAIcomp = GetComponent<MovementAIComponent>();
if (movementAIcomp){
// TODO: set path in existing movementAIComp
} else if (path->pathType == PathType::Movement) {
auto movementAIcomponent = GetComponent<MovementAIComponent>();
if (movementAIcomponent && combatAiId == 0) {
movementAIcomponent->SetPath(pathName);
} else {
// TODO: create movementAIcomp and set path
MovementAIInfo moveInfo = MovementAIInfo();
moveInfo.movementType = "";
moveInfo.wanderChance = 0;
moveInfo.wanderRadius = 16;
moveInfo.wanderSpeed = 2.5f;
moveInfo.wanderDelayMax = 5;
moveInfo.wanderDelayMin = 2;
AddComponent<MovementAIComponent>(moveInfo);
}
}*/
}
} else {
// else we still need to setup moving platform if it has a moving platform comp but no path
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
Expand Down
99 changes: 79 additions & 20 deletions dGame/dComponents/MovementAIComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,42 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) :
m_CurrentSpeed = 0;
m_MaxSpeed = 0;
m_LockRotation = false;
m_Path = nullptr;
m_SourcePosition = m_Parent->GetPosition();
m_Paused = false;
m_SavedVelocity = NiPoint3Constant::ZERO;

if (!m_Parent->GetComponent<BaseCombatAIComponent>()) SetPath(m_Parent->GetVarAsString(u"attached_path"));
}

void MovementAIComponent::SetPath(const std::string pathName) {
m_Path = Game::zoneManager->GetZone()->GetPath(pathName);
if (!pathName.empty()) LOG("WARNING: %s path %s", m_Path ? "Found" : "Failed to find", pathName.c_str());
if (!m_Path) return;
SetMaxSpeed(1);
SetCurrentSpeed(m_BaseSpeed);
SetPath(m_Path->pathWaypoints);
}

void MovementAIComponent::Pause() {
m_Paused = true;
SetPosition(ApproximateLocation());
m_SavedVelocity = GetVelocity();
SetVelocity(NiPoint3Constant::ZERO);
Game::entityManager->SerializeEntity(m_Parent);
}

void MovementAIComponent::Resume() {
m_Paused = false;
SetVelocity(m_SavedVelocity);
m_SavedVelocity = NiPoint3Constant::ZERO;
SetRotation(NiQuaternion::LookAt(m_Parent->GetPosition(), m_NextWaypoint));
Game::entityManager->SerializeEntity(m_Parent);
}

void MovementAIComponent::Update(const float deltaTime) {
if (m_Paused) return;

if (m_PullingToPoint) {
const auto source = GetCurrentWaypoint();

Expand Down Expand Up @@ -81,27 +114,24 @@ void MovementAIComponent::Update(const float deltaTime) {
}

m_TimeTravelled += deltaTime;

SetPosition(ApproximateLocation());

if (m_TimeTravelled < m_TimeToTravel) return;
m_TimeTravelled = 0.0f;

const auto source = GetCurrentWaypoint();

SetPosition(source);

NiPoint3 velocity = NiPoint3Constant::ZERO;
m_SourcePosition = source;

if (m_Acceleration > 0 && m_BaseSpeed > 0 && AdvanceWaypointIndex()) // Do we have another waypoint to seek?
{
m_NextWaypoint = GetCurrentWaypoint();

if (m_NextWaypoint == source) {
m_TimeToTravel = 0.0f;
} else {
if (m_CurrentSpeed < m_MaxSpeed) {
m_CurrentSpeed += m_Acceleration;
}

m_CurrentSpeed = std::min(m_CurrentSpeed, m_MaxSpeed);
m_CurrentSpeed = std::min(m_CurrentSpeed + m_Acceleration, m_MaxSpeed);

const auto speed = m_CurrentSpeed * m_BaseSpeed; // scale speed based on base speed

Expand All @@ -110,7 +140,7 @@ void MovementAIComponent::Update(const float deltaTime) {
// Normalize the vector
const auto length = delta.Length();
if (length > 0.0f) {
velocity = (delta / length) * speed;
SetVelocity((delta / length) * speed);
}

// Calclute the time it will take to reach the next waypoint with the current speed
Expand All @@ -122,17 +152,27 @@ void MovementAIComponent::Update(const float deltaTime) {
} else {
// Check if there are more waypoints in the queue, if so set our next destination to the next waypoint
if (m_CurrentPath.empty()) {
Stop();

return;
if (m_Path) {
if (m_Path->pathBehavior == PathBehavior::Loop) {
SetPath(m_Path->pathWaypoints);
} else if (m_Path->pathBehavior == PathBehavior::Bounce) {
std::vector<PathWaypoint> waypoints = m_Path->pathWaypoints;
std::reverse(waypoints.begin(), waypoints.end());
SetPath(waypoints);
} else if (m_Path->pathBehavior == PathBehavior::Once) {
Stop();
return;
}
} else {
Stop();
return;
}
}
SetDestination(m_CurrentPath.top());
SetDestination(m_CurrentPath.top().position);

m_CurrentPath.pop();
}

SetVelocity(velocity);

Game::entityManager->SerializeEntity(m_Parent);
}

Expand All @@ -155,7 +195,7 @@ NiPoint3 MovementAIComponent::GetCurrentWaypoint() const {
}

NiPoint3 MovementAIComponent::ApproximateLocation() const {
auto source = m_Parent->GetPosition();
auto source = m_SourcePosition;

if (AtFinalWaypoint()) return source;

Expand Down Expand Up @@ -221,13 +261,13 @@ void MovementAIComponent::PullToPoint(const NiPoint3& point) {
m_PullPoint = point;
}

void MovementAIComponent::SetPath(std::vector<NiPoint3> path) {
void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) {
if (path.empty()) return;
std::for_each(path.rbegin(), path.rend() - 1, [this](const NiPoint3& point) {
std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) {
this->m_CurrentPath.push(point);
});

SetDestination(path.front());
SetDestination(path.front().position);
}

float MovementAIComponent::GetBaseSpeed(LOT lot) {
Expand Down Expand Up @@ -272,6 +312,23 @@ void MovementAIComponent::SetRotation(const NiQuaternion& value) {
if (!m_LockRotation) m_Parent->SetRotation(value);
}

NiPoint3 MovementAIComponent::GetVelocity() const {
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();

if (controllablePhysicsComponent != nullptr) {
return controllablePhysicsComponent->GetVelocity();
}

auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();

if (simplePhysicsComponent != nullptr) {
return simplePhysicsComponent->GetVelocity();
}

return NiPoint3Constant::ZERO;

}

void MovementAIComponent::SetVelocity(const NiPoint3& value) {
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();

Expand All @@ -288,7 +345,7 @@ void MovementAIComponent::SetVelocity(const NiPoint3& value) {
}
}

void MovementAIComponent::SetDestination(const NiPoint3& destination) {
void MovementAIComponent::SetDestination(const NiPoint3 destination) {
if (m_PullingToPoint) return;

const auto location = ApproximateLocation();
Expand All @@ -297,6 +354,8 @@ void MovementAIComponent::SetDestination(const NiPoint3& destination) {
SetPosition(location);
}

m_SourcePosition = location;

std::vector<NiPoint3> computedPath;
if (dpWorld::IsLoaded()) {
computedPath = dpWorld::GetNavMesh()->GetPath(m_Parent->GetPosition(), destination, m_Info.wanderSpeed);
Expand Down
25 changes: 22 additions & 3 deletions dGame/dComponents/MovementAIComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
#include "Logger.h"
#include "Component.h"
#include "eReplicaComponentType.h"
#include "Zone.h"
#include <vector>

class ControllablePhysicsComponent;
class BaseCombatAIComponent;

struct Path;

/**
* Information that describes the different variables used to make an entity move around
*/
Expand Down Expand Up @@ -61,6 +64,8 @@ class MovementAIComponent final : public Component {

MovementAIComponent(Entity* parentEntity, MovementAIInfo info);

void SetPath(const std::string pathName);

void Update(float deltaTime) override;

/**
Expand All @@ -73,7 +78,7 @@ class MovementAIComponent final : public Component {
* Set a destination point for the entity to move towards
* @param value the destination point to move towards
*/
void SetDestination(const NiPoint3& value);
void SetDestination(const NiPoint3 value);

/**
* Returns the current rotation this entity is moving towards
Expand Down Expand Up @@ -189,7 +194,13 @@ class MovementAIComponent final : public Component {
* Sets a path to follow for the AI
* @param path the path to follow
*/
void SetPath(std::vector<NiPoint3> path);
void SetPath(std::vector<PathWaypoint> path);

void Pause();

void Resume();

NiPoint3 GetVelocity() const;

/**
* Returns the base speed from the DB for a given LOT
Expand Down Expand Up @@ -301,7 +312,15 @@ class MovementAIComponent final : public Component {
/**
* The path from the current position to the destination.
*/
std::stack<NiPoint3> m_CurrentPath;
std::stack<PathWaypoint> m_CurrentPath;

const Path* m_Path = nullptr;

NiPoint3 m_SourcePosition;

bool m_Paused;

NiPoint3 m_SavedVelocity;
};

#endif // MOVEMENTAICOMPONENT_H
1 change: 1 addition & 0 deletions dGame/dComponents/ProximityMonitorComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void ProximityMonitorComponent::Update(float deltaTime) {
for (const auto& prox : m_ProximitiesData) {
if (!prox.second) continue;

prox.second->SetPosition(m_Parent->GetPosition());
//Process enter events
for (auto* en : prox.second->GetNewObjects()) {
m_Parent->OnCollisionProximity(en->GetObjectID(), prox.first, "ENTER");
Expand Down
5 changes: 2 additions & 3 deletions dScripts/02_server/Map/AM/WanderingVendor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
void WanderingVendor::OnStartup(Entity* self) {
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (!movementAIComponent) return;
// movementAIComponent->Resume();
self->SetProximityRadius(10, "playermonitor");
}

void WanderingVendor::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) {
if (status == "ENTER" && entering->IsPlayer()) {
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (!movementAIComponent) return;
// movementAIComponent->Pause();
movementAIComponent->Pause();
self->CancelTimer("startWalking");
} else if (status == "LEAVE") {
auto* proximityMonitorComponent = self->GetComponent<ProximityMonitorComponent>();
Expand All @@ -28,6 +27,6 @@ void WanderingVendor::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "startWalking") {
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (!movementAIComponent) return;
// movementAIComponent->Resume();
movementAIComponent->Resume();
}
}
6 changes: 1 addition & 5 deletions dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,7 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) {
movementAI->SetCurrentSpeed(toSpawn.initialSpeed);
movementAI->SetHaltDistance(0.0f);

std::vector<NiPoint3> pathWaypoints;

for (const auto& waypoint : path->pathWaypoints) {
pathWaypoints.push_back(waypoint.position);
}
std::vector<PathWaypoint> pathWaypoints = path->pathWaypoints;

if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) {
std::reverse(pathWaypoints.begin(), pathWaypoints.end());
Expand Down
9 changes: 4 additions & 5 deletions dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
void WblRobotCitizen::OnStartup(Entity* self) {
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (!movementAIComponent) return;
// movementAIComponent->Resume();
}

void WblRobotCitizen::OnUse(Entity* self, Entity* user) {
// auto movementAIComponent = self->GetComponent<MovementAIComponent>();
// if (!movementAIComponent) movementAIComponent->Pause();
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (movementAIComponent) movementAIComponent->Pause();
auto face = NiQuaternion::LookAt(self->GetPosition(), user->GetPosition());
self->SetRotation(face);
auto timer = RenderComponent::PlayAnimation(self, "wave");
auto timer = RenderComponent::PlayAnimation(self, "wave", 0.4f);
self->AddTimer("animation time", timer);
}

void WblRobotCitizen::OnTimerDone(Entity* self, std::string timerName) {
auto movementAIComponent = self->GetComponent<MovementAIComponent>();
if (!movementAIComponent) return;
// movementAIComponent->Resume();
movementAIComponent->Resume();
}
Loading

0 comments on commit bd9b790

Please sign in to comment.