Setting up the script

So firstly of all we have to set up our games scripts. I started with


class TrainInfo extends UTGame;

event PlayerController Login(string Portal, string Options, const UniqueNetId UniqueId, out string ErrorMessage)
	local NavigationPoint StartSpot;
	local PlayerController NewPlayer;
	local string InName;
	local rotator SpawnRotation;
	local Mustang_Content Pawn;
	local Pawn thepawn;
	StartSpot = FindPlayerStart( None, 0, Portal );
	if( StartSpot == None )
		ErrorMessage = PathName(WorldInfo.Game.GameMessageClass) $ ".FailedPlaceMessage";
		return None;
	SpawnRotation.Yaw = StartSpot.Rotation.Yaw;
	NewPlayer = SpawnPlayerController(StartSpot.Location, SpawnRotation);
	if( NewPlayer == None )
		`log("Couldn't spawn player controller of class "$PlayerControllerClass);
		ErrorMessage = PathName(WorldInfo.Game.GameMessageClass) $ ".FailedSpawnMessage";
		return None;
	NewPlayer.StartSpot = StartSpot;
	thepawn = spawn(class 'TrainPawn' ,,,StartSpot.Location+Vect(0,0,100)); //+100 to make sure the two pawns do not get stuck
	Pawn = spawn(class 'Mustang_Content',,,StartSpot.Location);
	Pawn.TryToDrive(thePawn);//The ****!
    return NewPlayer;



class TrainPawn extends UTPawn;


class TrainPlayerController extends UTPlayerController;

var         SplineConstraint          Constraint;   //Constraint

struct sSplinePath
	var SplineActor StartAnchor;
	var SplineActor EndAnchor;
	var array Path;

	var SplineActor NearAnchorLow;
	var SplineActor NearAnchorHigh;
	var float RecentPosition;
	var float RespectivePosition;
	var Vector RecentLocation;

simulated event PostBeginPlay()

	//Setup our Constraint
	Constraint = new class'SplineConstraint';

event PlayerTick( float DeltaTime )
	if(Constraint.Pawn == none)


event Possess(Pawn inPawn, bool bVehicleTransition)
	Super.Possess(inPawn, bVehicleTransition);




class SplineConstraint extends Object;

var         Pawn             Pawn;                  //Pawn to Constrain to the Spline
var         array SplineCache;           //Cache of our Current SplineActors
var         Vector             StartPosition;         //Pawn's Start location on the Path
var         float              Leeway;                //if the Pawn is farther than this amount the constraint will Lerp it back
var         float              LerpSpeed;             //How fast the Pawn gets Lerp'd into position

var         bool               bEnableDebug;          //Is Debugging enabled for the SplineConstraint

exec function ShowConstraint()
	bEnableDebug = !bEnableDebug;

		`log("Show Constraints Enabled");
		`log("Show Constraints Disabled");

 * Initializes the class and finds the SplineActors
 * @param WorldInfo
function Initialize(WorldInfo WorldInfo)
	local SplineActor Current;

	//Add Our splines to our Cache
	foreach WorldInfo.DynamicActors( class'SplineActor', Current)
		SplineCache.AddItem( Current );

		Current.nextOrdered = Current.GetBestConnectionInDirection(vect(0,1,0));

		if(Current.nextOrdered != none)
			Current.nextOrdered.prevOrdered = Current;

 * Set the Pawn for Constraint and Initialize Constraint
function SetConstraint(Pawn PawnToConstrain)
	Pawn = PawnToConstrain;

 * Updates and Enforces the Constraint
function Update(float DeltaTime)
	local SplineActor   Spline;                  //Used to iterate through our SplineCache
	local SplineActor   CurrentSplineActor;      //Current SplineActor We are Focused on
	local SplineActor   PrevSplineActor;         //Previous SplineActor from CurrentSplineActor
	local SplineActor   NextSplineActor;         //Next SplineActor from CurrentSplineActor
	local Vector        RequiredLocation;        //Position on the spline we should be constrained to
	local Vector        Direction;               //Direction we should be facing.  Heading Vector.  using Rotator(Direction)
	local float         BestDistance;            //Used to find the closest SplineActor
	local float         Distance;                //Distance on the Spline to find a Location
	local float         DotProduct;              //Used to find which side of the CurrentSplineActor we are on.

	//Temp Debug Value
	local float         Z;

	//Set to a High Number
	BestDistance = 10000;

	//Find the closest SplineActor that has a Previous and Next Ordered SplineActor
	foreach SplineCache( Spline )
		if(VSize( Pawn.Location - Spline.Location ) < BestDistance)
			// If this Spline doesn't have a PrevOrdered or NextOrdered then skip it.
			// Our CurrentSplineActor needs to be one that has a Prev and Next Ordered SplineActor
			if(Spline.prevOrdered == none || Spline.nextOrdered == none)

			//Set our CurrentSplineActor
			CurrentSplineActor = Spline;

			//Update our BestDistance to this Spline and then check for a closer SplineActor
			BestDistance = VSize( Pawn.Location - Spline.Location);

	//Don't continue if we don't have a CurrentSplineActor
	if(CurrentSplineActor == none)

	NextSplineActor = CurrentSplineActor.nextOrdered;
	PrevSplineActor = CurrentSplineActor.prevOrdered;

	//Need a Previous and Next SplineActor for the Constraint to Work.
	//Check here just in case
	if( NextSplineActor == none || PrevSplineActor == none)

	//Set our starting location.
	//Playerstart should be close to this in the Map.
	if(StartPosition == vect(0,0,0))
		StartPosition = CurrentSplineActor.prevOrdered.Location;  //Generally the start pos will be on a Prev SplineActor

	//Find out which side of the CurrentSplineActor we are on for our positon Calculations.
	DotProduct = Normal(Pawn.Location - CurrentSplineActor.Location) dot Normal(CurrentSplineActor.Location - NextSplineActor.Location);

	//If the DotProduct is Less than 0 than we are in between the Current and Next SplineActors
	//If the DotProduct is Greater than 0 than we are in between the Previous and Current SplineActors
	if(DotProduct  Leeway)
		//use Lerp
		RequiredLocation.X = Lerp(Pawn.Location.X, RequiredLocation.X, LerpSpeed);
		RequiredLocation.Y = Lerp(Pawn.Location.Y, RequiredLocation.Y, LerpSpeed);

		//Set Location

	//Face our Pawn to the the direction the Spline is faceing
	//Needs to be modified to go both directions and dependent on the mouse cursor position.
	Pawn.FaceRotation(Rotator(Direction), DeltaTime);

	//Check if we should show Debug
		//Draw a line from Pawn.Location to NextSplineActor.Location
		Pawn.DrawDebugLine(Pawn.Location, NextSplineActor.Location, 255,0,0, false);

		//Draw a line from Pawn.Location to CurrentSplineActor.Location
		Pawn.DrawDebugLine(Pawn.Location, CurrentSplineActor.Location, 0,255,0, false);

		//Draw a line from Pawn.Location to PrevSplineActor.Location
		Pawn.DrawDebugLine(Pawn.Location, PrevSplineActor.Location, 255, 0, 0, false);

		RequiredLocation.Z = Z;
		//Draw a line from Pawn.Location to RequiredLocation
		Pawn.DrawDebugLine(Pawn.Location, RequiredLocation, 0, 0, 255, false);

		//Draw Boxes around the SplineActors to show their Location
		foreach SplineCache( Spline )
			Pawn.DrawDebugBox(Spline.Location, vect(10,10,10), 255, 255, 0, false);

	bEnableDebug = true
	Leeway = 10
	LerpSpeed = 0.5

I also added a spline constraint class which you will see referenced in the playercontroller class. I will talk a little
bit more about the spline constraint class later on but this basically glues the pawn to the tracks so that they can only move backwards and forwards
(Which is useful when running a train!!)


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s