Skip to content
Snippets Groups Projects
Commit 19efafce authored by Ehret's avatar Ehret
Browse files

also the cpp file for previous commit

parent 73ed206b
Branches
Tags
2 merge requests!28Improve Walking implementation,!13Draft: Improve walking implementation

#include "Pawn/VRPawnMovement.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetSystemLibrary.h"
UVRPawnMovement::UVRPawnMovement(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
......@@ -19,6 +20,9 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, F
if (NavigationMode == EVRNavigationModes::NAV_WALK)
{
// you are only allowed to move horizontally in NAV_WALK
// everything else will be handled by stepping-up/gravity
// so remove Z component for the input vector of the UFloatingPawnMovement
PositionChange.Z = 0.0f;
ConsumeInputVector();
AddInputVector(PositionChange);
......@@ -26,17 +30,22 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, F
if(NavigationMode == EVRNavigationModes::NAV_FLY || NavigationMode == EVRNavigationModes::NAV_WALK)
{
MoveByGravityOrStepUp(DeltaTime);
CheckForPhysWalkingCollision();
if(CheckForVirtualMovCollision(PositionChange, DeltaTime))
if(CheckForVirtualSteerCollision(PositionChange, DeltaTime))
{
// if we would move into something if we apply this input (estimating distance by max speed)
// we consume the input so it is not applied
ConsumeInputVector();
}
// so we add stepping-up (for both walk and fly)
// and gravity for walking only
MoveByGravityOrStepUp(DeltaTime);
}
if(NavigationMode == EVRNavigationModes::NAV_NONE)
{
//just remove whatever input is there
ConsumeInputVector();
}
......@@ -45,18 +54,6 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, F
LastHeadPosition = HeadComponent->GetComponentLocation();
}
bool UVRPawnMovement::CheckForVirtualMovCollision(FVector PositionChange, float DeltaTime)
{
FVector ProbePosition = PositionChange.GetSafeNormal() * GetMaxSpeed() * DeltaTime;
FHitResult FHitResultVR;
CapsuleColliderComponent->AddWorldOffset(ProbePosition, true, &FHitResultVR);
if (FVector::Distance(FHitResultVR.Location, CapsuleColliderComponent->GetComponentLocation()) < CapsuleColliderComponent->GetScaledCapsuleRadius())
{
return true;
}
return false;
}
void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent)
{
HeadComponent = NewHeadComponent;
......@@ -68,12 +65,30 @@ void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent)
void UVRPawnMovement::SetCapsuleColliderToUserSize()
{
float CharachterSize = abs(UpdatedComponent->GetComponentLocation().Z - HeadComponent->GetComponentLocation().Z);
if (CharachterSize > MaxStepHeight)
{
float ColliderHeight = CharachterSize - MaxStepHeight;
float ColliderHalfHeight = ColliderHeight / 2.0f;
// the collider should be placed
// between head and floor + MaxStepHeight
// head
// / \
// / \
// | |
// | |
// |collider|
// | |
// | |
// \ /
// \ __ /
// |
// MaxStepHeight
// |
// floor: ______________
const float UserSize = HeadComponent->GetComponentLocation().Z - UpdatedComponent->GetComponentLocation().Z;
if (UserSize > MaxStepHeight)
{
const float ColliderHeight = UserSize - MaxStepHeight;
const float ColliderHalfHeight = ColliderHeight / 2.0f;
if (ColliderHalfHeight <= CapsuleRadius)
{//Make the collider to a Sphere
CapsuleColliderComponent->SetCapsuleSize(ColliderHalfHeight, ColliderHalfHeight);
......@@ -85,109 +100,88 @@ void UVRPawnMovement::SetCapsuleColliderToUserSize()
CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation());
CapsuleColliderComponent->AddWorldOffset(FVector(0, 0, -ColliderHalfHeight));
CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1));
}
else
{
CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation());
CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1));
}
CapsuleColliderComponent->SetWorldRotation(FRotator::ZeroRotator);
}
void UVRPawnMovement::CheckForPhysWalkingCollision()
{
FVector CurrentHeadPosition = HeadComponent->GetComponentLocation();
FVector Direction = CurrentHeadPosition - LastHeadPosition;
FHitResult FHitResultPhys;
CapsuleColliderComponent->AddWorldOffset(Direction, true, &FHitResultPhys);
const FHitResult HitResult = CreateCapsuleTrace(LastHeadPosition, HeadComponent->GetComponentLocation(), false);
if (FHitResultPhys.bBlockingHit)
//if this was not possible move it the entire pawn to avoid the head collision
if (HitResult.bBlockingHit)
{
UpdatedComponent->AddLocalOffset(FHitResultPhys.Normal*FHitResultPhys.PenetrationDepth);
UpdatedComponent->AddLocalOffset(HitResult.Normal*HitResult.PenetrationDepth);
}
}
void UVRPawnMovement::MoveByGravityOrStepUp(float DeltaSeconds)
bool UVRPawnMovement::CheckForVirtualSteerCollision(FVector PositionChange, float DeltaTime)
{
FVector StartLineTraceUnderCollider = CapsuleColliderComponent->GetComponentLocation();
StartLineTraceUnderCollider.Z -= CapsuleColliderComponent->GetScaledCapsuleHalfHeight();
FHitResult HitDetailsMultiLineTrace = CreateMultiLineTrace(FVector(0, 0, -1), StartLineTraceUnderCollider, CapsuleColliderComponent->GetScaledCapsuleRadius() / 4.0f, false);
float DistanceDifference = abs(MaxStepHeight - HitDetailsMultiLineTrace.Distance);
//Going up (in Fly and Walk Mode)
if ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance < MaxStepHeight))
{
ShiftVertically(DistanceDifference, UpSteppingAcceleration, DeltaSeconds, 1);
}
//Gravity (only in Walk Mode)
else if (NavigationMode==EVRNavigationModes::NAV_WALK && ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance > MaxStepHeight) || (HitDetailsMultiLineTrace.Actor == nullptr && HitDetailsMultiLineTrace.Distance != -1.0f)))
FVector ProbePosition = PositionChange.GetSafeNormal() * GetMaxSpeed() * DeltaTime;
const FHitResult HitResult = CreateCapsuleTrace(HeadComponent->GetComponentLocation(), ProbePosition, false);
if (HitResult.bBlockingHit)
{
ShiftVertically(DistanceDifference, GravityAcceleration, DeltaSeconds, -1);
return true;
}
return false;
}
void UVRPawnMovement::ShiftVertically(float DiffernceDistance, float VerticalAcceleration, float DeltaSeconds, int Direction)
void UVRPawnMovement::MoveByGravityOrStepUp(float DeltaSeconds)
{
VerticalSpeed += VerticalAcceleration * DeltaSeconds;
if (VerticalSpeed*DeltaSeconds < DiffernceDistance)
const FVector DownTraceStart = CapsuleColliderComponent->GetComponentLocation();
const float DownTraceDist = 1000.0f;
const FVector DownTraceDir = FVector(0,0,-1);
const FVector DownTraceEnd = DownTraceStart + DownTraceDist * DownTraceDir;
const FHitResult DownTraceHitResult = CreateCapsuleTrace(DownTraceStart, DownTraceEnd, true);
float HeightDifference = 0.0f;
if(DownTraceHitResult.bBlockingHit)
{
UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * VerticalSpeed * DeltaSeconds));
HeightDifference = DownTraceHitResult.ImpactPoint.Z - UpdatedComponent->GetComponentLocation().Z;
//so for HeightDifference>0, we have to move the pawn up; for HeightDifference<0 we have to move it down
}
else
//Going up (in Fly and Walk Mode)
if (HeightDifference>0.0f && HeightDifference<=MaxStepHeight)
{
UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * DiffernceDistance));
VerticalSpeed = 0;
}
ShiftVertically(HeightDifference, UpSteppingAcceleration, DeltaSeconds);
}
FHitResult UVRPawnMovement::CreateLineTrace(FVector Direction, const FVector Start, bool Visibility)
if(NavigationMode!=EVRNavigationModes::NAV_WALK)
{
//Re-initialize hit info
FHitResult HitDetails = FHitResult(ForceInit);
FVector End = ((Direction * 1000.f) + Start);
// additional trace parameters
FCollisionQueryParams TraceParams(FName(TEXT("InteractTrace")), true, NULL);
TraceParams.bTraceComplex = true; //to use complex collision on whatever we interact with to provide better precision.
TraceParams.bReturnPhysicalMaterial = true; //to provide details about the physical material, if one exists on the thing we hit, to come back in our hit result.
if (Visibility)
DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 1);
return;
}
if (GetWorld()->LineTraceSingleByChannel(HitDetails, Start, End, ECC_Visibility, TraceParams))
{
if (HitDetails.bBlockingHit)
//Gravity (only in Walk Mode)
if (!DownTraceHitResult.bBlockingHit || HeightDifference<0.0f)
{
ShiftVertically(HeightDifference, GravityAcceleration, DeltaSeconds);
}
}
return HitDetails;
}
FHitResult UVRPawnMovement::CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility)
void UVRPawnMovement::ShiftVertically(float Distance, float VerticalAcceleration, float DeltaSeconds)
{
TArray<FVector> StartVectors;
TArray<FHitResult> OutHits;
FHitResult HitDetailsMultiLineTrace;
HitDetailsMultiLineTrace.Distance = -1.0f;//(Distance=-1) not existing, but to know if this Variable not Initialized(when all Traces not compatible)
StartVectors.Add(Start); //LineTraceCenter
StartVectors.Add(Start + FVector(0, -Radius, 0)); //LineTraceLeft
StartVectors.Add(Start + FVector(0, +Radius, 0)); //LineTraceRight
StartVectors.Add(Start + FVector(+Radius, 0, 0)); //LineTraceFront
StartVectors.Add(Start + FVector(-Radius, 0, 0)); //LineTraceBehind
bool IsBlockingHitAndSameActor = true;
bool IsAllNothingHiting = true;
// loop through TArray
for (FVector& Vector : StartVectors)
VerticalSpeed += VerticalAcceleration * DeltaSeconds;
if (abs(VerticalSpeed*DeltaSeconds) < abs(Distance))
{
FHitResult OutHit = CreateLineTrace(Direction, Vector, Visibility);
OutHits.Add(OutHit);
IsBlockingHitAndSameActor &= (OutHit.Actor == OutHits[0].Actor); //If all Hiting the same Object, then you are (going up/down) or (walking)
IsAllNothingHiting &= (OutHit.Actor == nullptr); //If all Hiting nothing, then you are falling
UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, VerticalSpeed * DeltaSeconds));
}
else
{
UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Distance));
VerticalSpeed = 0;
}
}
if (IsBlockingHitAndSameActor || IsAllNothingHiting)
HitDetailsMultiLineTrace = OutHits[0];
FHitResult UVRPawnMovement::CreateCapsuleTrace(const FVector Start, FVector End, bool DrawDebug) const
{
const EDrawDebugTrace::Type DrawType = DrawDebug ? EDrawDebugTrace::Type::ForDuration : EDrawDebugTrace::Type::None;
return HitDetailsMultiLineTrace;
FHitResult Hit;
UKismetSystemLibrary::CapsuleTraceSingle(GetWorld(), Start, End, CapsuleColliderComponent->GetScaledCapsuleRadius(), CapsuleColliderComponent->GetScaledCapsuleHalfHeight() ,UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_Visibility), true, {}, DrawType, Hit, true);
return Hit;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment