Announcement

Collapse

The Infinity Blade Forums Have Moved

We've launched brand new Infinity Blade forums with improved features and revamped layout. We've also included a complete archive of the previous posts. Come check out the new Infinity Blade forums.
See more
See less

Attaching Train to rails using splines - help desperately needed!

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Attaching Train to rails using splines - help desperately needed!

    Hey guys,

    Im having loads of trouble here, hopefully someone can help. Ive got a spline class set up to allow a default pawn to move along the spline,however when I spawn him into a vehicle using Kismet (even when using Script) the vehicle can move away from the tracks even though its still connected to the spline whereas the spawn stays locked in. Does anyone know how I would adapt this class for a vehicle? I've been trying for over a month now with no success.

    PlayerControllerClass:

    Code:
    class TrainPlayerController extends GamePlayerController;
    
    var         SplineConstraint          Constraint;   //Constraint 
    
    struct sSplinePath
    {
    	var SplineActor StartAnchor;
    	var SplineActor EndAnchor;
    	var array<SplineActor> Path;
    
    	var SplineActor NearAnchorLow;
    	var SplineActor NearAnchorHigh;
    	var float RecentPosition;
    	var float RespectivePosition;
    	var Vector RecentLocation;
    };
    
    simulated event PostBeginPlay()
    {
    	super.PostBeginPlay();
    
    	//Setup our Constraint
    	Constraint = new class'SplineConstraint';
    	Constraint.Initialize(WorldInfo);
    	//
    	TrainInfo(WorldInfo.Game).RestartPlayer(self);
    }
    
    event PlayerTick( float DeltaTime )
    {
    	if(Constraint.Pawn == none)
    		Constraint.SetConstraint(Pawn);
    
    	super.PlayerTick(DeltaTime);
    	Constraint.Update(DeltaTime);
    }
    
    DefaultProperties
    {
    
    }
    Spline Constraint:
    Code:
    class SplineConstraint extends Object;
    
    var         Pawn             Pawn;                  //Pawn to Constrain to the Spline
    var         array<SplineActor> 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;
    
    	if(bEnableDebug)
    	{
    		`log("Show Constraints Enabled");
    	}
    	else
    	{
    		`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;
    	Initialize(Pawn.WorldInfo);
    }
    
    /**
     * 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)
    				continue;
    
    			//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) 
    		return;
    
    	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)
    		return;
    
    	//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
    		Pawn.SetLocation(StartPosition);  
    	}
    	
    	//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 < 0)
    	{
    		//Find our 2D distance from Pawn.Location to Our CurrentSplineActor.Location
    		Distance = VSize2D(Pawn.Location - CurrentSplineActor.Location);
    
    		//Use Distance to find the required Location on the Spline
    		RequiredLocation = CurrentSplineActor.FindSplineComponentTo(NextSplineActor).GetLocationAtDistanceAlongSpline(Distance);
    
    		//Find our Heading so We can face our Pawn this way.  Not setup to go both directions yet.
    		Direction = Normal(CurrentSplineActor.FindSplineComponentTo(NextSplineActor).GetTangentAtDistanceAlongSpline(Distance));
    	}
    	else
    	{
    		//Find our 2D distance from Pawn.Location to Our PrevSplineActor.Location
    		Distance = VSize2D(Pawn.Location - PrevSplineActor.Location);
    
    		//Use Distance to find the required Location on the Spline
    		RequiredLocation = PrevSplineActor.FindSplineComponentTo(CurrentSplineActor).GetLocationAtDistanceAlongSpline(Distance);
    
    		//Find our Heading so We can face our Pawn this way.  Not setup to go both directions yet.
    		Direction = Normal(PrevSplineActor.FindSplineComponentTo(CurrentSplineActor).GetTangentAtDistanceAlongSpline(Distance));
    	}
    
    	//used for Debug
    	Z = RequiredLocation.Z;
    
    	//Set the RequiredLocation Z to the Pawn.Location.Z Since we are only Constraining X and Y
    	RequiredLocation.Z = Pawn.Location.Z;
    
    	//Enforce our Constraint
    	if(VSize2D(Pawn.Location - RequiredLocation) > Leeway)
    	{
    		//use Lerp
    		RequiredLocation.X = Lerp(Pawn.Location.X, RequiredLocation.X, LerpSpeed);
    		RequiredLocation.Y = Lerp(Pawn.Location.Y, RequiredLocation.Y, LerpSpeed);
    
    		//Set Location
    		Pawn.SetLocation(RequiredLocation);
    	}
    
    	//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
    	if(bEnableDebug)
    	{
    		//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);
    		}
    	}
    }
    
    DefaultProperties
    {
    	bEnableDebug = true
    	Leeway = 10
    	LerpSpeed = 0.01
    
    }
    Theres no code in my Pawn or Gameinfo class affecting the Spline either.

    Any ideas please? Help would be greatly appreciated!

  • #2
    Sorry for bumping but i want post here my working code for other users (i think that it isn't what you are searching). I created this today. Its class of actor that is "attached to spline" or constrainted to move along it. If u want change speed of move, direction or starting location use these variables: Speed, StartingSplineActor, Direction of move ( you can assign it in actors properties in editor). It's ready for copy&paste. Everything what should u do is add mesh in def properties.



    I created this really simple code:

    Code:
    class Train extends Actor placeable;
    
    var array<SplineActor> SplineCache;             //List of all SplineActors
    var float              Distance;                //Distance on the Spline to find a Location
    var() float              Speed;                 // Speed of train - you can assign it in editor
    var SplineActor        CurrentSplineActor;   
    var() SplineActor      StartingSplineActor;       // Position where will our train start - you can assign it in editor
    
    enum ReverserDirection  // Directions of move along spline
    {
            RD_Forward,
            RD_Backward
    };
    var() ReverserDirection ReverserDir; // You can assign variable in editor
    
    function PostBeginPlay()
    {
            super.PostBeginPlay();
            InitializeSplineActors();       // Create list of all SplineActors
    }
    
    function InitializeSplineActors()
    {
    	local SplineActor Current;
    
    	foreach AllActors( class'SplineActor', Current)
    	{
    		SplineCache.AddItem( Current );
    		Current.nextOrdered = Current.GetBestConnectionInDirection(vect(0,1,0)); // Assign next spline actor
    		if(Current.nextOrdered != none)          
    		{
    			Current.nextOrdered.prevOrdered = Current; // Assign previous spline actor to prevordered var
    		}
    	}
    }
    
    function Tick(float DeltaTime)    
    {
    	local Vector        RequiredLocation;        //Position on the spline we should be constrained to
    	local Vector        Direction;               //Direction we should be facing - rotation.
    	local float         MaxDistance;           // lenght of spline component
    	local Rotator       InvertedRotation;    // Used for Backward rotation change
    
            super.Tick(DeltaTime);
           
            if(CurrentSplineActor==none)
            {
            CurrentSplineActor=StartingSplineActor; // Set our starting location as location of StartingSplineActor
            }
    
            MaxDistance = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.nextOrdered).GetSplineLength();
            //Assigning distance between CurrentSplineActor and next spline actor
            If(ReverserDir == RD_Forward && Speed != 0) 
            {
                    If((MaxDistance-Distance) > Speed) 
                    {
                            Distance += Speed;  // Normal move
                    }
                    else
                    {
                            Distance = Speed - (MaxDistance-Distance); // ! MaxDistance-Distance < Speed
                            CurrentSplineActor = CurrentSplineActor.nextOrdered; // Setting next actor as current spline //actor
                    }
                    RequiredLocation = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetLocationAtDistanceAlongSpline(Distance); // Changing our distance along spline to vector
                    Direction = Normal(CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetTangentAtDistanceAlongSpline(Distance)); // Changing our distance along spline to direction vector and converting it to unit vector
                   	
                    SetRotation(Rotator(Direction));
                   	SetLocation(RequiredLocation);
            }
            else if(ReverserDir == RD_Backward && Speed != 0)  // Inverted Move
            {
            	If(Distance > Speed)
                    {
                            Distance -= Speed; 
                    }
                    else
                    {
                            MaxDistance = CurrentSplineActor.prevOrdered.FindSplineComponentTo(CurrentSplineActor).GetSplineLength();
                            Distance = MaxDistance - (Speed - Distance);
                            CurrentSplineActor = CurrentSplineActor.prevOrdered;
                    }
    
                    RequiredLocation = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetLocationAtDistanceAlongSpline(Distance);           `log("RequiredLocation"@RequiredLocation);
                    Direction = Normal(CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetTangentAtDistanceAlongSpline(Distance));
    
                    InvertedRotation = Rotator(Direction);
                   	InvertedRotation.Yaw += 32768;
                    
                    SetRotation(InvertedRotation);
                    SetLocation(RequiredLocation);
            }
    }
    
    defaultproperties
    {
    // Put your mesh code here
    }

    Comment


    • #3
      Ive noticed that this required you to enter a speed value in order for the vehicle to move along the spline. Is there anyway this can be done purely by the player input? i.e forward/backward?

      Comment


      • #4
        Yes, it is easy to implement.

        In player controller class use appropriate function (StartFire etc.) and increase speed of your train every click.

        Pseudocode:

        PC class:

        IncreaseVelocity = 1;

        exec function StartFire(byte FireModeNum)
        {
        MyTrain.Speed += IncreaseVelocity;
        }

        It will be little harder if u want to implement acceleration but it is possible.

        Comment


        • #5
          New version. Deleted "InvertedRotation", reverser and added startup location initialization. Speed < 0 is now backward movement.

          Code:
          class Train extends Actor placeable;
          
          var array<SplineActor> SplineCache;             //List of all SplineActors
          var float              Distance;                //Distance on the Spline to find a Location
          var() float              Speed;                 // Speed of train - you can assign it in editor
          var SplineActor        CurrentSplineActor;   
          var() SplineActor      StartingSplineActor;       // Position where will our train start - you can assign it in editor
          
          function PostBeginPlay()
          {
                  super.PostBeginPlay();
                  InitializeSplineActors();       // Create list of all SplineActors
                  MoveToRail();                   // Moves train to StartingSplineActor
          }
          
          function InitializeSplineActors()
          {
          	local SplineActor Current;
          
          	foreach AllActors( class'SplineActor', Current)
          	{
          		SplineCache.AddItem( Current );
          		Current.nextOrdered = Current.GetBestConnectionInDirection(vect(0,1,0)); // Assign next spline actor
          		if(Current.nextOrdered != none)          
          		{
          			Current.nextOrdered.prevOrdered = Current; // Assign previous spline actor to prevordered var
          		}
          	}
          }
          
          function MoveToRail()
          {
              local Vector        RequiredLocation;        //Position on the spline we should be constrained to
          	local Vector        Direction;               //Direction we should be facing - rotation.
          	local float         StartDistance;           // lenght of spline component
          
            if(CurrentSplineActor==none)
            {
                CurrentSplineActor=StartingSplineActor; // Set our starting location as location of StartingSplineActor
            }
          
            StartDistance = 0;  // Normal move
          
            RequiredLocation = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetLocationAtDistanceAlongSpline(StartDistance); // Changing our distance along spline to vector
            Direction = Normal(CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetTangentAtDistanceAlongSpline(StartDistance)); // Changing our distance along spline to direction vector and converting it to unit vector
          
            SetRotation(Rotator(Direction));
            SetLocation(RequiredLocation);
          }
          
          function Tick(float DeltaTime)    
          {
          	local Vector        RequiredLocation;        //Position on the spline we should be constrained to
          	local Vector        Direction;               //Direction we should be facing - rotation.
          	local float         MaxDistance;           // lenght of spline component
          
              super.Tick(DeltaTime);
                 
              if(CurrentSplineActor==none)
              {
                  CurrentSplineActor=StartingSplineActor; // Set our starting location as location of StartingSplineActor
              }
          
                  //Assigning distance between CurrentSplineActor and next spline actor
                  If(Speed > 0)
                  {
                      MaxDistance = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.nextOrdered).GetSplineLength();
                          If((MaxDistance-Distance) > Speed) 
                          {
                                  Distance += Speed;  // Normal move
                          }
                          else
                          {
          
                                  Distance = Speed - (MaxDistance-Distance); // ! MaxDistance-Distance < Speed
                                  CurrentSplineActor = CurrentSplineActor.nextOrdered; // Setting next actor as current spline //actor
                          }
                          RequiredLocation = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetLocationAtDistanceAlongSpline(Distance); // Changing our distance along spline to vector
                          Direction = Normal(CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetTangentAtDistanceAlongSpline(Distance)); // Changing our distance along spline to direction vector and converting it to unit vector
          
                          SetRotation(Rotator(Direction));
                         	SetLocation(RequiredLocation);
                  }
                  else if(Speed < 0)  // Inverted Move
                  {
                      MaxDistance = CurrentSplineActor.prevOrdered.FindSplineComponentTo(CurrentSplineActor).GetSplineLength();
                  	If(Distance > Speed)
                          {
                                  Distance += Speed;
                          }
                          else
                          {
                                  Distance = MaxDistance - (Speed - Distance);
                                  CurrentSplineActor = CurrentSplineActor.prevOrdered;
                          }
          
                          RequiredLocation = CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetLocationAtDistanceAlongSpline(Distance);           `log("RequiredLocation"@RequiredLocation);
                          Direction = Normal(CurrentSplineActor.FindSplineComponentTo(CurrentSplineActor.NextOrdered).GetTangentAtDistanceAlongSpline(Distance));
          
                          SetRotation(Rotator(Direction));
                          SetLocation(RequiredLocation);
                  }
          }
          
          defaultproperties
          {
              Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
              End Object
              Components.Add(MyLightEnvironment)
          
              Begin Object Class=StaticMeshComponent Name=Cursor
                    Scale=0.4
                    LightEnvironment=MyLightEnvironment
                    CastShadow=true
                   	bCastDynamicShadow=true
             	      bOwnerNoSee=false
                    BlockRigidBody=false
                    CollideActors=false
                    BlockActors=false
                    BlockZeroExtent=false
              StaticMesh=StaticMesh'EngineMeshes.Sphere'
              End Object
          
              Components.Add(Cursor)
          }

          Comment

          Working...
          X