I implemented somthing similar in my own project using splines, and trigger volume.
When the player enters the volume I disable the input of the character and give it to my scriptedpath blueprint,
void AScriptVolume::OnTriggerEnter(UPrimitiveComponent * HitComp, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult){
MyCharacter->DisableInput(controller);
InputComponent = NewObject<UInputComponent>(this, UInputComponent::StaticClass(), "Input Component");
InputComponent->bBlockInput = bBlockInput;
if (InputComponent)
{
InputComponent->BindAxis("MoveForward", this, &AScriptVolume::AdvanceCharacterForward);
InputComponent->BindAxis("MoveRight", this, &AScriptVolume::AdvanceCharacterRight);
EnableInput(controller);
}
void AScriptVolume::AdvanceCharacterForward(float value)
{
APlayerController* controller = Cast<APlayerController>(MyCharacter->Controller);
// find out which way is forward
const FRotator Rotation = controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
inputVector += FVector2D(Direction)*value;
}
void AScriptVolume::AdvanceCharacterRight(float value)
{
APlayerController* controller = Cast<APlayerController>(MyCharacter->Controller);
// find out which way is right
const FRotator Rotation = controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
inputVector += FVector2D(Direction)*value;
}
Then every tick I calculate the direction of the input and check if its in the valid direction, in my case based on the forward and backward vectors of my character. If the input is correct a calculate the time value it has to move to in the spline.
float angleF = UKharaUtils::CalcAngleBetweenVectors2D(FVector2D(MyCharacter->GetActorForwardVector()), inputVector);
float angleB = UKharaUtils::CalcAngleBetweenVectors2D(FVector2D(-MyCharacter->GetActorForwardVector()), inputVector);
if (inputVector.SizeSquared() > 0 && FMath::Abs(angleF) < INPUTANGLEMARGIN || FMath::Abs(angleB) < INPUTANGLEMARGIN)
{
float direction = 0;
if (FMath::Abs(angleF) < INPUTANGLEMARGIN)
{
direction = 1;
} else
{
direction = -1;
}
timeValue += GetWorld()->GetDeltaSeconds() * 1 / MovementDuration*inputVector.Size()*direction;
SplineCharacterMovement(timeValue, direction);
}
inputVector = FVector2D::ZeroVector;
the method SplineCharacterMovement is incharged of calculating the movement of the character
void AScriptVolume::SplineCharacterMovement(float val, int32 direction)
{
FVector SplineLocation = CharacterPath->GetLocationAtDistanceAlongSpline(val*CharacterPath->GetSplineLength(), ESplineCoordinateSpace::World);
FVector SplineTangent = CharacterPath->GetTangentAtDistanceAlongSpline(val*CharacterPath->GetSplineLength(), ESplineCoordinateSpace::World);
FRotator CharRot= MyCharacter->GetActorRotation();
FRotator DestRot = CharRot;
SplineTangent.Normalize();
float DirTangentAngleDif = UKharaUtils::CalcAngleBetweenVectors2D(FVector2D(MyCharacter->GetActorForwardVector()), FVector2D(SplineTangent));
DestRot.Yaw += DirTangentAngleDif;
MyCharacter->StartAutomaticMovement(Khara->GetActorRotation(), DestRot, Khara->GetActorLocation(), SplineLocation, EKharaStatesEnum::KSE_Normal, Khara->GetKharaMovementComponent()->RotationRate.Yaw, CharacterMovementSpeed, true);
MyCharacter->GetMovementComponent()->Velocity = SplineTangent*CharacterMovementSpeed*direction;
}
-
CharacterPath: is my splinecomponent
-
StartAutomaticMovement: is an auxiliary function to learp my
character from one point to another
-
CharacterMovementSpeed: is a variable set in the begin play based
on the time it take the character to
cross the spline and the length of
the spline