Index: binaries/data/mods/public/simulation/components/Formation.js
===================================================================
--- binaries/data/mods/public/simulation/components/Formation.js
+++ binaries/data/mods/public/simulation/components/Formation.js
@@ -378,6 +378,10 @@
}
this.ComputeMotionParameters();
+
+ if (!this.rearrange)
+ return;
+
this.MoveMembersIntoFormation(true, true);
};
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js
+++ binaries/data/mods/public/simulation/components/UnitAI.js
@@ -240,7 +240,15 @@
this.FinishOrder();
return;
}
-
+let cmpPhysics = Engine.QueryInterface(this.entity, IID_Physics);
+if (cmpPhysics)
+{
+ cmpPhysics.SetActive(true);
+ cmpPhysics.ApplyForce(0, 750, 0);
+ //let cmpPos = Engine.QueryInterface(this.entity, IID_Position);
+ //if (cmpPos)
+ // cmpPos.SetHeightFixed(50);
+}
// Stop moving immediately.
this.StopMoving();
this.FinishOrder();
Index: binaries/data/mods/public/simulation/templates/template_unit.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit.xml
+++ binaries/data/mods/public/simulation/templates/template_unit.xml
@@ -71,6 +71,15 @@
+
+ false
+ 0.5
+ 9.81
+ 0.5
+ 75
+ 1000
+ 0
+
0
upright
Index: source/simulation2/TypeList.h
===================================================================
--- source/simulation2/TypeList.h
+++ source/simulation2/TypeList.h
@@ -132,6 +132,9 @@
INTERFACE(Pathfinder)
COMPONENT(Pathfinder)
+INTERFACE(Physics)
+COMPONENT(Physics)
+
INTERFACE(Player)
COMPONENT(PlayerScripted)
Index: source/simulation2/components/CCmpPhysics.cpp
===================================================================
--- /dev/null
+++ source/simulation2/components/CCmpPhysics.cpp
@@ -0,0 +1,259 @@
+/* Copyright (C) 2020 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 .
+ */
+
+#include "precompiled.h"
+
+#include "simulation2/system/Component.h"
+#include "ICmpPhysics.h"
+
+#include "simulation2/MessageTypes.h"
+
+#include "ICmpPosition.h"
+#include "ICmpTerrain.h"
+#include "ICmpWaterManager.h"
+
+#include "ps/Profile.h"
+
+/**
+ * Fairly basic physics implementation, for units and buildings etc.
+ */
+class CCmpPhysics : public ICmpPhysics
+{
+public:
+ static void ClassInit(CComponentManager& UNUSED(componentManager))
+ {
+ }
+
+ DEFAULT_COMPONENT_ALLOCATOR(Physics)
+
+ bool m_Active;
+
+ entity_pos_t m_AirFriction;
+ entity_pos_t m_GroundFriction;
+ entity_pos_t m_Gravity;
+ entity_pos_t m_Mass;
+ entity_pos_t m_MaxForce;
+ entity_pos_t m_MomentOfInertia;
+
+ CVector3D m_Velocity;
+ CVector3D m_Acceleration;
+
+ static std::string GetSchema()
+ {
+ return
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ "";
+ }
+
+ virtual void Init(const CParamNode& paramNode)
+ {
+ m_Active = paramNode.GetChild("Active").ToBool();
+
+ m_AirFriction = paramNode.GetChild("AirFriction").ToFixed();
+ m_GroundFriction = paramNode.GetChild("GroundFriction").ToFixed();
+ m_Gravity = paramNode.GetChild("Gravity").ToFixed();
+ m_Mass = paramNode.GetChild("Mass").ToFixed();
+ m_MaxForce = paramNode.GetChild("MaxForce").ToFixed();
+ m_MomentOfInertia = paramNode.GetChild("MomentOfInertia").ToFixed();
+
+ if (m_Active)
+ GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Update, this, true);
+ }
+
+ virtual void Deinit()
+ {
+ }
+
+ virtual void Serialize(ISerializer& serialize)
+ {
+ serialize.Bool("active", m_Active);
+
+ serialize.NumberFixed_Unbounded("frictionair", m_AirFriction);
+ serialize.NumberFixed_Unbounded("gravity", m_Gravity);
+ serialize.NumberFixed_Unbounded("frictionground", m_GroundFriction);
+ serialize.NumberFixed_Unbounded("mass", m_Mass);
+ serialize.NumberFixed_Unbounded("maxforce", m_MaxForce);
+ serialize.NumberFixed_Unbounded("momentofinertia", m_MomentOfInertia);
+
+ serialize.NumberFloat_Unbounded("velocityx", m_Velocity.X);
+ serialize.NumberFloat_Unbounded("velocityy", m_Velocity.Y);
+ serialize.NumberFloat_Unbounded("velocityz", m_Velocity.Z);
+
+ serialize.NumberFloat_Unbounded("accelerationx", m_Acceleration.X);
+ serialize.NumberFloat_Unbounded("accelerationy", m_Acceleration.Y);
+ serialize.NumberFloat_Unbounded("accelerationz", m_Acceleration.Z);
+ }
+
+ virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
+ {
+ Init(paramNode);
+
+ deserialize.Bool("active", m_Active);
+
+ deserialize.NumberFixed_Unbounded("frictionair", m_AirFriction);
+ deserialize.NumberFixed_Unbounded("gravity", m_Gravity);
+ deserialize.NumberFixed_Unbounded("frictionground", m_GroundFriction);
+ deserialize.NumberFixed_Unbounded("mass", m_Mass);
+ deserialize.NumberFixed_Unbounded("maxforce", m_MaxForce);
+ deserialize.NumberFixed_Unbounded("momentofinertia", m_MomentOfInertia);
+
+ deserialize.NumberFloat_Unbounded("velocityx", m_Velocity.X);
+ deserialize.NumberFloat_Unbounded("velocityy", m_Velocity.Y);
+ deserialize.NumberFloat_Unbounded("velocityz", m_Velocity.Z);
+
+ deserialize.NumberFloat_Unbounded("accelerationx", m_Acceleration.X);
+ deserialize.NumberFloat_Unbounded("accelerationy", m_Acceleration.Y);
+ deserialize.NumberFloat_Unbounded("accelerationz", m_Acceleration.Z);
+ }
+
+ virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
+ {
+ switch (msg.GetType())
+ {
+ case MT_Update:
+ {
+ PROFILE("Physics::Update");
+
+ if (!m_Active)
+ break;
+
+ Update(static_cast (msg).turnLength);
+
+ break;
+ }
+ }
+ }
+
+ void Update(fixed turnLength)
+ {
+ // When there is no net energy, there is nothing to do.
+ //if (m_Energy.X == 0 && m_Energy.Y == 0 && m_Energy.Z == 0)
+ // return;
+
+ // If there's no position don't do anything.
+ CmpPtr cmpPosition(GetEntityHandle());
+ if (!cmpPosition || !cmpPosition->IsInWorld())
+ return;
+ CVector3D initialPosition = cmpPosition->GetPosition();
+
+ float dt = turnLength.ToFloat();
+
+ CVector3D newPosition;
+
+ m_Velocity += m_Acceleration * dt;
+ newPosition = initialPosition + m_Velocity * dt;
+
+ CmpPtr cmpTerrain(GetSystemEntity());
+ CmpPtr cmpWaterMgr(GetSystemEntity());
+
+ float groundLevel = cmpTerrain->GetExactGroundLevel(newPosition.X, newPosition.Z);
+ float waterLevel = cmpWaterMgr->GetExactWaterLevel(newPosition.X, newPosition.Z);
+
+LOGERROR("%s", (fixed::FromFloat(m_Velocity.Y)).ToString());
+
+ // ToDo: Fix entities landing on water.
+ // They should just try to stand on the ground actually,
+ // unless they are dead, then they should float. So that should
+ // be done in CCmpDecay probably.
+ // However, when going too deep a unit should die.
+ if (newPosition.Y < waterLevel && waterLevel > groundLevel && m_Velocity.Y <= 0)
+ {
+ cmpPosition->SetFloating(true);
+
+ newPosition.Y = waterLevel;
+
+ // Drain all energy when landing on water.
+ m_Velocity *= 0;
+ m_Acceleration *= 0;
+ }
+ else if (newPosition.Y > groundLevel)
+ {
+ // Simplified Stokes' drag.
+ m_Acceleration.X -= abs(m_Velocity.X) * (m_AirFriction.ToFloat() / m_Mass.ToFloat());
+ m_Acceleration.Y -= abs(m_Velocity.Y) * (m_AirFriction.ToFloat() / m_Mass.ToFloat());
+ m_Acceleration.Z -= abs(m_Velocity.Z) * (m_AirFriction.ToFloat() / m_Mass.ToFloat());
+
+ // Gravity pull.
+ m_Velocity.Y -= m_Gravity.ToFloat() * dt;
+ }
+ else if (newPosition.Y <= groundLevel)
+ {
+ CVector3D normal = cmpTerrain->CalcExactNormal(newPosition.X, newPosition.Z);
+ float normalForce = m_Mass.ToFloat() * m_Gravity.ToFloat();
+
+ float length = m_Velocity.Length();
+ m_Velocity *= 1.0f / length;
+
+ // Reflect the force, losing some speed in the process.
+ float dotProduct = m_Velocity.Dot(normal);
+ float dampen = 1.0f - (m_GroundFriction.ToFloat() - dotProduct);
+ if (dampen < 0.0f)
+ dampen = 0.0f;
+
+ m_Velocity = (normal * -2 * dotProduct + m_Velocity) * dampen * length;
+
+ newPosition.Y = groundLevel;
+ }
+ else
+ {
+ // Nothing?
+ }
+
+ // We should check for collisions.
+
+ cmpPosition->MoveTo(entity_pos_t::FromFloat(newPosition.X), entity_pos_t::FromFloat(newPosition.Z));
+ cmpPosition->SetHeightFixed(entity_pos_t::FromFloat(newPosition.Y));
+ }
+
+ virtual void ApplyForce(float x, float y, float z)
+ {
+ // Correct for time force applies? What are nice values?
+ m_Acceleration.X += x / m_Mass.ToFloat();
+ m_Acceleration.Y += y / m_Mass.ToFloat();
+ m_Acceleration.Z += z / m_Mass.ToFloat();
+ }
+
+ virtual void SetActive(bool active)
+ {
+ if (active != m_Active)
+ {
+ GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Update, this, active);
+ m_Active = active;
+ }
+ }
+};
+
+REGISTER_COMPONENT_TYPE(Physics)
Index: source/simulation2/components/ICmpPhysics.h
===================================================================
--- /dev/null
+++ source/simulation2/components/ICmpPhysics.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2020 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 .
+ */
+
+#ifndef INCLUDED_ICMPPHYSICS
+#define INCLUDED_ICMPPHYSICS
+
+#include "simulation2/system/Interface.h"
+#include "simulation2/components/ICmpPosition.h" // for entity_pos_t
+
+/**
+ * Simple physics.
+ */
+class ICmpPhysics : public IComponent
+{
+public:
+ // Adds some force to the fake physics of this entity.
+ virtual void ApplyForce(float x, float y, float z) = 0;
+
+ // Set whether physics is active for this entity.
+ virtual void SetActive(bool active) = 0;
+
+ DECLARE_INTERFACE_TYPE(Physics)
+};
+
+#endif // INCLUDED_ICMPPHYSICS
Index: source/simulation2/components/ICmpPhysics.cpp
===================================================================
--- /dev/null
+++ source/simulation2/components/ICmpPhysics.cpp
@@ -0,0 +1,27 @@
+/* Copyright (C) 2020 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 .
+ */
+
+#include "precompiled.h"
+
+#include "ICmpPhysics.h"
+
+#include "simulation2/system/InterfaceScripted.h"
+
+BEGIN_INTERFACE_WRAPPER(Physics)
+DEFINE_INTERFACE_METHOD_3("ApplyForce", void, ICmpPhysics, ApplyForce, float, float, float)
+DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpPhysics, SetActive, bool)
+END_INTERFACE_WRAPPER(Physics)