Ticket #2319: Physics.patch
File Physics.patch, 13.7 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/template_unit.xml
21 21 <DelayTime>80.0</DelayTime> 22 22 <SinkRate>0.01</SinkRate> 23 23 <SinkAccel>0.0</SinkAccel> 24 <DecayType>physics</DecayType> 25 <PhysicsParameters> 26 <GroundFriction>0.1</GroundFriction> 27 <AirFriction>0.2</AirFriction> 28 <Weight>50.0</Weight> 29 </PhysicsParameters> 24 30 </Decay> 25 31 <Footprint> 26 32 <Circle radius="1.5"/> -
binaries/data/mods/public/simulation/helpers/Damage.js
51 51 warn("The " + data.shape + " splash damage shape is not implemented!"); 52 52 } 53 53 // Call CauseDamage which reduces the hitpoints, posts network command, plays sounds.... 54 Damage.CauseDamage({"strengths":data.strengths, "target":entity, "attacker":data.attacker, "multiplier":damageMultiplier, "type":data.type + ".Splash" })54 Damage.CauseDamage({"strengths":data.strengths, "target":entity, "attacker":data.attacker, "multiplier":damageMultiplier, "type":data.type + ".Splash", "origin" : data.origin }) 55 55 } 56 56 }; 57 57 … … 62 62 * data.attacker = <entity id> 63 63 * data.multiplier = <float between 1 and 0> 64 64 * data.type = <string> 65 * data.origin = {'x':<int>, 'z':<int>} 65 66 */ 66 67 Damage.CauseDamage = function(data) 67 68 { … … 78 79 if (targetState.killed) 79 80 Damage.TargetKilled(data.attacker, data.target); 80 81 82 if (targetState.corpse) 83 { 84 if (data.type.search("Splash") !== -1) 85 { 86 var cmpDecay = Engine.QueryInterface(targetState.corpse, IID_Decay); 87 if (cmpDecay) 88 { 89 var cmpEPos = Engine.QueryInterface(data.target, IID_Position); 90 var pos = [cmpEPos.GetPosition().x-data["origin"].x,cmpEPos.GetPosition().z-data["origin"].z]; 91 cmpDecay.ApplyForce(pos[0]*4.0,10.0,pos[1]*4.0); 92 } 93 } 94 } 95 81 96 // Post the network command (make it work in multiplayer) 82 97 Engine.PostMessage(data.target, MT_Attacked, {"attacker":data.attacker, "target":data.target, "type":data.type, "damage":-targetState.change}); 83 98 -
binaries/data/mods/public/simulation/components/Health.js
150 150 */ 151 151 Health.prototype.Reduce = function(amount) 152 152 { 153 var state = { "killed": false };153 var state = { "killed": false ,"corpse" : undefined }; 154 154 if (amount >= 0 && this.hitpoints == this.GetMaxHitpoints()) 155 155 { 156 156 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); … … 175 175 176 176 if (this.template.DeathType == "corpse") 177 177 { 178 this.CreateCorpse();178 state.corpse = this.CreateCorpse(); 179 179 Engine.DestroyEntity(this.entity); 180 180 } 181 181 else if (this.template.DeathType == "vanish") -
source/simulation2/components/ICmpPosition.h
105 105 virtual bool IsFloating() = 0; 106 106 107 107 /** 108 * Set whether an entity floats on water 109 */ 110 virtual void SetFloating(bool newValue) = 0; 111 112 /** 108 113 * Returns the current x,y,z position (no interpolation). 109 114 * Depends on the current terrain heightmap. 110 115 * Must not be called unless IsInWorld is true. -
source/simulation2/components/ICmpDecay.h
26 26 class ICmpDecay : public IComponent 27 27 { 28 28 public: 29 // adds directly to the fake physics "force". 30 virtual void ApplyForce(float x, float y, float z) = 0; 31 29 32 DECLARE_INTERFACE_TYPE(Decay) 30 33 }; 31 34 -
source/simulation2/components/CCmpDecay.cpp
25 25 #include "ICmpPosition.h" 26 26 #include "ICmpTerrain.h" 27 27 #include "ICmpVisual.h" 28 #include "ICmpWaterManager.h" 28 29 29 30 /** 30 31 * Fairly basic decay implementation, for units and buildings etc. … … 49 50 { 50 51 componentManager.SubscribeToMessageType(MT_Interpolate); 51 52 } 53 54 enum { 55 DECAY_CLASSIC = 0, 56 DECAY_SHIP = 1, 57 DECAY_PHYSICS = 2 58 }; 52 59 53 60 DEFAULT_COMPONENT_ALLOCATOR(Decay) 54 61 55 62 bool m_Active; 56 bool m_ShipSink; 63 bool m_ReallyInited; 64 uint8_t m_DecayType; 65 57 66 float m_DelayTime; 58 67 float m_SinkRate; 59 68 float m_SinkAccel; 60 69 70 // for physics decay only 71 CVector3D m_Force; 72 float m_GroundFriction; // a fake friction, so that a round object might roll down a hill but a human probably won't. 73 float m_AirFriction; // note that values range [0..1] for both frictions where 1 means none and 0 means total stop. 74 float m_Weight; 75 CFixedVector3D m_PositionOneSecAgo; // to check if we should go into basic decay. 76 float m_LastPositionCheck; 77 78 // for ship-like sinking only 61 79 entity_pos_t m_InitialXRotation; 62 80 entity_pos_t m_InitialZRotation; 63 64 // Used to randomize ship-like sinking65 81 float m_SinkingAngleX; 66 82 float m_SinkingAngleZ; 67 83 … … 86 102 "</element>" 87 103 "</optional>" 88 104 "<optional>" 89 "<element name='SinkingAnim' a:help='If this element is present, the entity will decay in a ship-like manner'>" 90 "<empty/>" 105 "<element name='DecayType' a:help='You can choose from three different behaviors for decaying.'>" 106 "<choice>" 107 "<value a:help='Decay straight into the ground after an optional delay. Default value.'>classic</value>" 108 "<value a:help='Sink like a ship would.'>ship</value>" 109 "<value a:help='Fly in the air before decaying classically.'>physics</value>" 110 "</choice>" 91 111 "</element>" 112 "</optional>" 113 "<optional>" 114 "<element name='PhysicsParameters' a:help='Parameters for the physics if decay type is \"physics\".'>" 115 "<interleave>" 116 "<element name='GroundFriction' a:help='How to dampen the movement when hitting the ground. 1 is complete stop, 0 is none at all. Values higher than 1 will react weirdly.'>" 117 "<ref name='nonNegativeDecimal'/>" 118 "</element>" 119 "<element name='AirFriction' a:help='How to dampen the movement in the air. 1 is complete stop, 0 is none at all. Values higher than 1 might lead to weird behavior.'>" 120 "<ref name='nonNegativeDecimal'/>" 121 "</element>" 122 "<element name='Weight' a:help='How much this unit is affected by gravity.'>" 123 "<ref name='nonNegativeDecimal'/>" 124 "</element>" 125 "</interleave>" 126 "</element>" 92 127 "</optional>"; 93 128 } 94 129 95 130 virtual void Init(const CParamNode& paramNode) 96 131 { 97 132 m_Active = !paramNode.GetChild("Inactive").IsOk(); 98 m_ShipSink = paramNode.GetChild("SinkingAnim").IsOk(); 133 134 if (!paramNode.GetChild("DecayType").IsOk() || paramNode.GetChild("DecayType").ToString() == L"classic") 135 m_DecayType = DECAY_CLASSIC; 136 else if(paramNode.GetChild("DecayType").ToString() == L"ship") 137 m_DecayType = DECAY_SHIP; 138 else if(paramNode.GetChild("DecayType").ToString() == L"physics") 139 { 140 m_DecayType = DECAY_PHYSICS; 141 if (!paramNode.GetChild("PhysicsParameters").IsOk()) 142 { 143 debug_warn(L"CCmpDecay in physics mode without physics parameters"); 144 m_Active = false; 145 } 146 else 147 { 148 m_Force = CVector3D(); 149 m_GroundFriction = paramNode.GetChild("PhysicsParameters").GetChild("GroundFriction").ToFloat(); 150 m_AirFriction = paramNode.GetChild("PhysicsParameters").GetChild("AirFriction").ToFloat(); 151 m_Weight = paramNode.GetChild("PhysicsParameters").GetChild("Weight").ToFloat(); 152 } 153 } 99 154 m_DelayTime = paramNode.GetChild("DelayTime").ToFixed().ToFloat(); 100 155 m_SinkRate = paramNode.GetChild("SinkRate").ToFixed().ToFloat(); 101 156 m_SinkAccel = paramNode.GetChild("SinkAccel").ToFixed().ToFloat(); 102 157 103 158 m_CurrentTime = 0.f; 104 m_ TotalSinkDepth = -1.f;159 m_ReallyInited = false; 105 160 106 161 // Detect unsafe misconfiguration 107 162 if (m_Active && !ENTITY_IS_LOCAL(GetEntityId())) … … 144 199 break; 145 200 } 146 201 202 CFixedVector3D pos = cmpPosition->GetPosition(); 203 147 204 // Compute the depth the first time this is called 148 205 // (This is a bit of an ugly place to do it but at least we'll be sure 149 206 // the actor component was loaded already) 150 if ( m_TotalSinkDepth < 0.f)207 if (!m_ReallyInited) 151 208 { 209 m_ReallyInited = true; 152 210 m_TotalSinkDepth = 1.f; // minimum so we always sink at least a little 153 211 154 212 CmpPtr<ICmpVisual> cmpVisual(GetEntityHandle()); … … 161 219 // If this is a floating unit, we want it to sink all the way under the terrain, 162 220 // so find the difference between its current position and the terrain 163 221 164 CFixedVector3D pos = cmpPosition->GetPosition();165 222 166 223 CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); 167 224 if (cmpTerrain) … … 171 228 } 172 229 173 230 // Sink it further down if it sinks like a ship, as it will rotate. 174 if (m_ ShipSink)231 if (m_DecayType == DECAY_SHIP) 175 232 { 176 233 // lacking randomness we'll trick 177 234 m_SinkingAngleX = (pos.X.ToInt_RoundToNearest() % 30 - 15) / 15.0; 178 235 m_SinkingAngleZ = (pos.Z.ToInt_RoundToNearest() % 30) / 40.0; 179 236 m_TotalSinkDepth += 10.f; 237 238 // probably 0 in both cases but we'll remember it anyway. 239 m_InitialXRotation = cmpPosition->GetRotation().X; 240 m_InitialZRotation = cmpPosition->GetRotation().Z; 180 241 } 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 242 } 185 243 186 244 m_CurrentTime += msgData.deltaSimTime; 187 245 188 if (m_ CurrentTime >= m_DelayTime)246 if (m_DecayType == DECAY_PHYSICS) 189 247 { 248 // decay our force and apply it 249 CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); 250 CmpPtr<ICmpWaterManager> cmpWaterMgr(GetSystemEntity()); 251 252 pos.X += fixed::FromFloat(m_Force.X*msgData.deltaSimTime); 253 pos.Y += fixed::FromFloat(m_Force.Y*msgData.deltaSimTime); 254 pos.Z += fixed::FromFloat(m_Force.Z*msgData.deltaSimTime); 255 256 float groundLevel = cmpTerrain->GetExactGroundLevel(pos.X.ToFloat(),pos.Z.ToFloat()); 257 float waterLevel = cmpWaterMgr->GetExactWaterLevel(pos.X.ToFloat(),pos.Z.ToFloat()); 258 259 m_Force.Y -= m_Weight * 0.2f * msgData.deltaSimTime; 260 261 if (pos.Y.ToFloat() < waterLevel) 262 { 263 // just die. 264 m_DecayType = DECAY_CLASSIC; 265 m_ReallyInited = false; 266 267 cmpPosition->SetFloating(true); 268 m_DelayTime = m_CurrentTime-1; 269 m_SinkRate = 0.1; 270 m_SinkAccel = 0.1; 271 m_LastPositionCheck = m_CurrentTime; // avoids an update. 272 } 273 else if (pos.Y.ToFloat() > groundLevel) 274 { 275 // just fly 276 m_Force.X -= m_Force.X * m_AirFriction*msgData.deltaSimTime; 277 m_Force.Y -= m_Force.Y * m_AirFriction*msgData.deltaSimTime; 278 m_Force.Z -= m_Force.Z * m_AirFriction*msgData.deltaSimTime; 279 } 280 else 281 { 282 // we've hit the ground 283 CVector3D normal = cmpTerrain->CalcExactNormal(pos.X.ToFloat(),pos.Z.ToFloat()); 284 float length = m_Force.Length(); 285 m_Force *= 1.0f/length; 286 // reflect the force, losing some speed in the process. 287 float dot = m_Force.Dot(normal); 288 float dampen = (1.0f-(m_GroundFriction-dot)); 289 if (dampen < 0.0f) 290 dampen = 0.0f; 291 m_Force = (normal * -2 * dot + m_Force) * dampen * length; 292 293 pos.Y = fixed::FromFloat(groundLevel); 294 } 295 // checked if we stopped moving. 296 if (m_CurrentTime - m_LastPositionCheck > 1) 297 { 298 if ((m_PositionOneSecAgo-pos).Length().ToFloat() < 0.5f) 299 { 300 m_DecayType = DECAY_CLASSIC; 301 m_DelayTime += m_CurrentTime; 302 m_ReallyInited = false; 303 } 304 m_PositionOneSecAgo = pos; 305 m_LastPositionCheck = m_CurrentTime; 306 } 307 cmpPosition->MoveTo(pos.X,pos.Z); 308 cmpPosition->SetHeightFixed(pos.Y); 309 } 310 else if (m_CurrentTime >= m_DelayTime) 311 { 190 312 float t = m_CurrentTime - m_DelayTime; 191 313 float depth = (m_SinkRate * t) + (m_SinkAccel * t * t); 192 314 193 if (m_ ShipSink)315 if (m_DecayType == DECAY_SHIP) 194 316 { 195 317 // exponential sinking with tilting 196 318 float tilt_time = t > 5.f ? 5.f : t; … … 203 325 if (depth < 0.f) 204 326 depth = 0.f; 205 327 } 206 207 328 cmpPosition->SetHeightOffset(entity_pos_t::FromFloat(-depth)); 208 329 209 330 if (depth > m_TotalSinkDepth) … … 214 335 } 215 336 } 216 337 } 338 339 virtual void ApplyForce(float x, float y, float z) 340 { 341 m_Force.X += x; 342 m_Force.Y += y; 343 m_Force.Z += z; 344 } 345 217 346 }; 218 347 219 348 REGISTER_COMPONENT_TYPE(Decay) -
source/simulation2/components/ICmpDecay.cpp
22 22 #include "simulation2/system/InterfaceScripted.h" 23 23 24 24 BEGIN_INTERFACE_WRAPPER(Decay) 25 DEFINE_INTERFACE_METHOD_3("ApplyForce", void, ICmpDecay, ApplyForce, float, float, float) 25 26 END_INTERFACE_WRAPPER(Decay) -
source/simulation2/components/CCmpPosition.cpp
310 310 return m_Floating; 311 311 } 312 312 313 virtual void SetFloating(bool newValue) 314 { 315 m_Floating = newValue; 316 } 317 313 318 virtual CFixedVector3D GetPosition() 314 319 { 315 320 if (!m_InWorld)