Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpVisualActor.cpp
Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
class CCmpVisualActor : public ICmpVisual | class CCmpVisualActor : public ICmpVisual | ||||
{ | { | ||||
public: | public: | ||||
static void ClassInit(CComponentManager& componentManager) | static void ClassInit(CComponentManager& componentManager) | ||||
{ | { | ||||
componentManager.SubscribeToMessageType(MT_Update_Final); | |||||
componentManager.SubscribeToMessageType(MT_InterpolatedPositionChanged); | componentManager.SubscribeToMessageType(MT_InterpolatedPositionChanged); | ||||
componentManager.SubscribeToMessageType(MT_OwnershipChanged); | componentManager.SubscribeToMessageType(MT_OwnershipChanged); | ||||
componentManager.SubscribeToMessageType(MT_ValueModification); | componentManager.SubscribeToMessageType(MT_ValueModification); | ||||
componentManager.SubscribeToMessageType(MT_TerrainChanged); | componentManager.SubscribeToMessageType(MT_TerrainChanged); | ||||
componentManager.SubscribeToMessageType(MT_Destroy); | componentManager.SubscribeToMessageType(MT_Destroy); | ||||
} | } | ||||
DEFAULT_COMPONENT_ALLOCATOR(VisualActor) | DEFAULT_COMPONENT_ALLOCATOR(VisualActor) | ||||
private: | private: | ||||
std::wstring m_BaseActorName, m_ActorName; | std::wstring m_BaseActorName, m_ActorName; | ||||
bool m_IsFoundationActor; | bool m_IsFoundationActor; | ||||
CUnit* m_Unit; | CUnit* m_Unit; | ||||
fixed m_R, m_G, m_B; // shading color | fixed m_R, m_G, m_B; // shading color | ||||
std::map<std::string, std::string> m_AnimOverride; | |||||
// Current animation state | // Current animation state | ||||
fixed m_AnimRunThreshold; // if non-zero this is the special walk/run mode | |||||
std::string m_AnimName; | std::string m_AnimName; | ||||
bool m_AnimOnce; | bool m_AnimOnce; | ||||
fixed m_AnimSpeed; | fixed m_AnimSpeed; | ||||
std::wstring m_SoundGroup; | std::wstring m_SoundGroup; | ||||
fixed m_AnimDesync; | fixed m_AnimDesync; | ||||
fixed m_AnimSyncRepeatTime; // 0.0 if not synced | fixed m_AnimSyncRepeatTime; | ||||
fixed m_AnimSyncOffsetTime; | fixed m_AnimSyncOffsetTime; | ||||
std::string m_MovingPrefix; | |||||
fixed m_MovingSpeed; | |||||
std::map<CStr, CStr> m_VariantSelections; | std::map<CStr, CStr> m_VariantSelections; | ||||
u32 m_Seed; // seed used for random variations | u32 m_Seed; // seed used for random variations | ||||
bool m_ConstructionPreview; | bool m_ConstructionPreview; | ||||
bool m_VisibleInAtlasOnly; | bool m_VisibleInAtlasOnly; | ||||
bool m_IsActorOnly; // an in-world entity should not have this or it might not be rendered. | bool m_IsActorOnly; // an in-world entity should not have this or it might not be rendered. | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | return | ||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>"; | "</element>"; | ||||
} | } | ||||
virtual void Init(const CParamNode& paramNode) | virtual void Init(const CParamNode& paramNode) | ||||
{ | { | ||||
m_Unit = NULL; | m_Unit = NULL; | ||||
m_R = m_G = m_B = fixed::FromInt(1); | m_R = m_G = m_B = fixed::FromInt(1); | ||||
m_MovingSpeed = fixed::FromInt(1); | |||||
m_ConstructionPreview = paramNode.GetChild("ConstructionPreview").IsOk(); | m_ConstructionPreview = paramNode.GetChild("ConstructionPreview").IsOk(); | ||||
m_Seed = GetEntityId(); | m_Seed = GetEntityId(); | ||||
m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk(); | m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk(); | ||||
if (m_IsFoundationActor) | if (m_IsFoundationActor) | ||||
m_BaseActorName = m_ActorName = paramNode.GetChild("FoundationActor").ToString(); | m_BaseActorName = m_ActorName = paramNode.GetChild("FoundationActor").ToString(); | ||||
Show All 19 Lines | public: | ||||
template<typename S> | template<typename S> | ||||
void SerializeCommon(S& serialize) | void SerializeCommon(S& serialize) | ||||
{ | { | ||||
serialize.NumberFixed_Unbounded("r", m_R); | serialize.NumberFixed_Unbounded("r", m_R); | ||||
serialize.NumberFixed_Unbounded("g", m_G); | serialize.NumberFixed_Unbounded("g", m_G); | ||||
serialize.NumberFixed_Unbounded("b", m_B); | serialize.NumberFixed_Unbounded("b", m_B); | ||||
SerializeMap<SerializeString, SerializeString>()(serialize, "anim overrides", m_AnimOverride); | |||||
serialize.NumberFixed_Unbounded("anim run threshold", m_AnimRunThreshold); | |||||
serialize.StringASCII("anim name", m_AnimName, 0, 256); | serialize.StringASCII("anim name", m_AnimName, 0, 256); | ||||
serialize.Bool("anim once", m_AnimOnce); | serialize.Bool("anim once", m_AnimOnce); | ||||
serialize.NumberFixed_Unbounded("anim speed", m_AnimSpeed); | serialize.NumberFixed_Unbounded("anim speed", m_AnimSpeed); | ||||
serialize.String("sound group", m_SoundGroup, 0, 256); | serialize.String("sound group", m_SoundGroup, 0, 256); | ||||
serialize.NumberFixed_Unbounded("anim desync", m_AnimDesync); | serialize.NumberFixed_Unbounded("anim desync", m_AnimDesync); | ||||
serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime); | serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime); | ||||
serialize.NumberFixed_Unbounded("anim sync offset time", m_AnimSyncOffsetTime); | serialize.NumberFixed_Unbounded("anim sync offset time", m_AnimSyncOffsetTime); | ||||
serialize.NumberFixed_Unbounded("anim moving speed", m_MovingSpeed); | |||||
serialize.StringASCII("anim moving prefix", m_MovingPrefix, 0, 256); | |||||
SerializeMap<SerializeString, SerializeString>()(serialize, "variation", m_VariantSelections); | SerializeMap<SerializeString, SerializeString>()(serialize, "variation", m_VariantSelections); | ||||
serialize.NumberU32_Unbounded("seed", m_Seed); | serialize.NumberU32_Unbounded("seed", m_Seed); | ||||
serialize.String("actor", m_ActorName, 0, 256); | serialize.String("actor", m_ActorName, 0, 256); | ||||
// TODO: store actor variables? | // TODO: store actor variables? | ||||
} | } | ||||
Show All 30 Lines | if (m_Unit) | ||||
m_Unit->GetModel().SetPlayerID(cmpOwnership->GetOwner()); | m_Unit->GetModel().SetPlayerID(cmpOwnership->GetOwner()); | ||||
} | } | ||||
} | } | ||||
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
{ | { | ||||
switch (msg.GetType()) | switch (msg.GetType()) | ||||
{ | { | ||||
case MT_Update_Final: | |||||
{ | |||||
const CMessageUpdate_Final& msgData = static_cast<const CMessageUpdate_Final&> (msg); | |||||
Update(msgData.turnLength); | |||||
break; | |||||
} | |||||
case MT_OwnershipChanged: | case MT_OwnershipChanged: | ||||
{ | { | ||||
if (!m_Unit) | if (!m_Unit) | ||||
break; | break; | ||||
const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); | const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); | ||||
m_Unit->GetModel().SetPlayerID(msgData.to); | m_Unit->GetModel().SetPlayerID(msgData.to); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | public: | ||||
virtual std::string GetAnimationName() const | virtual std::string GetAnimationName() const | ||||
{ | { | ||||
return m_AnimName; | return m_AnimName; | ||||
} | } | ||||
virtual void SelectAnimation(const std::string& name, bool once = false, fixed speed = fixed::FromInt(1)) | virtual void SelectAnimation(const std::string& name, bool once = false, fixed speed = fixed::FromInt(1)) | ||||
{ | { | ||||
m_AnimRunThreshold = fixed::Zero(); | |||||
m_AnimName = name; | m_AnimName = name; | ||||
m_AnimOnce = once; | m_AnimOnce = once; | ||||
m_AnimSpeed = speed; | m_AnimSpeed = speed; | ||||
m_SoundGroup = L""; | m_SoundGroup = L""; | ||||
m_AnimDesync = fixed::FromInt(1)/20; // TODO: make this an argument | m_AnimDesync = fixed::FromInt(1)/20; // TODO: make this an argument | ||||
m_AnimSyncRepeatTime = fixed::Zero(); | m_AnimSyncRepeatTime = fixed::Zero(); | ||||
m_AnimSyncOffsetTime = fixed::Zero(); | m_AnimSyncOffsetTime = fixed::Zero(); | ||||
SetVariant("animation", m_AnimName); | // TODO: change this once we support walk/run-anims | ||||
std::string animName = name; | |||||
/*if (!m_MovingPrefix.empty() && m_AnimName != "idle") | |||||
animName = m_MovingPrefix + "-" + m_AnimName; | |||||
else */if (!m_MovingPrefix.empty()) | |||||
animName = m_MovingPrefix; | |||||
if (!m_Unit || !m_Unit->GetAnimation() || !m_Unit->GetID()) | if (!m_Unit || !m_Unit->GetAnimation() || !m_Unit->GetID()) | ||||
return; | return; | ||||
CmpPtr<ICmpSound> cmpSound(GetSimContext(), m_Unit->GetID()); | CmpPtr<ICmpSound> cmpSound(GetSimContext(), m_Unit->GetID()); | ||||
if (cmpSound) | if (cmpSound) | ||||
m_SoundGroup = cmpSound->GetSoundGroup(wstring_from_utf8(m_AnimName)); | m_SoundGroup = cmpSound->GetSoundGroup(wstring_from_utf8(m_AnimName)); | ||||
m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed.ToFloat(), m_AnimDesync.ToFloat(), m_SoundGroup.c_str()); | SetVariant("animation", animName); | ||||
} | |||||
virtual void ReplaceMoveAnimation(const std::string& name, const std::string& replace) | if (m_Unit && m_Unit->GetAnimation()) | ||||
{ | m_Unit->GetAnimation()->SetAnimationState(animName, m_AnimOnce, m_MovingSpeed.Multiply(m_AnimSpeed).ToFloat(), m_AnimDesync.ToFloat(), m_SoundGroup.c_str()); | ||||
m_AnimOverride[name] = replace; | |||||
} | } | ||||
virtual void ResetMoveAnimation(const std::string& name) | virtual void SetMovingSpeed(fixed movingSpeed) | ||||
{ | { | ||||
std::map<std::string, std::string>::const_iterator it = m_AnimOverride.find(name); | // TODO: don't copy strings for fun. | ||||
if (it != m_AnimOverride.end()) | std::string prefix; | ||||
m_AnimOverride.erase(name); | if (movingSpeed.IsZero()) | ||||
prefix = ""; | |||||
else | |||||
{ | |||||
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetEntityHandle()); | |||||
if (!cmpUnitMotion) | |||||
return; | |||||
prefix = cmpUnitMotion->GetSpeedRatio() <= fixed::FromInt(1) ? "walk" : "run"; | |||||
} | } | ||||
m_MovingPrefix = prefix; | |||||
m_MovingSpeed = movingSpeed.IsZero() ? fixed::FromInt(1) : movingSpeed; | |||||
virtual void SelectMovementAnimation(fixed runThreshold) | SelectAnimation(m_AnimName, m_AnimOnce, m_AnimSpeed); | ||||
{ | |||||
m_AnimRunThreshold = runThreshold; | |||||
} | } | ||||
virtual void SetAnimationSyncRepeat(fixed repeattime) | virtual void SetAnimationSyncRepeat(fixed repeattime) | ||||
{ | { | ||||
m_AnimSyncRepeatTime = repeattime; | m_AnimSyncRepeatTime = repeattime; | ||||
if (m_Unit && m_Unit->GetAnimation()) | if (m_Unit && m_Unit->GetAnimation()) | ||||
m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime.ToFloat()); | m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime.ToFloat()); | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | private: | ||||
/// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init. | /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init. | ||||
void InitSelectionShapeDescriptor(const CParamNode& paramNode); | void InitSelectionShapeDescriptor(const CParamNode& paramNode); | ||||
// ReloadActor is used when the actor or seed changes. | // ReloadActor is used when the actor or seed changes. | ||||
void ReloadActor(); | void ReloadActor(); | ||||
// ReloadUnitAnimation is used for a minimal reloading upon deserialization, when the actor and seed are identical. | // ReloadUnitAnimation is used for a minimal reloading upon deserialization, when the actor and seed are identical. | ||||
// It is also used by ReloadActor. | // It is also used by ReloadActor. | ||||
void ReloadUnitAnimation(); | void ReloadUnitAnimation(); | ||||
void Update(fixed turnLength); | |||||
}; | }; | ||||
REGISTER_COMPONENT_TYPE(VisualActor) | REGISTER_COMPONENT_TYPE(VisualActor) | ||||
// ------------------------------------------------------------------------------------------------------------------ | // ------------------------------------------------------------------------------------------------------------------ | ||||
void CCmpVisualActor::InitModel(const CParamNode& paramNode) | void CCmpVisualActor::InitModel(const CParamNode& paramNode) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | void CCmpVisualActor::ReloadUnitAnimation() | ||||
// We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate | // We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate | ||||
if (!m_AnimSyncRepeatTime.IsZero()) | if (!m_AnimSyncRepeatTime.IsZero()) | ||||
m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime.ToFloat()); | m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime.ToFloat()); | ||||
if (!m_AnimSyncOffsetTime.IsZero()) | if (!m_AnimSyncOffsetTime.IsZero()) | ||||
m_Unit->GetAnimation()->SetAnimationSyncOffset(m_AnimSyncOffsetTime.ToFloat()); | m_Unit->GetAnimation()->SetAnimationSyncOffset(m_AnimSyncOffsetTime.ToFloat()); | ||||
} | } | ||||
void CCmpVisualActor::Update(fixed UNUSED(turnLength)) | |||||
{ | |||||
// This function is currently only used to update the animation if the speed in | |||||
// CCmpUnitMotion changes. This also only happens in the "special movement mode" | |||||
// triggered by SelectMovementAnimation. | |||||
// TODO: This should become event based, in order to save performance and to make the code | |||||
// far less hacky. We should also take into account the speed when the animation is different | |||||
// from the "special movement mode" walking animation. | |||||
// If we're not in the special movement mode, nothing to do. | |||||
if (m_AnimRunThreshold.IsZero()) | |||||
return; | |||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | |||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | |||||
return; | |||||
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetEntityHandle()); | |||||
if (!cmpUnitMotion) | |||||
return; | |||||
fixed speed = cmpUnitMotion->GetCurrentSpeed(); | |||||
wraitii: This is bad because it introduces coupling between Visual Actor and unitMotion. And it needs… | |||||
std::string name; | |||||
if (speed.IsZero()) | |||||
{ | |||||
speed = fixed::FromFloat(1.f); | |||||
name = "idle"; | |||||
} | |||||
else | |||||
name = speed < m_AnimRunThreshold ? "walk" : "run"; | |||||
std::map<std::string, std::string>::const_iterator it = m_AnimOverride.find(name); | |||||
if (it != m_AnimOverride.end()) | |||||
name = it->second; | |||||
// Selecting the animation is going to reset the anim run threshold, so save it | |||||
fixed runThreshold = m_AnimRunThreshold; | |||||
SelectAnimation(name, false, speed); | |||||
m_AnimRunThreshold = runThreshold; | |||||
} |
Wildfire Games · Phabricator
This is bad because it introduces coupling between Visual Actor and unitMotion. And it needs one to listen to Update messages.
In D13 UnitMotion calls visual actor directly to update the speed, which is faster and also less coupled (though Visual actor still calls UnitMotion to get the walk/run speed difference, this could be removed.)
You'll also note that since this doesn't call any of the UnitMotion state, but relies on M_CurrentSpeed, we have the explanation for the STATE_STOPPING hackiness.