138 lines
4.2 KiB
Ucode
138 lines
4.2 KiB
Ucode
//=============================================================================
|
|
// AICommand_ScriptedPawn_TraverseSpline
|
|
//=============================================================================
|
|
// AICommand to get a pawn to follow a spline
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2018 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
class AICommand_ScriptedPawn_TraverseSpline extends AICommand
|
|
within KFAIController;
|
|
|
|
var transient int SegmentGranularity;
|
|
|
|
var transient KFPawn_Scripted MyScriptedPawn;
|
|
|
|
var transient array<SplineActor> Route;
|
|
var transient int SegIdx, SubSegIdx;
|
|
var transient vector Direction, SubSegEnd;
|
|
var transient SplineComponent SegSplineComp;
|
|
var transient float SegSplineLen;
|
|
|
|
static function bool TraverseSpline(KFAIController AI, SplineActor SplineStart, SplineActor SplineEnd, int Granularity)
|
|
{
|
|
local AICommand_ScriptedPawn_TraverseSpline Cmd;
|
|
|
|
if( AI != none && SplineStart != none )
|
|
{
|
|
Cmd = new(AI) class'AICommand_ScriptedPawn_TraverseSpline';
|
|
if( Cmd != none )
|
|
{
|
|
SplineStart.FindSplinePathTo(SplineEnd, Cmd.Route);
|
|
Cmd.SegmentGranularity = Granularity;
|
|
AI.PushCommand( Cmd );
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function Pushed()
|
|
{
|
|
local SplineActor SplineEnd;
|
|
|
|
Super.Pushed();
|
|
MyScriptedPawn = KFPawn_Scripted(Pawn);
|
|
|
|
// The route represents the path between the pawn's spawn location and its goal, but it's allowed
|
|
// to continue after its goal if there are more spline actors that the goal connects to, so add
|
|
// those to the end of the route
|
|
SplineEnd = Route[Route.Length - 1];
|
|
while (SplineEnd.Connections.Length > 0)
|
|
{
|
|
SplineEnd = SplineEnd.Connections[0].ConnectTo;
|
|
Route.AddItem(SplineEnd);
|
|
}
|
|
|
|
GotoState('TraversingSpline');
|
|
}
|
|
|
|
function Paused( GameAICommand NewCommand )
|
|
{
|
|
Super.Paused( NewCommand );
|
|
}
|
|
|
|
function Resumed( Name OldCommandName )
|
|
{
|
|
Super.Resumed( OldCommandName );
|
|
}
|
|
|
|
function Popped()
|
|
{
|
|
Super.Popped();
|
|
Route.Length = 0;
|
|
MyScriptedPawn.EndedRoute(Status == 'Success');
|
|
}
|
|
|
|
function bool PawnReachedDestination(vector Dest)
|
|
{
|
|
return VSize2D(MyScriptedPawn.Location - Dest) < 10;
|
|
}
|
|
|
|
state TraversingSpline
|
|
{
|
|
Begin:
|
|
if (Route.Length == 0)
|
|
{
|
|
Status = 'Failure';
|
|
}
|
|
else
|
|
{
|
|
// consider the pawn to have "reached" the node it spawns at
|
|
MyScriptedPawn.ReachedRouteMarker(0, Route[0], 0, 0);
|
|
|
|
SegIdx = 1;
|
|
do // for each segment (space between two spline actors)...
|
|
{
|
|
SegSplineComp = Route[SegIdx-1].FindSplineComponentTo(Route[SegIdx]);
|
|
SegSplineLen = SegSplineComp.GetSplineLength();
|
|
SubSegIdx = 1;
|
|
do // for each sub-segment (space between segment "granules")...
|
|
{
|
|
SubSegEnd = SegSplineComp != none ?
|
|
SegSplineComp.GetLocationAtDistanceAlongSpline((float(SubSegIdx)/float(SegmentGranularity+1))*SegSplineLen) :
|
|
Route[SegIdx].Location;
|
|
do // update velocity and rotation toward sub-segment
|
|
{
|
|
Direction = SubSegEnd - Pawn.Location;
|
|
if (MyScriptedPawn.Physics == PHYS_Walking)
|
|
{
|
|
Direction.Z = 0.f;
|
|
}
|
|
Direction = Normal(Direction);
|
|
|
|
MyScriptedPawn.Velocity = Direction * MyScriptedPawn.GroundSpeed;
|
|
MyScriptedPawn.SetDesiredRotation(rotator(Direction),,,0.1f);
|
|
|
|
Sleep(0.f);
|
|
} until (PawnReachedDestination(SubSegEnd)); // until we've reached the next segment "granule"
|
|
|
|
MyScriptedPawn.ReachedRouteMarker(
|
|
SegIdx,
|
|
SubSegIdx == (SegmentGranularity + 1) ? Route[SegIdx] : none,
|
|
SubSegIdx,
|
|
SegSplineLen / float(SegmentGranularity+1));
|
|
|
|
++SubSegIdx;
|
|
} until (PawnReachedDestination(Route[SegIdx].Location) && SubSegIdx == (SegmentGranularity + 2)); // until we've reached the next spline actor AND we've reached each "granule" ...
|
|
// ... because we can get close enough to the next spline actor before we've made sure we've reached each "granule", and that can throw off logic
|
|
|
|
++SegIdx;
|
|
} until (SegIdx == Route.Length); // until we've reached the last spline actor in the route
|
|
|
|
MyScriptedPawn.Acceleration = vect(0, 0, 0);
|
|
Status = 'Success';
|
|
}
|
|
|
|
PopCommand(self);
|
|
} |