forked from mirrors/0ad
Let units take time actual time for turning while moving. This limits the possibility of "dancing" (making short moves to avoid being hit by arrows) beyond only patrolling.
Reviewed By: wraitii Gameplay Tests By: FeldFeld Comments By: Freagarach, Angen Differential Revision: D2837 refs: #5106 This was SVN commit r24415.
This commit is contained in:
@@ -859,36 +859,18 @@ Formation.prototype.GetRealOffsetPositions = function(offsets, pos)
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the estimated rotation of the formation
|
||||
* based on the first unitAI target position when ordered to walk,
|
||||
* based on the current rotation in other cases.
|
||||
* Calculate the estimated rotation of the formation based on the current rotation.
|
||||
* Return the sine and cosine of the angle.
|
||||
*/
|
||||
Formation.prototype.GetEstimatedOrientation = function(pos)
|
||||
{
|
||||
let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
|
||||
let r = { "sin": 0, "cos": 1 };
|
||||
let unitAIState = cmpUnitAI.GetCurrentState();
|
||||
if (unitAIState == "FORMATIONCONTROLLER.WALKING" || unitAIState == "FORMATIONCONTROLLER.COMBAT.APPROACHING")
|
||||
{
|
||||
let targetPos = cmpUnitAI.GetTargetPositions();
|
||||
if (!targetPos.length)
|
||||
return r;
|
||||
let d = targetPos[0].sub(pos).normalize();
|
||||
if (!d.x && !d.y)
|
||||
return r;
|
||||
r.cos = d.y;
|
||||
r.sin = d.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!cmpPosition)
|
||||
return r;
|
||||
let rot = cmpPosition.GetRotation().y;
|
||||
r.sin = Math.sin(rot);
|
||||
r.cos = Math.cos(rot);
|
||||
}
|
||||
let r = {};
|
||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!cmpPosition)
|
||||
return r;
|
||||
let rot = cmpPosition.GetRotation().y;
|
||||
r.sin = Math.sin(rot);
|
||||
r.cos = Math.cos(rot);
|
||||
return r;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<Altitude>-1</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>true</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>5.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>5</TurnRate>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<Overlay>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<Visibility>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>1.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>1</TurnRate>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<EditorOnly/>
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>3.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>3</TurnRate>
|
||||
</Position>
|
||||
<Trader>
|
||||
<GainMultiplier>0.75</GainMultiplier>
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<Overlay>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<Visibility>
|
||||
<RetainInFog>true</RetainInFog>
|
||||
|
||||
@@ -74,8 +74,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<ProductionQueue>
|
||||
<BatchTimeModifier>1.0</BatchTimeModifier>
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<EditorOnly/>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
<Altitude>0</Altitude>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<EditorOnly/>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<Anchor>pitch</Anchor>
|
||||
<Floating>false</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>6.0</TurnRate>
|
||||
<TurnRate>6</TurnRate>
|
||||
</Position>
|
||||
<RangeOverlayManager/>
|
||||
<RangeOverlayRenderer/>
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
<stone>0</stone>
|
||||
<metal>0</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>4</TurnRate>
|
||||
</Position>
|
||||
<Promotion>
|
||||
<RequiredXp>150</RequiredXp>
|
||||
</Promotion>
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
<wood>8</wood>
|
||||
<metal>10</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>4</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
<Damage>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<food>30</food>
|
||||
<metal>20</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
<Damage>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<Loot>
|
||||
<xp>260</xp>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Promotion>
|
||||
<RequiredXp>150</RequiredXp>
|
||||
</Promotion>
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
<Type>food</Type>
|
||||
<Color r="227" g="130" b="141"/>
|
||||
</Minimap>
|
||||
<Position>
|
||||
<TurnRate>4</TurnRate>
|
||||
</Position>
|
||||
<ResourceGatherer disable=""/>
|
||||
<Selectable>
|
||||
<Overlay>
|
||||
|
||||
+3
@@ -27,6 +27,9 @@
|
||||
<Loot>
|
||||
<xp>50</xp>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
<Damage>
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
special/formations/wedge
|
||||
</Formations>
|
||||
</Identity>
|
||||
<Position>
|
||||
<TurnRate>4</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
<Damage>
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
<Identity>
|
||||
<VisibleClasses datatype="tokens">Elephant Melee</VisibleClasses>
|
||||
</Identity>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
<Damage>
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
<Position>
|
||||
<Anchor>upright</Anchor>
|
||||
<Floating>true</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<TurnRate>3.0</TurnRate>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>3</TurnRate>
|
||||
</Position>
|
||||
<Repairable>
|
||||
<RepairTimeRatio>4.0</RepairTimeRatio>
|
||||
|
||||
@@ -66,6 +66,9 @@
|
||||
<wood>40</wood>
|
||||
<metal>30</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<ResourceGatherer disable=""/>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
<wood>30</wood>
|
||||
<metal>20</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<ResourceGatherer disable=""/>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
</Loot>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Repairable>
|
||||
<RepairTimeRatio>4.0</RepairTimeRatio>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
</Loot>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
<TurnRate>2</TurnRate>
|
||||
</Position>
|
||||
<Resistance>
|
||||
<Entity>
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
<Obstruction disable=""/>
|
||||
<Position>
|
||||
<Anchor>upright</Anchor>
|
||||
<TurnRate>1.0</TurnRate>
|
||||
<Floating>true</Floating>
|
||||
<FloatDepth>0.0</FloatDepth>
|
||||
<FloatDepth>0</FloatDepth>
|
||||
<TurnRate>1</TurnRate>
|
||||
</Position>
|
||||
<Repairable>
|
||||
<RepairTimeRatio>3.0</RepairTimeRatio>
|
||||
|
||||
@@ -70,7 +70,8 @@ public:
|
||||
bool m_Floating;
|
||||
entity_pos_t m_FloatDepth;
|
||||
|
||||
float m_RotYSpeed; // maximum radians per second, used by InterpolatedRotY to follow RotY
|
||||
// Maximum radians per second, used by InterpolatedRotY to follow RotY and the unitMotion.
|
||||
fixed m_RotYSpeed;
|
||||
|
||||
// Dynamic state:
|
||||
|
||||
@@ -129,7 +130,7 @@ public:
|
||||
"<element name='FloatDepth' a:help='The depth at which an entity floats on water (needs Floating to be true)'>"
|
||||
"<ref name='nonNegativeDecimal'/>"
|
||||
"</element>"
|
||||
"<element name='TurnRate' a:help='Maximum graphical rotation speed around Y axis, in radians per second'>"
|
||||
"<element name='TurnRate' a:help='Maximum rotation speed around Y axis, in radians per second. Used for all graphical rotations and some real unitMotion driven rotations.'>"
|
||||
"<ref name='positiveDecimal'/>"
|
||||
"</element>";
|
||||
}
|
||||
@@ -154,7 +155,7 @@ public:
|
||||
m_Floating = paramNode.GetChild("Floating").ToBool();
|
||||
m_FloatDepth = paramNode.GetChild("FloatDepth").ToFixed();
|
||||
|
||||
m_RotYSpeed = paramNode.GetChild("TurnRate").ToFixed().ToFloat();
|
||||
m_RotYSpeed = paramNode.GetChild("TurnRate").ToFixed();
|
||||
|
||||
m_RotX = m_RotY = m_RotZ = entity_angle_t::FromInt(0);
|
||||
m_InterpolatedRotX = m_InterpolatedRotY = m_InterpolatedRotZ = 0.f;
|
||||
@@ -189,6 +190,7 @@ public:
|
||||
serialize.NumberFixed_Unbounded("rot x", m_RotX);
|
||||
serialize.NumberFixed_Unbounded("rot y", m_RotY);
|
||||
serialize.NumberFixed_Unbounded("rot z", m_RotZ);
|
||||
serialize.NumberFixed_Unbounded("rot y speed", m_RotYSpeed);
|
||||
serialize.NumberFixed_Unbounded("altitude", m_Y);
|
||||
serialize.Bool("relative", m_RelativeToGround);
|
||||
serialize.Bool("floating", m_Floating);
|
||||
@@ -246,6 +248,7 @@ public:
|
||||
deserialize.NumberFixed_Unbounded("rot x", m_RotX);
|
||||
deserialize.NumberFixed_Unbounded("rot y", m_RotY);
|
||||
deserialize.NumberFixed_Unbounded("rot z", m_RotZ);
|
||||
deserialize.NumberFixed_Unbounded("rot y speed", m_RotYSpeed);
|
||||
deserialize.NumberFixed_Unbounded("altitude", m_Y);
|
||||
deserialize.Bool("relative", m_RelativeToGround);
|
||||
deserialize.Bool("floating", m_Floating);
|
||||
@@ -536,6 +539,11 @@ public:
|
||||
return CFixedVector2D(m_PrevX, m_PrevZ);
|
||||
}
|
||||
|
||||
virtual fixed GetTurnRate() const
|
||||
{
|
||||
return m_RotYSpeed;
|
||||
}
|
||||
|
||||
virtual void TurnTo(entity_angle_t y)
|
||||
{
|
||||
if (m_TurretParent != INVALID_ENTITY)
|
||||
@@ -780,13 +788,14 @@ public:
|
||||
|
||||
if (rotY != m_InterpolatedRotY)
|
||||
{
|
||||
float rotYSpeed = m_RotYSpeed.ToFloat();
|
||||
float delta = rotY - m_InterpolatedRotY;
|
||||
// Wrap delta to -M_PI..M_PI
|
||||
delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI
|
||||
if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI
|
||||
delta -= (float)M_PI; // range -M_PI..M_PI
|
||||
// Clamp to max rate
|
||||
float deltaClamped = Clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime);
|
||||
float deltaClamped = Clamp(delta, -rotYSpeed*msgData.deltaSimTime, +rotYSpeed*msgData.deltaSimTime);
|
||||
// Calculate new orientation, in a peculiar way in order to make sure the
|
||||
// result gets close to m_orientation (rather than being n*2*M_PI out)
|
||||
m_InterpolatedRotY = rotY + deltaClamped - delta;
|
||||
|
||||
@@ -616,7 +616,7 @@ private:
|
||||
* This does not send actually change the position.
|
||||
* @returns true if the move was obstructed.
|
||||
*/
|
||||
bool PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos) const;
|
||||
bool PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, entity_angle_t& angle);
|
||||
|
||||
/**
|
||||
* Update other components on our speed.
|
||||
@@ -872,28 +872,33 @@ void CCmpUnitMotion::Move(fixed dt)
|
||||
return;
|
||||
|
||||
CFixedVector2D initialPos = cmpPosition->GetPosition2D();
|
||||
entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
|
||||
|
||||
// Keep track of the current unit's position during the update
|
||||
// Keep track of the current unit's position and rotation during the update.
|
||||
CFixedVector2D pos = initialPos;
|
||||
entity_angle_t angle = initialAngle;
|
||||
|
||||
// If we're chasing a potentially-moving unit and are currently close
|
||||
// enough to its current position, and we can head in a straight line
|
||||
// to it, then throw away our current path and go straight to it
|
||||
bool wentStraight = TryGoingStraightToTarget(initialPos);
|
||||
|
||||
bool wasObstructed = PerformMove(dt, m_ShortPath, m_LongPath, pos);
|
||||
bool wasObstructed = PerformMove(dt, cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, pos, angle);
|
||||
|
||||
// Update our speed over this turn so that the visual actor shows the correct animation.
|
||||
if (pos == initialPos)
|
||||
{
|
||||
if (angle != initialAngle)
|
||||
cmpPosition->TurnTo(angle);
|
||||
UpdateMovementState(fixed::Zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the Position component after our movement (if we actually moved anywhere)
|
||||
// When moving always set the angle in the direction of the movement.
|
||||
CFixedVector2D offset = pos - initialPos;
|
||||
|
||||
// Face towards the target
|
||||
entity_angle_t angle = atan2_approx(offset.X, offset.Y);
|
||||
cmpPosition->MoveAndTurnTo(pos.X,pos.Y, angle);
|
||||
angle = atan2_approx(offset.X, offset.Y);
|
||||
cmpPosition->MoveAndTurnTo(pos.X, pos.Y, angle);
|
||||
|
||||
// Calculate the mean speed over this past turn.
|
||||
UpdateMovementState(offset.Length() / dt);
|
||||
@@ -942,12 +947,18 @@ bool CCmpUnitMotion::PossiblyAtDestination() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCmpUnitMotion::PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos) const
|
||||
bool CCmpUnitMotion::PerformMove(fixed dt, const fixed& turnRate, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos, entity_angle_t& angle)
|
||||
{
|
||||
// If there are no waypoint, behave as though we were obstructed and let HandleObstructedMove handle it.
|
||||
if (shortPath.m_Waypoints.empty() && longPath.m_Waypoints.empty())
|
||||
return true;
|
||||
|
||||
// Wrap the angle to (-Pi, Pi].
|
||||
while (angle > entity_angle_t::Pi())
|
||||
angle -= entity_angle_t::Pi() * 2;
|
||||
while (angle < -entity_angle_t::Pi())
|
||||
angle += entity_angle_t::Pi() * 2;
|
||||
|
||||
// TODO: there's some asymmetry here when units look at other
|
||||
// units' positions - the result will depend on the order of execution.
|
||||
// Maybe we should split the updates into multiple phases to minimise
|
||||
@@ -957,26 +968,24 @@ bool CCmpUnitMotion::PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath
|
||||
ENSURE(cmpPathfinder);
|
||||
|
||||
fixed basicSpeed = m_Speed;
|
||||
// If in formation, run to keep up; otherwise just walk
|
||||
// If in formation, run to keep up; otherwise just walk.
|
||||
if (IsFormationMember())
|
||||
basicSpeed = m_Speed.Multiply(m_RunMultiplier);
|
||||
|
||||
// Find the speed factor of the underlying terrain
|
||||
// Find the speed factor of the underlying terrain.
|
||||
// (We only care about the tile we start on - it doesn't matter if we're moving
|
||||
// partially onto a much slower/faster tile)
|
||||
// TODO: Terrain-dependent speeds are not currently supported
|
||||
// partially onto a much slower/faster tile).
|
||||
// TODO: Terrain-dependent speeds are not currently supported.
|
||||
fixed terrainSpeed = fixed::FromInt(1);
|
||||
|
||||
fixed maxSpeed = basicSpeed.Multiply(terrainSpeed);
|
||||
|
||||
// We want to move (at most) maxSpeed*dt units from pos towards the next waypoint
|
||||
|
||||
fixed timeLeft = dt;
|
||||
fixed zero = fixed::Zero();
|
||||
|
||||
while (timeLeft > zero)
|
||||
{
|
||||
// If we ran out of path, we have to stop
|
||||
// If we ran out of path, we have to stop.
|
||||
if (shortPath.m_Waypoints.empty() && longPath.m_Waypoints.empty())
|
||||
break;
|
||||
|
||||
@@ -987,11 +996,37 @@ bool CCmpUnitMotion::PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath
|
||||
target = CFixedVector2D(shortPath.m_Waypoints.back().x, shortPath.m_Waypoints.back().z);
|
||||
|
||||
CFixedVector2D offset = target - pos;
|
||||
if (turnRate > zero)
|
||||
{
|
||||
fixed maxRotation = turnRate.Multiply(timeLeft);
|
||||
fixed angleDiff = angle - atan2_approx(offset.X, offset.Y);
|
||||
if (angleDiff != zero)
|
||||
{
|
||||
fixed absoluteAngleDiff = angleDiff.Absolute();
|
||||
if (absoluteAngleDiff > entity_angle_t::Pi())
|
||||
absoluteAngleDiff = entity_angle_t::Pi() * 2 - absoluteAngleDiff;
|
||||
|
||||
// Work out how far we can travel in timeLeft
|
||||
// Figure out whether rotating will increase or decrease the angle, and how far we need to rotate in that direction.
|
||||
int direction = (entity_angle_t::Zero() < angleDiff && angleDiff <= entity_angle_t::Pi()) || angleDiff < -entity_angle_t::Pi() ? -1 : 1;
|
||||
|
||||
// Can't rotate far enough, just rotate in the correct direction.
|
||||
if (absoluteAngleDiff > maxRotation)
|
||||
{
|
||||
angle += maxRotation * direction;
|
||||
if (angle * direction > entity_angle_t::Pi())
|
||||
angle -= entity_angle_t::Pi() * 2 * direction;
|
||||
break;
|
||||
}
|
||||
// Rotate towards the next waypoint and continue moving.
|
||||
angle = atan2_approx(offset.X, offset.Y);
|
||||
timeLeft = (maxRotation - absoluteAngleDiff) / turnRate;
|
||||
}
|
||||
}
|
||||
|
||||
// Work out how far we can travel in timeLeft.
|
||||
fixed maxdist = maxSpeed.Multiply(timeLeft);
|
||||
|
||||
// If the target is close, we can move there directly
|
||||
// If the target is close, we can move there directly.
|
||||
fixed offsetLength = offset.Length();
|
||||
if (offsetLength <= maxdist)
|
||||
{
|
||||
@@ -999,7 +1034,7 @@ bool CCmpUnitMotion::PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath
|
||||
{
|
||||
pos = target;
|
||||
|
||||
// Spend the rest of the time heading towards the next waypoint
|
||||
// Spend the rest of the time heading towards the next waypoint.
|
||||
timeLeft = (maxdist - offsetLength) / maxSpeed;
|
||||
|
||||
if (shortPath.m_Waypoints.empty())
|
||||
@@ -1011,13 +1046,13 @@ bool CCmpUnitMotion::PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error - path was obstructed
|
||||
// Error - path was obstructed.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not close enough, so just move in the right direction
|
||||
// Not close enough, so just move in the right direction.
|
||||
offset.Normalize(maxdist);
|
||||
target = pos + offset;
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ DEFINE_INTERFACE_METHOD_CONST_0("GetPosition", CFixedVector3D, ICmpPosition, Get
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetPosition2D", CFixedVector2D, ICmpPosition, GetPosition2D)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetPreviousPosition", CFixedVector3D, ICmpPosition, GetPreviousPosition)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetPreviousPosition2D", CFixedVector2D, ICmpPosition, GetPreviousPosition2D)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetTurnRate", fixed, ICmpPosition, GetTurnRate)
|
||||
DEFINE_INTERFACE_METHOD_1("TurnTo", void, ICmpPosition, TurnTo, entity_angle_t)
|
||||
DEFINE_INTERFACE_METHOD_1("SetYRotation", void, ICmpPosition, SetYRotation, entity_angle_t)
|
||||
DEFINE_INTERFACE_METHOD_2("SetXZRotation", void, ICmpPosition, SetXZRotation, entity_angle_t, entity_angle_t)
|
||||
|
||||
@@ -184,6 +184,11 @@ public:
|
||||
*/
|
||||
virtual CFixedVector2D GetPreviousPosition2D() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the turn rate in radians per second.
|
||||
*/
|
||||
virtual fixed GetTurnRate() const = 0;
|
||||
|
||||
/**
|
||||
* Rotate smoothly to the given angle around the upwards axis.
|
||||
* @param y clockwise radians from the +Z axis.
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
virtual CFixedVector2D GetPosition2D() const { return CFixedVector2D(m_Pos.X, m_Pos.Z); }
|
||||
virtual CFixedVector3D GetPreviousPosition() const { return CFixedVector3D(); }
|
||||
virtual CFixedVector2D GetPreviousPosition2D() const { return CFixedVector2D(); }
|
||||
virtual fixed GetTurnRate() const { return fixed::Zero(); }
|
||||
virtual void TurnTo(entity_angle_t UNUSED(y)) { }
|
||||
virtual void SetYRotation(entity_angle_t UNUSED(y)) { }
|
||||
virtual void SetXZRotation(entity_angle_t UNUSED(x), entity_angle_t UNUSED(z)) { }
|
||||
|
||||
Reference in New Issue
Block a user