mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 06:23:46 +00:00
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