Ticket #2319: Physics.patch

File Physics.patch, 13.7 KB (added by wraitii, 10 years ago)
  • binaries/data/mods/public/simulation/templates/template_unit.xml

     
    2121    <DelayTime>80.0</DelayTime>
    2222    <SinkRate>0.01</SinkRate>
    2323    <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>
    2430  </Decay>
    2531  <Footprint>
    2632    <Circle radius="1.5"/>
  • binaries/data/mods/public/simulation/helpers/Damage.js

     
    5151            warn("The " + data.shape + " splash damage shape is not implemented!");
    5252        }
    5353        // 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 })
    5555    }
    5656};
    5757
     
    6262 * data.attacker = <entity id>
    6363 * data.multiplier = <float between 1 and 0>
    6464 * data.type = <string>
     65 * data.origin = {'x':<int>, 'z':<int>}
    6566 */
    6667Damage.CauseDamage = function(data)
    6768{
     
    7879    if (targetState.killed)
    7980        Damage.TargetKilled(data.attacker, data.target);
    8081
     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   
    8196    // Post the network command (make it work in multiplayer)
    8297    Engine.PostMessage(data.target, MT_Attacked, {"attacker":data.attacker, "target":data.target, "type":data.type, "damage":-targetState.change});
    8398
  • binaries/data/mods/public/simulation/components/Health.js

     
    150150 */
    151151Health.prototype.Reduce = function(amount)
    152152{
    153     var state = { "killed": false };
     153    var state = { "killed": false ,"corpse" : undefined };
    154154    if (amount >= 0 && this.hitpoints == this.GetMaxHitpoints())
    155155    {
    156156        var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     
    175175
    176176            if (this.template.DeathType == "corpse")
    177177            {
    178                 this.CreateCorpse();
     178                state.corpse = this.CreateCorpse();
    179179                Engine.DestroyEntity(this.entity);
    180180            }
    181181            else if (this.template.DeathType == "vanish")
  • source/simulation2/components/ICmpPosition.h

     
    105105    virtual bool IsFloating() = 0;
    106106
    107107    /**
     108     * Set whether an entity floats on water
     109     */
     110    virtual void SetFloating(bool newValue) = 0;
     111
     112    /**
    108113     * Returns the current x,y,z position (no interpolation).
    109114     * Depends on the current terrain heightmap.
    110115     * Must not be called unless IsInWorld is true.
  • source/simulation2/components/ICmpDecay.h

     
    2626class ICmpDecay : public IComponent
    2727{
    2828public:
     29    // adds directly to the fake physics "force".
     30    virtual void ApplyForce(float x, float y, float z) = 0;
     31   
    2932    DECLARE_INTERFACE_TYPE(Decay)
    3033};
    3134
  • source/simulation2/components/CCmpDecay.cpp

     
    2525#include "ICmpPosition.h"
    2626#include "ICmpTerrain.h"
    2727#include "ICmpVisual.h"
     28#include "ICmpWaterManager.h"
    2829
    2930/**
    3031 * Fairly basic decay implementation, for units and buildings etc.
     
    4950    {
    5051        componentManager.SubscribeToMessageType(MT_Interpolate);
    5152    }
     53   
     54    enum {
     55        DECAY_CLASSIC = 0,
     56        DECAY_SHIP = 1,
     57        DECAY_PHYSICS = 2
     58    };
    5259
    5360    DEFAULT_COMPONENT_ALLOCATOR(Decay)
    5461
    5562    bool m_Active;
    56     bool m_ShipSink;
     63    bool m_ReallyInited;
     64    uint8_t m_DecayType;
     65   
    5766    float m_DelayTime;
    5867    float m_SinkRate;
    5968    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
    6179    entity_pos_t m_InitialXRotation;
    6280    entity_pos_t m_InitialZRotation;
    63 
    64     // Used to randomize ship-like sinking
    6581    float m_SinkingAngleX;
    6682    float m_SinkingAngleZ;
    6783
     
    86102                "</element>"
    87103            "</optional>"
    88104            "<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>"
    91111                "</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>"
    92127            "</optional>";
    93128    }
    94129
    95130    virtual void Init(const CParamNode& paramNode)
    96131    {
    97132        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        }
    99154        m_DelayTime = paramNode.GetChild("DelayTime").ToFixed().ToFloat();
    100155        m_SinkRate = paramNode.GetChild("SinkRate").ToFixed().ToFloat();
    101156        m_SinkAccel = paramNode.GetChild("SinkAccel").ToFixed().ToFloat();
    102157
    103158        m_CurrentTime = 0.f;
    104         m_TotalSinkDepth = -1.f;
     159        m_ReallyInited = false;
    105160
    106161        // Detect unsafe misconfiguration
    107162        if (m_Active && !ENTITY_IS_LOCAL(GetEntityId()))
     
    144199                break;
    145200            }
    146201
     202            CFixedVector3D pos = cmpPosition->GetPosition();
     203
    147204            // Compute the depth the first time this is called
    148205            // (This is a bit of an ugly place to do it but at least we'll be sure
    149206            // the actor component was loaded already)
    150             if (m_TotalSinkDepth < 0.f)
     207            if (!m_ReallyInited)
    151208            {
     209                m_ReallyInited = true;
    152210                m_TotalSinkDepth = 1.f; // minimum so we always sink at least a little
    153211
    154212                CmpPtr<ICmpVisual> cmpVisual(GetEntityHandle());
     
    161219                // If this is a floating unit, we want it to sink all the way under the terrain,
    162220                // so find the difference between its current position and the terrain
    163221
    164                 CFixedVector3D pos = cmpPosition->GetPosition();
    165222
    166223                CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
    167224                if (cmpTerrain)
     
    171228                }
    172229
    173230                // Sink it further down if it sinks like a ship, as it will rotate.
    174                 if (m_ShipSink)
     231                if (m_DecayType == DECAY_SHIP)
    175232                {
    176233                    // lacking randomness we'll trick
    177234                    m_SinkingAngleX = (pos.X.ToInt_RoundToNearest() % 30 - 15) / 15.0;
    178235                    m_SinkingAngleZ = (pos.Z.ToInt_RoundToNearest() % 30) / 40.0;
    179236                    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;
    180241                }
    181                 // probably 0 in both cases but we'll remember it anyway.
    182                 m_InitialXRotation = cmpPosition->GetRotation().X;
    183                 m_InitialZRotation = cmpPosition->GetRotation().Z;
    184242            }
    185243
    186244            m_CurrentTime += msgData.deltaSimTime;
    187245
    188             if (m_CurrentTime >= m_DelayTime)
     246            if (m_DecayType == DECAY_PHYSICS)
    189247            {
     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            {
    190312                float t = m_CurrentTime - m_DelayTime;
    191313                float depth = (m_SinkRate * t) + (m_SinkAccel * t * t);
    192314
    193                 if (m_ShipSink)
     315                if (m_DecayType == DECAY_SHIP)
    194316                {
    195317                    // exponential sinking with tilting
    196318                    float tilt_time = t > 5.f ? 5.f : t;
     
    203325                    if (depth < 0.f)
    204326                        depth = 0.f;
    205327                }
    206                
    207328                cmpPosition->SetHeightOffset(entity_pos_t::FromFloat(-depth));
    208329
    209330                if (depth > m_TotalSinkDepth)
     
    214335        }
    215336        }
    216337    }
     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
    217346};
    218347
    219348REGISTER_COMPONENT_TYPE(Decay)
  • source/simulation2/components/ICmpDecay.cpp

     
    2222#include "simulation2/system/InterfaceScripted.h"
    2323
    2424BEGIN_INTERFACE_WRAPPER(Decay)
     25DEFINE_INTERFACE_METHOD_3("ApplyForce", void, ICmpDecay, ApplyForce, float, float, float)
    2526END_INTERFACE_WRAPPER(Decay)
  • source/simulation2/components/CCmpPosition.cpp

     
    310310        return m_Floating;
    311311    }
    312312
     313    virtual void SetFloating(bool newValue)
     314    {
     315        m_Floating = newValue;
     316    }
     317
    313318    virtual CFixedVector3D GetPosition()
    314319    {
    315320        if (!m_InWorld)