Hello, new developer here. I’m working on a skateboard controller (using the third-person template as a starting point). In the Tick method I use line traces to calculate the slope the board is on, and rotate its yaw or roll values to match the slope. I then also use this value to determine if the board needs to speed up or slow down, and adjust the speed (a float named current velocity, between 1.f and -1.f, replacing the forward movement input. There’s also a “Kick” input that adds to this number, but I don’t think that relates to the issue.)
The problem is that when the board goes up the slope, stops, and comes back down, it attempts to align itself with the negative X-axis. Either I do not understand GetActorForwardVector() well enough, or AddMovementInput(), but I’ve tried looking at the documentation and uses of these functions and can’t see what I’m missing.
The code is below, but here’s also a video of the problem, because it’s quite hard to describe with words : Skate Game Unreal Editor 2023 02 10 21 36 13 - YouTube (just ignore the debug lines).
Code:
void AJadeBlokSkateGameCharacter::Tick(float DeltaTime)
{
float pitch;
float roll;
int lineCastLength = 70;
FRotator rotation;
FHitResult hity1;
FHitResult hity2;
FHitResult hitx1;
FHitResult hitx2;
auto c = FCollisionQueryParams();
c.AddIgnoredActor(this);
auto start = GetActorLocation();
auto end = start + FVector(0, 0, -lineCastLength);
this->GetWorld()->LineTraceSingleByObjectType(hity1, start, end - lineCastLength * GetActorForwardVector(), ECC_WorldStatic, c);
this->GetWorld()->LineTraceSingleByObjectType(hity2, start, end + lineCastLength * GetActorForwardVector(), ECC_WorldStatic, c);
this->GetWorld()->LineTraceSingleByObjectType(hitx1, start, end + lineCastLength * GetActorForwardVector().RotateAngleAxis(90, FVector(0, 0, 1)), ECC_WorldStatic, c);
this->GetWorld()->LineTraceSingleByObjectType(hitx2, start, end - lineCastLength * GetActorForwardVector().RotateAngleAxis(90, FVector(0, 0, 1)), ECC_WorldStatic, c);
auto a = hity1.GetActor();
auto b = hity2.GetActor();
auto y = hitx1.GetActor();
auto z = hitx2.GetActor();
if (a != nullptr && b != nullptr && y != nullptr && z != nullptr) {
FVector i = hity2.Location - hity1.Location;
i.Normalize();
pitch = FMath::RadiansToDegrees(FMath::Asin(FVector::DotProduct(i, FVector(0, 0, 1))));
i = hitx2.Location - hitx1.Location;
i.Normalize();
roll = FMath::RadiansToDegrees(FMath::Asin(FVector::DotProduct(i, FVector(0, 0, 1))));
SetActorRotation(FRotator(pitch, GetActorRotation().Yaw, roll));
currentVelocity -= 0.001f * pitch;
}
Super::Tick(DeltaTime);
if (isBoardEnabled)
{
if (currentVelocity > 0)
{
AddMovementInput(GetActorForwardVector(), currentVelocity);
}
else if (currentVelocity < 0)
{
AddMovementInput(GetActorForwardVector(), currentVelocity);
}
GEngine->AddOnScreenDebugMessage(0, 0.5f, FColor(1, 0, 0), FString::Printf(TEXT("Yaw: %f"), GetActorRotation().Yaw));
if (currentVelocity > 0.001f)
{
currentVelocity -= 0.001f;
}
else if (currentVelocity < -0.001f)
{
currentVelocity += 0.001f;
}
else if (pitch == 0 && currentVelocity < 0.001f && currentVelocity > -0.001f)
{
ToggleBoard();
}
}
}