Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CCmpDecay.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
21 #include "ICmpDecay.h"
22 
24 
25 #include "ICmpPosition.h"
26 #include "ICmpTerrain.h"
27 #include "ICmpVisual.h"
28 
29 /**
30  * Fairly basic decay implementation, for units and buildings etc.
31  * The decaying entity remains stationary for some time period, then falls downwards
32  * with some initial speed and some acceleration, until it has fully sunk.
33  * The sinking depth is determined from the actor's bounding box and the terrain.
34  *
35  * This currently doesn't work with entities whose ICmpPosition has an initial Y offset.
36  *
37  * This isn't very efficient (we'll store data and iterate every frame for every entity,
38  * not just for corpse entities) - it could be designed more optimally if that's a real problem.
39  *
40  * Eventually we might want to adjust the decay rate based on user configuration (low-spec
41  * machines could have fewer corpses), number of corpses, etc.
42  *
43  * Must not be used on network-synchronised entities, unless <Inactive> is present.
44  */
45 class CCmpDecay : public ICmpDecay
46 {
47 public:
48  static void ClassInit(CComponentManager& componentManager)
49  {
50  componentManager.SubscribeToMessageType(MT_Interpolate);
51  }
52 
54 
55  bool m_Active;
56  bool m_ShipSink;
57  float m_DelayTime;
58  float m_SinkRate;
59  float m_SinkAccel;
60 
63 
64  // Used to randomize ship-like sinking
67 
69  float m_TotalSinkDepth; // distance we need to sink (derived from bounding box), or -1 if undetermined
70 
71  static std::string GetSchema()
72  {
73  return
74  "<element name='DelayTime' a:help='Time to wait before starting to sink, in seconds'>"
75  "<ref name='nonNegativeDecimal'/>"
76  "</element>"
77  "<element name='SinkRate' a:help='Initial rate of sinking, in metres per second'>"
78  "<ref name='nonNegativeDecimal'/>"
79  "</element>"
80  "<element name='SinkAccel' a:help='Acceleration rate of sinking, in metres per second per second'>"
81  "<ref name='nonNegativeDecimal'/>"
82  "</element>"
83  "<optional>"
84  "<element name='Inactive' a:help='If this element is present, the entity will not do any decaying'>"
85  "<empty/>"
86  "</element>"
87  "</optional>"
88  "<optional>"
89  "<element name='SinkingAnim' a:help='If this element is present, the entity will decay in a ship-like manner'>"
90  "<empty/>"
91  "</element>"
92  "</optional>";
93  }
94 
95  virtual void Init(const CParamNode& paramNode)
96  {
97  m_Active = !paramNode.GetChild("Inactive").IsOk();
98  m_ShipSink = paramNode.GetChild("SinkingAnim").IsOk();
99  m_DelayTime = paramNode.GetChild("DelayTime").ToFixed().ToFloat();
100  m_SinkRate = paramNode.GetChild("SinkRate").ToFixed().ToFloat();
101  m_SinkAccel = paramNode.GetChild("SinkAccel").ToFixed().ToFloat();
102 
103  m_CurrentTime = 0.f;
104  m_TotalSinkDepth = -1.f;
105 
106  // Detect unsafe misconfiguration
108  {
109  debug_warn(L"CCmpDecay must not be used on non-local (network-synchronised) entities");
110  m_Active = false;
111  }
112  }
113 
114  virtual void Deinit()
115  {
116  }
117 
118  virtual void Serialize(ISerializer& UNUSED(serialize))
119  {
120  // This component isn't network-synchronised, so don't serialize anything
121  }
122 
123  virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize))
124  {
125  Init(paramNode);
126  }
127 
128  virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
129  {
130  switch (msg.GetType())
131  {
132  case MT_Interpolate:
133  {
134  if (!m_Active)
135  break;
136 
137  const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
138 
139  CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
140  if (!cmpPosition || !cmpPosition->IsInWorld())
141  {
142  // If there's no position (this usually shouldn't happen), destroy the unit immediately
144  break;
145  }
146 
147  // Compute the depth the first time this is called
148  // (This is a bit of an ugly place to do it but at least we'll be sure
149  // the actor component was loaded already)
150  if (m_TotalSinkDepth < 0.f)
151  {
152  m_TotalSinkDepth = 1.f; // minimum so we always sink at least a little
153 
154  CmpPtr<ICmpVisual> cmpVisual(GetEntityHandle());
155  if (cmpVisual)
156  {
157  CBoundingBoxAligned bound = cmpVisual->GetBounds();
158  m_TotalSinkDepth = std::max(m_TotalSinkDepth, bound[1].Y - bound[0].Y);
159  }
160 
161  // If this is a floating unit, we want it to sink all the way under the terrain,
162  // so find the difference between its current position and the terrain
163 
164  CFixedVector3D pos = cmpPosition->GetPosition();
165 
166  CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
167  if (cmpTerrain)
168  {
169  fixed ground = cmpTerrain->GetGroundLevel(pos.X, pos.Z);
170  m_TotalSinkDepth += std::max(0.f, (pos.Y - ground).ToFloat());
171  }
172 
173  // Sink it further down if it sinks like a ship, as it will rotate.
174  if (m_ShipSink)
175  {
176  // lacking randomness we'll trick
177  m_SinkingAngleX = (pos.X.ToInt_RoundToNearest() % 30 - 15) / 15.0;
178  m_SinkingAngleZ = (pos.Z.ToInt_RoundToNearest() % 30) / 40.0;
179  m_TotalSinkDepth += 10.f;
180  }
181  // probably 0 in both cases but we'll remember it anyway.
182  m_InitialXRotation = cmpPosition->GetRotation().X;
183  m_InitialZRotation = cmpPosition->GetRotation().Z;
184  }
185 
186  m_CurrentTime += msgData.deltaSimTime;
187 
188  if (m_CurrentTime >= m_DelayTime)
189  {
190  float t = m_CurrentTime - m_DelayTime;
191  float depth = (m_SinkRate * t) + (m_SinkAccel * t * t);
192 
193  if (m_ShipSink)
194  {
195  // exponential sinking with tilting
196  float tilt_time = t > 5.f ? 5.f : t;
197  float tiltSink = tilt_time * tilt_time / 5.f;
198  entity_pos_t RotX = entity_pos_t::FromFloat(((m_InitialXRotation.ToFloat() * (5.f - tiltSink)) + (m_SinkingAngleX * tiltSink)) / 5.f);
199  entity_pos_t RotZ = entity_pos_t::FromFloat(((m_InitialZRotation.ToFloat() * (3.f - tilt_time)) + (m_SinkingAngleZ * tilt_time)) / 3.f);
200  cmpPosition->SetXZRotation(RotX,RotZ);
201 
202  depth = m_SinkRate * (exp(t - 1.f) - 0.54881163609f) + (m_SinkAccel * exp(t - 4.f) - 0.01831563888f);
203  if (depth < 0.f)
204  depth = 0.f;
205  }
206 
207  cmpPosition->SetHeightOffset(entity_pos_t::FromFloat(-depth));
208 
209  if (depth > m_TotalSinkDepth)
211  }
212 
213  break;
214  }
215  }
216  }
217 };
218 
An entity initialisation parameter node.
Definition: ParamNode.h:112
void SubscribeToMessageType(MessageTypeId mtid)
Subscribe the current component type to the given message type.
A simple fixed-point number class.
Definition: Fixed.h:115
virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z)=0
float m_SinkingAngleX
Definition: CCmpDecay.cpp:65
entity_pos_t m_InitialZRotation
Definition: CCmpDecay.cpp:62
Definition: Decompose.h:22
#define REGISTER_COMPONENT_TYPE(cname)
Definition: Component.h:30
virtual void Init(const CParamNode &paramNode)
Definition: CCmpDecay.cpp:95
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
float m_SinkRate
Definition: CCmpDecay.cpp:58
#define ENTITY_IS_LOCAL(id)
Definition: Entity.h:60
bool IsOk() const
Returns true if this is a valid CParamNode, false if it represents a non-existent node...
Definition: ParamNode.cpp:193
float m_CurrentTime
Definition: CCmpDecay.cpp:68
Serialization interface; see serialization overview.
Definition: ISerializer.h:120
virtual CFixedVector3D GetRotation()=0
Returns the current rotation (relative to the upwards axis), as Euler angles with X=pitch...
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)
Definition: CCmpDecay.cpp:123
virtual bool IsInWorld()=0
Returns true if the entity currently exists at a defined position in the world.
float deltaSimTime
Elapsed simulation time since previous interpolate, in seconds.
Definition: MessageTypes.h:134
static void ClassInit(CComponentManager &componentManager)
Definition: CCmpDecay.cpp:48
CEntityHandle GetEntityHandle() const
Definition: IComponent.h:45
float m_SinkingAngleZ
Definition: CCmpDecay.cpp:66
fixed ToFixed() const
Parses the content of this node as a fixed-point number.
Definition: ParamNode.cpp:222
entity_id_t GetEntityId() const
Definition: IComponent.h:48
virtual int GetType() const =0
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none...
Definition: ParamNode.cpp:185
float m_DelayTime
Definition: CCmpDecay.cpp:57
float m_SinkAccel
Definition: CCmpDecay.cpp:59
float ToFloat() const
Convert to float. May be lossy - float can&#39;t represent all values.
Definition: Fixed.h:161
virtual void Deinit()
Definition: CCmpDecay.cpp:114
virtual void HandleMessage(const CMessage &msg, bool global)
Definition: CCmpDecay.cpp:128
entity_pos_t m_InitialXRotation
Definition: CCmpDecay.cpp:61
#define DEFAULT_COMPONENT_ALLOCATOR(cname)
Definition: Component.h:44
const CSimContext & GetSimContext() const
Definition: IComponent.h:52
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
bool m_ShipSink
Definition: CCmpDecay.cpp:56
CEntityHandle GetSystemEntity() const
Definition: IComponent.h:50
float m_TotalSinkDepth
Definition: CCmpDecay.cpp:69
virtual CFixedVector3D GetPosition()=0
Returns the current x,y,z position (no interpolation).
virtual CBoundingBoxAligned GetBounds()=0
Get the world-space bounding box of the object&#39;s visual representation.
static std::string GetSchema()
Definition: CCmpDecay.cpp:71
static CFixed FromFloat(float n)
Definition: Fixed.h:141
bool m_Active
Definition: CCmpDecay.cpp:55
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
void DestroyComponentsSoon(entity_id_t ent)
Destroys all the components belonging to the specified entity when FlushDestroyedComponents is called...
int ToInt_RoundToNearest() const
Definition: Fixed.h:190
Prepare for rendering a new frame (set up model positions etc).
Definition: MessageTypes.h:122
Animated corpse-decay.
Definition: ICmpDecay.h:26
Fairly basic decay implementation, for units and buildings etc.
Definition: CCmpDecay.cpp:45
virtual void SetHeightOffset(entity_pos_t dy)=0
Set the vertical offset above the terrain/water surface.
CComponentManager & GetComponentManager() const
Definition: SimContext.cpp:35
Deserialization interface; see serialization overview.
Definition: IDeserializer.h:34
virtual void SetXZRotation(entity_angle_t x, entity_angle_t z)=0
Rotate immediately to the given angles around the X (pitch) and Z (roll) axes.
virtual void Serialize(ISerializer &serialize)
Definition: CCmpDecay.cpp:118