1
0
forked from 0ad/0ad

Fix units chasing each other. Fixes #1537

This was SVN commit r14449.
This commit is contained in:
sanderd17 2013-12-30 16:07:19 +00:00
parent ddee36e0a8
commit 298115f4c5
7 changed files with 90 additions and 39 deletions

View File

@ -602,7 +602,7 @@ var UnitFsmSpec = {
"Order.ReturnResource": function(msg) {
// Try to move to the dropsite
if (this.MoveToTarget(this.order.data.target))
if (this.MoveToTargetRange(this.order.data.target, IID_ResourceGatherer))
{
// We've started walking to the target
this.SetNextState("INDIVIDUAL.RETURNRESOURCE.APPROACHING");
@ -1706,31 +1706,32 @@ var UnitFsmSpec = {
// Check the target is still alive and attackable
if (this.TargetIsAlive(target) && this.CanAttack(target, this.order.data.forceResponse || null))
{
// Check we can still reach the target
// If we are hunting, first update the target position of the gather order so we know where will be the killed animal
if (this.order.data.hunting && this.orderQueue[1] && this.orderQueue[1].data.lastPos)
{
var cmpPosition = Engine.QueryInterface(this.order.data.target, IID_Position);
if (cmpPosition && cmpPosition.IsInWorld())
{
// Store the initial position, so that we can find the rest of the herd later
if (!this.orderQueue[1].data.initPos)
this.orderQueue[1].data.initPos = this.orderQueue[1].data.lastPos;
this.orderQueue[1].data.lastPos = cmpPosition.GetPosition();
// We still know where the animal is, so we shouldn't give up before going there
this.orderQueue[1].data.secondTry = undefined;
}
}
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.lastAttacked = cmpTimer.GetTime() - msg.lateness;
this.FaceTowardsTarget(target);
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
cmpAttack.PerformAttack(this.order.data.attackType, target);
// Check we can still reach the target for the next attack
if (this.CheckTargetAttackRange(target, IID_Attack, this.order.data.attackType))
{
// If we are hunting, first update the target position of the gather order so we know where will be the killed animal
if (this.order.data.hunting && this.orderQueue[1] && this.orderQueue[1].data.lastPos)
{
var cmpPosition = Engine.QueryInterface(this.order.data.target, IID_Position);
if (cmpPosition && cmpPosition.IsInWorld())
{
// Store the initial position, so that we can find the rest of the herd later
if (!this.orderQueue[1].data.initPos)
this.orderQueue[1].data.initPos = this.orderQueue[1].data.lastPos;
this.orderQueue[1].data.lastPos = cmpPosition.GetPosition();
// We still know where the animal is, so we shouldn't give up before going there
this.orderQueue[1].data.secondTry = undefined;
}
}
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.lastAttacked = cmpTimer.GetTime() - msg.lateness;
this.FaceTowardsTarget(target);
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
cmpAttack.PerformAttack(this.order.data.attackType, target);
if (this.resyncAnimation)
{
this.SetAnimationSync(this.attackTimers.repeat, this.attackTimers.repeat);

View File

@ -11,7 +11,7 @@
<Pierce>10.0</Pierce>
<Crush>0.0</Crush>
<MaxRange>16.0</MaxRange>
<MinRange>0.0</MinRange>
<MinRange>20.0</MinRange>
<ProjectileSpeed>25.0</ProjectileSpeed>
<PrepareTime>900</PrepareTime>
<RepeatTime>1500</RepeatTime>

View File

@ -6,7 +6,6 @@
<Pierce>20.0</Pierce>
<Crush>0.0</Crush>
<MaxRange>56.0</MaxRange>
<MinRange>0.0</MinRange>
<ProjectileSpeed>75.0</ProjectileSpeed>
<PrepareTime>1200</PrepareTime>
<RepeatTime>2000</RepeatTime>

View File

@ -6,7 +6,6 @@
<Pierce>25.0</Pierce>
<Crush>0.0</Crush>
<MaxRange>44</MaxRange>
<MinRange>0.0</MinRange>
<ProjectileSpeed>50.0</ProjectileSpeed>
<PrepareTime>1200</PrepareTime>
<RepeatTime>2000</RepeatTime>

View File

@ -442,7 +442,17 @@ public:
return m_Tag;
}
virtual bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& out)
{
return GetObstructionSquare(out, true);
}
virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out)
{
return GetObstructionSquare(out, false);
}
virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out, bool previousPosition)
{
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
if (!cmpPosition)
@ -455,7 +465,11 @@ public:
if (!cmpPosition->IsInWorld())
return false; // no obstruction square
CFixedVector2D pos = cmpPosition->GetPosition2D();
CFixedVector2D pos;
if (previousPosition)
pos = cmpPosition->GetPreviousPosition2D();
else
pos = cmpPosition->GetPosition2D();
if (m_Type == STATIC)
out = cmpObstructionManager->GetStaticShapeObstruction(pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1);
else if (m_Type == UNIT)

View File

@ -995,10 +995,19 @@ void CCmpUnitMotion::Move(fixed dt)
}
else
{
// check if target was reached in case of a moving target
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
if
(
cmpUnitMotion && cmpUnitMotion->IsMoving() &&
MoveToTargetRange(m_TargetEntity, m_TargetMinRange, m_TargetMaxRange)
)
return;
// Not in formation, so just finish moving
StopMoving();
m_State = STATE_IDLE;
MoveSucceeded();
if (m_FacePointAfterMove)
FaceTowardsPointFromPos(pos, m_FinalGoal.x, m_FinalGoal.z);
@ -1508,7 +1517,12 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
if (distance < minRange)
// compare with previous obstruction
ICmpObstructionManager::ObstructionSquare previousObstruction;
cmpObstruction->GetPreviousObstructionSquare(previousObstruction);
entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize);
if (distance < minRange && previousDistance < minRange)
{
// Too close to the square - need to move away
@ -1523,7 +1537,7 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
goal.hw = obstruction.hw + delta;
goal.hh = obstruction.hh + delta;
}
else if (maxRange < entity_pos_t::Zero() || distance < maxRange)
else if (maxRange < entity_pos_t::Zero() || distance < maxRange || previousDistance < maxRange)
{
// We're already in range - no need to move anywhere
if (m_FacePointAfterMove)
@ -1554,6 +1568,17 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
return false;
}
entity_pos_t previousCircleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
if (previousCircleDistance < maxRange)
{
// We're already in range - no need to move anywhere
if (m_FacePointAfterMove)
FaceTowardsPointFromPos(pos, goal.x, goal.z);
return false;
}
entity_pos_t goalDistance = maxRange - g_GoalDelta;
goal.type = ICmpPathfinder::Goal::CIRCLE;
@ -1626,12 +1651,17 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
CFixedVector2D halfSize(obstruction.hw, obstruction.hh);
entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
// compare with previous obstruction
ICmpObstructionManager::ObstructionSquare previousObstruction;
cmpObstruction->GetPreviousObstructionSquare(previousObstruction);
entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize);
// See if we're too close to the target square
if (distance < minRange)
if (distance < minRange && previousDistance < minRange)
return false;
// See if we're close enough to the target square
if (maxRange < entity_pos_t::Zero() || distance <= maxRange)
if (maxRange < entity_pos_t::Zero() || distance <= maxRange || previousDistance <= maxRange)
return true;
entity_pos_t circleRadius = halfSize.Length();
@ -1643,6 +1673,11 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
entity_pos_t circleDistance = (pos - CFixedVector2D(obstruction.x, obstruction.z)).Length() - circleRadius;
if (circleDistance <= maxRange)
return true;
// also check circle around previous position
circleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
if (circleDistance <= maxRange)
return true;
}
@ -1655,14 +1690,12 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld())
return false;
CFixedVector2D targetPos = cmpTargetPosition->GetPosition2D();
CFixedVector2D targetPos = cmpTargetPosition->GetPreviousPosition2D();
entity_pos_t distance = (pos - targetPos).Length();
if (minRange <= distance && (maxRange < entity_pos_t::Zero() || distance <= maxRange))
return true;
return false;
return minRange <= distance &&
(maxRange < entity_pos_t::Zero() || distance <= maxRange);
}
}

View File

@ -47,6 +47,11 @@ public:
*/
virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) = 0;
/**
* Same as the method above, but returns an obstruction shape for the previous turn
*/
virtual bool GetPreviousObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) = 0;
virtual entity_pos_t GetUnitRadius() = 0;
virtual bool IsControlPersistent() = 0;