Implement a Motion Manager around UnitMotion.
This new MotionManager handles movement for UnitMotion components (not
UnitMotionFlying).
This is a first step towards unit pushing, by giving a central place for
the relevant units to collide.
One important side-effect is that movement is effectively synchronous -
the positions are not actually updated until all units have moved for a
turn (refs 6a66fb8205
).
As a side-effect, it's an optimisation: fewer messages are being sent
overall, which leads to a slight speedup (negligible without a lot of
units though).
This is a first step - ideally, the movement functions called from
UnitMotionManager would actually be moved there.
Differential Revision: https://code.wildfiregames.com/D3509
This was SVN commit r25071.
This commit is contained in:
parent
ae07dcb4ff
commit
bae258f9a1
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -196,6 +196,9 @@ INTERFACE(UnitMotion)
|
||||
COMPONENT(UnitMotion) // must be after Obstruction
|
||||
COMPONENT(UnitMotionScripted)
|
||||
|
||||
INTERFACE(UnitMotionManager)
|
||||
COMPONENT(UnitMotionManager)
|
||||
|
||||
INTERFACE(UnitRenderer)
|
||||
COMPONENT(UnitRenderer)
|
||||
|
||||
|
@ -119,9 +119,8 @@ class CCmpUnitMotion : public ICmpUnitMotion
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_Update_MotionFormation);
|
||||
componentManager.SubscribeToMessageType(MT_Update_MotionUnit);
|
||||
componentManager.SubscribeToMessageType(MT_Create);
|
||||
componentManager.SubscribeToMessageType(MT_Destroy);
|
||||
componentManager.SubscribeToMessageType(MT_PathResult);
|
||||
componentManager.SubscribeToMessageType(MT_OwnershipChanged);
|
||||
componentManager.SubscribeToMessageType(MT_ValueModification);
|
||||
@ -207,15 +206,6 @@ public:
|
||||
WaypointPath m_LongPath;
|
||||
WaypointPath m_ShortPath;
|
||||
|
||||
// Hack - units move one-at-a-time, so they may need to interplate their target position.
|
||||
// However, some computations are not doing during the motion messages, and those shouldn't (e.g. turn start).
|
||||
// This is true if and only if the calls take place during handling of the entity's MT_Motion* messages.
|
||||
// NB: this won't be true if we end up in UnitMotion because of another entity's motion messages,
|
||||
// but I think it fixes the issue of interpolating target position OK for current needs,
|
||||
// without having to add parameters everywhere.
|
||||
// No need for serialisation, it's just a transient boolean.
|
||||
bool m_InMotionMessage = false;
|
||||
|
||||
static std::string GetSchema()
|
||||
{
|
||||
return
|
||||
@ -321,33 +311,6 @@ public:
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_TurnStart:
|
||||
{
|
||||
TurnStart();
|
||||
break;
|
||||
}
|
||||
case MT_Update_MotionFormation:
|
||||
{
|
||||
if (m_FormationController)
|
||||
{
|
||||
m_InMotionMessage = true;
|
||||
fixed dt = static_cast<const CMessageUpdate_MotionFormation&> (msg).turnLength;
|
||||
Move(dt);
|
||||
m_InMotionMessage = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_Update_MotionUnit:
|
||||
{
|
||||
if (!m_FormationController)
|
||||
{
|
||||
m_InMotionMessage = true;
|
||||
fixed dt = static_cast<const CMessageUpdate_MotionUnit&> (msg).turnLength;
|
||||
Move(dt);
|
||||
m_InMotionMessage = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_RenderSubmit:
|
||||
{
|
||||
PROFILE("UnitMotion::RenderSubmit");
|
||||
@ -361,6 +324,18 @@ public:
|
||||
PathResult(msgData.ticket, msgData.path);
|
||||
break;
|
||||
}
|
||||
case MT_Create:
|
||||
{
|
||||
if (!ENTITY_IS_LOCAL(GetEntityId()))
|
||||
CmpPtr<ICmpUnitMotionManager>(GetSystemEntity())->Register(GetEntityId(), m_FormationController);
|
||||
break;
|
||||
}
|
||||
case MT_Destroy:
|
||||
{
|
||||
if (!ENTITY_IS_LOCAL(GetEntityId()))
|
||||
CmpPtr<ICmpUnitMotionManager>(GetSystemEntity())->Unregister(GetEntityId());
|
||||
break;
|
||||
}
|
||||
case MT_ValueModification:
|
||||
{
|
||||
const CMessageValueModification& msgData = static_cast<const CMessageValueModification&> (msg);
|
||||
@ -369,20 +344,15 @@ public:
|
||||
FALLTHROUGH;
|
||||
}
|
||||
case MT_OwnershipChanged:
|
||||
{
|
||||
OnValueModification();
|
||||
break;
|
||||
}
|
||||
case MT_Deserialized:
|
||||
{
|
||||
CmpPtr<ICmpValueModificationManager> cmpValueModificationManager(GetSystemEntity());
|
||||
if (!cmpValueModificationManager)
|
||||
break;
|
||||
|
||||
m_WalkSpeed = cmpValueModificationManager->ApplyModifications(L"UnitMotion/WalkSpeed", m_TemplateWalkSpeed, GetEntityId());
|
||||
m_RunMultiplier = cmpValueModificationManager->ApplyModifications(L"UnitMotion/RunMultiplier", m_TemplateRunMultiplier, GetEntityId());
|
||||
|
||||
// For MT_Deserialize compute m_Speed from the serialized m_SpeedMultiplier.
|
||||
// For MT_ValueModification and MT_OwnershipChanged, adjust m_SpeedMultiplier if needed
|
||||
// (in case then new m_RunMultiplier value is lower than the old).
|
||||
SetSpeedMultiplier(m_SpeedMultiplier);
|
||||
|
||||
OnValueModification();
|
||||
if (!ENTITY_IS_LOCAL(GetEntityId()))
|
||||
CmpPtr<ICmpUnitMotionManager>(GetSystemEntity())->Register(GetEntityId(), m_FormationController);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -651,17 +621,33 @@ private:
|
||||
*/
|
||||
void PathResult(u32 ticket, const WaypointPath& path);
|
||||
|
||||
void OnValueModification()
|
||||
{
|
||||
CmpPtr<ICmpValueModificationManager> cmpValueModificationManager(GetSystemEntity());
|
||||
if (!cmpValueModificationManager)
|
||||
return;
|
||||
|
||||
m_WalkSpeed = cmpValueModificationManager->ApplyModifications(L"UnitMotion/WalkSpeed", m_TemplateWalkSpeed, GetEntityId());
|
||||
m_RunMultiplier = cmpValueModificationManager->ApplyModifications(L"UnitMotion/RunMultiplier", m_TemplateRunMultiplier, GetEntityId());
|
||||
|
||||
// For MT_Deserialize compute m_Speed from the serialized m_SpeedMultiplier.
|
||||
// For MT_ValueModification and MT_OwnershipChanged, adjust m_SpeedMultiplier if needed
|
||||
// (in case then new m_RunMultiplier value is lower than the old).
|
||||
SetSpeedMultiplier(m_SpeedMultiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are at destination early in the turn, this both lets units react faster
|
||||
* and ensure that distance comparisons are done while units are not being moved
|
||||
* (otherwise they won't be commutative).
|
||||
*/
|
||||
void TurnStart();
|
||||
virtual void OnTurnStart();
|
||||
|
||||
/**
|
||||
* Do the per-turn movement and other updates.
|
||||
*/
|
||||
void Move(fixed dt);
|
||||
virtual void PreMove(ICmpUnitMotionManager::MotionState& state);
|
||||
|
||||
virtual void Move(ICmpUnitMotionManager::MotionState& state, fixed dt);
|
||||
|
||||
virtual void PostMove(ICmpUnitMotionManager::MotionState& state, fixed dt);
|
||||
|
||||
/**
|
||||
* Returns true if we are possibly at our destination.
|
||||
@ -908,7 +894,7 @@ void CCmpUnitMotion::PathResult(u32 ticket, const WaypointPath& path)
|
||||
}
|
||||
}
|
||||
|
||||
void CCmpUnitMotion::TurnStart()
|
||||
void CCmpUnitMotion::OnTurnStart()
|
||||
{
|
||||
if (PossiblyAtDestination())
|
||||
MoveSucceeded();
|
||||
@ -926,64 +912,57 @@ void CCmpUnitMotion::TurnStart()
|
||||
}
|
||||
}
|
||||
|
||||
void CCmpUnitMotion::Move(fixed dt)
|
||||
void CCmpUnitMotion::PreMove(ICmpUnitMotionManager::MotionState& state)
|
||||
{
|
||||
// If we were idle and will still be, no need for an update.
|
||||
state.needUpdate = m_CurSpeed != fixed::Zero() || m_MoveRequest.m_Type != MoveRequest::NONE;
|
||||
}
|
||||
|
||||
void CCmpUnitMotion::Move(ICmpUnitMotionManager::MotionState& state, fixed dt)
|
||||
{
|
||||
PROFILE("Move");
|
||||
|
||||
// If we were idle and will still be, we can return.
|
||||
// TODO: this will need to be removed if pushing is implemented.
|
||||
if (m_CurSpeed == fixed::Zero() && m_MoveRequest.m_Type == MoveRequest::NONE)
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
|
||||
if (!cmpPosition || !cmpPosition->IsInWorld())
|
||||
return;
|
||||
|
||||
CFixedVector2D initialPos = cmpPosition->GetPosition2D();
|
||||
entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
|
||||
|
||||
// Keep track of the current unit's position and rotation during the update.
|
||||
CFixedVector2D pos = initialPos;
|
||||
entity_angle_t angle = initialAngle;
|
||||
|
||||
// If we're chasing a potentially-moving unit and are currently close
|
||||
// enough to its current position, and we can head in a straight line
|
||||
// to it, then throw away our current path and go straight to it
|
||||
bool wentStraight = TryGoingStraightToTarget(initialPos);
|
||||
// to it, then throw away our current path and go straight to it.
|
||||
state.wentStraight = TryGoingStraightToTarget(state.initialPos);
|
||||
|
||||
bool wasObstructed = PerformMove(dt, cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, pos, angle);
|
||||
state.wasObstructed = PerformMove(dt, state.cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, state.pos, state.angle);
|
||||
}
|
||||
|
||||
void CCmpUnitMotion::PostMove(ICmpUnitMotionManager::MotionState& state, fixed dt)
|
||||
{
|
||||
// Update our speed over this turn so that the visual actor shows the correct animation.
|
||||
if (pos == initialPos)
|
||||
if (state.pos == state.initialPos)
|
||||
{
|
||||
if (angle != initialAngle)
|
||||
cmpPosition->TurnTo(angle);
|
||||
if (state.angle != state.initialAngle)
|
||||
state.cmpPosition->TurnTo(state.angle);
|
||||
UpdateMovementState(fixed::Zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the Position component after our movement (if we actually moved anywhere)
|
||||
// When moving always set the angle in the direction of the movement.
|
||||
CFixedVector2D offset = pos - initialPos;
|
||||
angle = atan2_approx(offset.X, offset.Y);
|
||||
cmpPosition->MoveAndTurnTo(pos.X, pos.Y, angle);
|
||||
CFixedVector2D offset = state.pos - state.initialPos;
|
||||
state.angle = atan2_approx(offset.X, offset.Y);
|
||||
state.cmpPosition->MoveAndTurnTo(state.pos.X, state.pos.Y, state.angle);
|
||||
|
||||
// Calculate the mean speed over this past turn.
|
||||
UpdateMovementState(offset.Length() / dt);
|
||||
}
|
||||
|
||||
if (wasObstructed && HandleObstructedMove(pos != initialPos))
|
||||
if (state.wasObstructed && HandleObstructedMove(state.pos != state.initialPos))
|
||||
return;
|
||||
else if (!wasObstructed && pos != initialPos)
|
||||
else if (!state.wasObstructed && state.pos != state.initialPos)
|
||||
m_FailedMovements = 0;
|
||||
|
||||
// We may need to recompute our path sometimes (e.g. if our target moves).
|
||||
// Since we request paths asynchronously anyways, this does not need to be done before moving.
|
||||
if (!wentStraight && PathingUpdateNeeded(pos))
|
||||
if (!state.wentStraight && PathingUpdateNeeded(state.pos))
|
||||
{
|
||||
PathGoal goal;
|
||||
if (ComputeGoal(goal, m_MoveRequest))
|
||||
ComputePathToGoal(pos, goal);
|
||||
ComputePathToGoal(state.pos, goal);
|
||||
}
|
||||
else if (m_FollowKnownImperfectPathCountdown > 0)
|
||||
--m_FollowKnownImperfectPathCountdown;
|
||||
@ -1276,7 +1255,8 @@ bool CCmpUnitMotion::ComputeTargetPosition(CFixedVector2D& out, const MoveReques
|
||||
// If our entity ID is higher, the target has already moved, so we can just use the position directly.
|
||||
// TODO: This does not really aim many turns in advance, with orthogonal trajectories it probably should.
|
||||
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), moveRequest.m_Entity);
|
||||
bool needInterpolation = cmpUnitMotion && cmpUnitMotion->IsMoveRequested() && m_InMotionMessage;
|
||||
CmpPtr<ICmpUnitMotionManager> cmpUnitMotionManager(GetSystemEntity());
|
||||
bool needInterpolation = cmpUnitMotion && cmpUnitMotion->IsMoveRequested() && cmpUnitMotionManager->ComputingMotion();
|
||||
if (needInterpolation && GetEntityId() < moveRequest.m_Entity)
|
||||
{
|
||||
// Add predicted movement.
|
||||
|
184
source/simulation2/components/CCmpUnitMotionManager.cpp
Normal file
184
source/simulation2/components/CCmpUnitMotionManager.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpUnitMotionManager.h"
|
||||
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "simulation2/components/ICmpUnitMotion.h"
|
||||
#include "simulation2/system/EntityMap.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Profile.h"
|
||||
|
||||
class CCmpUnitMotionManager : public ICmpUnitMotionManager
|
||||
{
|
||||
protected:
|
||||
EntityMap<MotionState> m_Units;
|
||||
EntityMap<MotionState> m_FormationControllers;
|
||||
|
||||
// Temporary vector, reconstructed each turn (stored here to avoid memory reallocations).
|
||||
std::vector<EntityMap<MotionState>::iterator> m_MovingUnits;
|
||||
|
||||
bool m_ComputingMotion;
|
||||
public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(MT_TurnStart);
|
||||
componentManager.SubscribeToMessageType(MT_Update_Final);
|
||||
componentManager.SubscribeToMessageType(MT_Update_MotionUnit);
|
||||
componentManager.SubscribeToMessageType(MT_Update_MotionFormation);
|
||||
}
|
||||
|
||||
DEFAULT_COMPONENT_ALLOCATOR(UnitMotionManager)
|
||||
|
||||
virtual void Init(const CParamNode& UNUSED(paramNode))
|
||||
{
|
||||
m_MovingUnits.reserve(40);
|
||||
}
|
||||
|
||||
virtual void Deinit()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Serialize(ISerializer& UNUSED(serialize))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize))
|
||||
{
|
||||
Init(paramNode);
|
||||
}
|
||||
|
||||
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_TurnStart:
|
||||
{
|
||||
OnTurnStart();
|
||||
break;
|
||||
}
|
||||
case MT_Update_MotionFormation:
|
||||
{
|
||||
fixed dt = static_cast<const CMessageUpdate_MotionFormation&> (msg).turnLength;
|
||||
m_ComputingMotion = true;
|
||||
MoveFormations(dt);
|
||||
m_ComputingMotion = false;
|
||||
break;
|
||||
}
|
||||
case MT_Update_MotionUnit:
|
||||
{
|
||||
fixed dt = static_cast<const CMessageUpdate_MotionUnit&> (msg).turnLength;
|
||||
m_ComputingMotion = true;
|
||||
MoveUnits(dt);
|
||||
m_ComputingMotion = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Register(entity_id_t ent, bool formationController);
|
||||
virtual void Unregister(entity_id_t ent);
|
||||
|
||||
virtual bool ComputingMotion() const
|
||||
{
|
||||
return m_ComputingMotion;
|
||||
}
|
||||
|
||||
void OnTurnStart();
|
||||
|
||||
void MoveUnits(fixed dt);
|
||||
void MoveFormations(fixed dt);
|
||||
void Move(EntityMap<MotionState>& ents, fixed dt);
|
||||
};
|
||||
|
||||
void CCmpUnitMotionManager::Register(entity_id_t ent, bool formationController)
|
||||
{
|
||||
MotionState state = {
|
||||
CmpPtr<ICmpPosition>(GetSimContext(), ent),
|
||||
CmpPtr<ICmpUnitMotion>(GetSimContext(), ent),
|
||||
CFixedVector2D(),
|
||||
CFixedVector2D(),
|
||||
fixed::Zero(),
|
||||
fixed::Zero(),
|
||||
false,
|
||||
false
|
||||
};
|
||||
if (!formationController)
|
||||
m_Units.insert(ent, state);
|
||||
else
|
||||
m_FormationControllers.insert(ent, state);
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::Unregister(entity_id_t ent)
|
||||
{
|
||||
EntityMap<MotionState>::iterator it = m_Units.find(ent);
|
||||
if (it != m_Units.end())
|
||||
{
|
||||
m_Units.erase(it);
|
||||
return;
|
||||
}
|
||||
it = m_FormationControllers.find(ent);
|
||||
if (it != m_FormationControllers.end())
|
||||
m_FormationControllers.erase(it);
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::OnTurnStart()
|
||||
{
|
||||
for (EntityMap<MotionState>::value_type& data : m_FormationControllers)
|
||||
data.second.cmpUnitMotion->OnTurnStart();
|
||||
|
||||
for (EntityMap<MotionState>::value_type& data : m_Units)
|
||||
data.second.cmpUnitMotion->OnTurnStart();
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::MoveUnits(fixed dt)
|
||||
{
|
||||
Move(m_Units, dt);
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::MoveFormations(fixed dt)
|
||||
{
|
||||
Move(m_FormationControllers, dt);
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::Move(EntityMap<MotionState>& ents, fixed dt)
|
||||
{
|
||||
m_MovingUnits.clear();
|
||||
for (EntityMap<MotionState>::iterator it = ents.begin(); it != ents.end(); ++it)
|
||||
{
|
||||
it->second.cmpUnitMotion->PreMove(it->second);
|
||||
if (!it->second.needUpdate)
|
||||
continue;
|
||||
m_MovingUnits.push_back(it);
|
||||
it->second.initialPos = it->second.cmpPosition->GetPosition2D();
|
||||
it->second.initialAngle = it->second.cmpPosition->GetRotation().Y;
|
||||
it->second.pos = it->second.initialPos;
|
||||
it->second.angle = it->second.initialAngle;
|
||||
}
|
||||
|
||||
for (EntityMap<MotionState>::iterator& it : m_MovingUnits)
|
||||
it->second.cmpUnitMotion->Move(it->second, dt);
|
||||
|
||||
for (EntityMap<MotionState>::iterator& it : m_MovingUnits)
|
||||
it->second.cmpUnitMotion->PostMove(it->second, dt);
|
||||
}
|
||||
|
||||
|
||||
REGISTER_COMPONENT_TYPE(UnitMotionManager)
|
@ -48,6 +48,14 @@ class CCmpUnitMotionScripted : public ICmpUnitMotion
|
||||
public:
|
||||
DEFAULT_SCRIPT_WRAPPER(UnitMotionScripted)
|
||||
|
||||
private:
|
||||
virtual void OnTurnStart() {};
|
||||
virtual void PreMove(ICmpUnitMotionManager::MotionState&) {};
|
||||
virtual void Move(ICmpUnitMotionManager::MotionState&, fixed) {};
|
||||
virtual void PostMove(ICmpUnitMotionManager::MotionState&, fixed) {};
|
||||
|
||||
public:
|
||||
|
||||
virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
|
||||
{
|
||||
return m_Script.Call<bool>("MoveToPointRange", x, z, minRange, maxRange);
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
#include "simulation2/components/ICmpPathfinder.h" // for pass_class_t
|
||||
#include "simulation2/components/ICmpPosition.h" // for entity_pos_t
|
||||
#include "simulation2/components/ICmpUnitMotionManager.h"
|
||||
|
||||
class CCmpUnitMotionManager;
|
||||
|
||||
/**
|
||||
* Motion interface for entities with complex movement capabilities.
|
||||
@ -33,6 +36,17 @@
|
||||
*/
|
||||
class ICmpUnitMotion : public IComponent
|
||||
{
|
||||
friend class CCmpUnitMotionManager;
|
||||
protected:
|
||||
/**
|
||||
* This external interface is used by the Unit Motion Manager.
|
||||
* Components that do not register there do not need to implement these.
|
||||
*/
|
||||
virtual void OnTurnStart() = 0;
|
||||
virtual void PreMove(ICmpUnitMotionManager::MotionState& state) = 0;
|
||||
virtual void Move(ICmpUnitMotionManager::MotionState& state, fixed dt) = 0;
|
||||
virtual void PostMove(ICmpUnitMotionManager::MotionState& state, fixed dt) = 0;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
|
25
source/simulation2/components/ICmpUnitMotionManager.cpp
Normal file
25
source/simulation2/components/ICmpUnitMotionManager.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ICmpUnitMotionManager.h"
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(UnitMotionManager)
|
||||
END_INTERFACE_WRAPPER(UnitMotionManager)
|
63
source/simulation2/components/ICmpUnitMotionManager.h
Normal file
63
source/simulation2/components/ICmpUnitMotionManager.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ICMPUNITMOTIONMANAGER
|
||||
#define INCLUDED_ICMPUNITMOTIONMANAGER
|
||||
|
||||
#include "simulation2/system/Interface.h"
|
||||
|
||||
class ICmpPosition;
|
||||
class ICmpUnitMotion;
|
||||
|
||||
class ICmpUnitMotionManager : public IComponent
|
||||
{
|
||||
public:
|
||||
// Persisted state for each unit.
|
||||
struct MotionState
|
||||
{
|
||||
// Component references - these must be kept alive for the duration of motion.
|
||||
CmpPtr<ICmpPosition> cmpPosition;
|
||||
CmpPtr<ICmpUnitMotion> cmpUnitMotion;
|
||||
|
||||
// Position before units start moving
|
||||
CFixedVector2D initialPos;
|
||||
// Transient position during the movement.
|
||||
CFixedVector2D pos;
|
||||
|
||||
fixed initialAngle;
|
||||
fixed angle;
|
||||
|
||||
// If true, the entity needs to be handled during movement.
|
||||
bool needUpdate;
|
||||
|
||||
// 'Leak' from UnitMotion.
|
||||
bool wentStraight;
|
||||
bool wasObstructed;
|
||||
};
|
||||
|
||||
virtual void Register(entity_id_t ent, bool formationController) = 0;
|
||||
virtual void Unregister(entity_id_t ent) = 0;
|
||||
|
||||
/**
|
||||
* True if entities are currently in the "Move" phase.
|
||||
*/
|
||||
virtual bool ComputingMotion() const = 0;
|
||||
|
||||
DECLARE_INTERFACE_TYPE(UnitMotionManager)
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPUNITMOTIONMANAGER
|
@ -677,6 +677,7 @@ void CComponentManager::AddSystemComponents(bool skipScriptedComponents, bool sk
|
||||
AddComponent(m_SystemEntity, CID_SoundManager, noParam);
|
||||
AddComponent(m_SystemEntity, CID_Terrain, noParam);
|
||||
AddComponent(m_SystemEntity, CID_TerritoryManager, noParam);
|
||||
AddComponent(m_SystemEntity, CID_UnitMotionManager, noParam);
|
||||
AddComponent(m_SystemEntity, CID_UnitRenderer, noParam);
|
||||
AddComponent(m_SystemEntity, CID_WaterManager, noParam);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user