167 lines
5.3 KiB
C++
167 lines
5.3 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "customCharacterMovementComponent.h"
|
|
#include "GameFramework/Character.h"
|
|
#include "Components/CapsuleComponent.h"
|
|
#include "Engine/World.h"
|
|
|
|
UCustomCharacterMovementComponent::UCustomCharacterMovementComponent()
|
|
{
|
|
// Set default values here if needed
|
|
}
|
|
|
|
// Custom movement physics
|
|
// Use custom movement 0 for climbing
|
|
void UCustomCharacterMovementComponent::PhysCustom(float DeltaTime, int32 Iterations)
|
|
{
|
|
// Handle custom movement mode physics here
|
|
switch (CustomMovementMode)
|
|
{
|
|
case 0:
|
|
{
|
|
PhysClimbing(DeltaTime, Iterations);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// For any other custom mode, fallback to base implementation
|
|
Super::PhysCustom(DeltaTime, Iterations);
|
|
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, TEXT("Movement mode not implemented!"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UCustomCharacterMovementComponent::PhysClimbing(float DeltaTime, int32 Iterations)
|
|
{
|
|
if (DeltaTime < MIN_TICK_TIME)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RestorePreAdditiveRootMotionVelocity();
|
|
|
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
|
{
|
|
if (bCheatFlying && Acceleration.IsZero())
|
|
{
|
|
Velocity = FVector::ZeroVector;
|
|
}
|
|
//const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction;
|
|
constexpr float Friction = 5.f;
|
|
CalcVelocity(DeltaTime, Friction, true, GetMaxBrakingDeceleration());
|
|
}
|
|
|
|
ApplyRootMotionToVelocity(DeltaTime);
|
|
|
|
bJustTeleported = false;
|
|
|
|
FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
|
const FVector Adjusted = Velocity * DeltaTime;
|
|
FHitResult Hit(1.f);
|
|
SafeMoveUpdatedComponent(Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
|
|
|
|
if (Hit.Time < 1.f)
|
|
{
|
|
SlideAlongSurface(Velocity * DeltaTime, 1.f - Hit.Time, Hit.Normal, Hit, true);
|
|
}
|
|
|
|
const ACharacter* Character = Cast<ACharacter>(GetOwner());
|
|
FHitResult WallHit;
|
|
const bool bWallFound = SweepForwardForWall(Character, WallHit);
|
|
if (bWallFound)
|
|
{
|
|
const FVector SurfaceNormal = WallHit.Normal;
|
|
|
|
// Update Location
|
|
const FVector TargetLocation = WallHit.Location + (SurfaceNormal * 0.1f);
|
|
const FVector NewLocation = FMath::VInterpTo(UpdatedComponent->GetComponentLocation(), TargetLocation, DeltaTime, 2.f);
|
|
UpdatedComponent->SetWorldLocation(NewLocation);
|
|
|
|
// Update Rotation
|
|
FRotator TargetRotation = FRotationMatrix::MakeFromXZ(-SurfaceNormal, FVector::UpVector).Rotator();
|
|
if (TargetRotation.Pitch < -70.0f)
|
|
{
|
|
TargetRotation = FRotator(0.0f, UpdatedComponent->GetComponentRotation().Yaw, 0.0f);
|
|
UpdatedComponent->SetWorldRotation(TargetRotation);
|
|
SetMovementMode(MOVE_Falling);
|
|
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, TEXT("Standing up"));
|
|
}
|
|
else
|
|
{
|
|
const FRotator NewRotation = FMath::RInterpTo(UpdatedComponent->GetComponentRotation(), TargetRotation, DeltaTime, 2.f);
|
|
UpdatedComponent->SetWorldRotation(NewRotation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reset Rotation and set MovementMode to Falling
|
|
const FRotator NewRotation = FRotator(0.0f, UpdatedComponent->GetComponentRotation().Yaw, 0.0f);
|
|
UpdatedComponent->SetWorldRotation(NewRotation);
|
|
SetMovementMode(MOVE_Falling);
|
|
}
|
|
|
|
if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
|
{
|
|
Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / DeltaTime;
|
|
}
|
|
}
|
|
|
|
void UCustomCharacterMovementComponent::OnMovementModeChanged(EMovementMode PreviousMovementMode, uint8 PreviousCustomMode)
|
|
{
|
|
Super::OnMovementModeChanged(PreviousMovementMode, PreviousCustomMode);
|
|
|
|
if (CharacterOwner)
|
|
{
|
|
if (MovementMode == MOVE_Custom && CustomMovementMode == 0)
|
|
{
|
|
CharacterOwner->bUseControllerRotationYaw = false;
|
|
}
|
|
else if (PreviousMovementMode == MOVE_Custom && PreviousCustomMode == 0)
|
|
{
|
|
CharacterOwner->bUseControllerRotationYaw = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sweeps forward from the character's capsule to detect a wall in front.
|
|
// Returns true if a blocking hit is found; OutHit contains hit information.
|
|
// SweepDistance is how far ahead to check.
|
|
bool UCustomCharacterMovementComponent::SweepForwardForWall(const ACharacter* Character, FHitResult& OutHit, const float SweepDistance)
|
|
{
|
|
if (!Character)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const UCapsuleComponent* Capsule = Character->GetCapsuleComponent();
|
|
if (!Capsule)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const UWorld* World = Character->GetWorld();
|
|
if (!World)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FVector Start = Capsule->GetComponentLocation();
|
|
const FVector Forward = Character->GetActorForwardVector();
|
|
const FVector End = Start + Forward * SweepDistance;
|
|
|
|
const float CapsuleRadius = Capsule->GetScaledCapsuleRadius();
|
|
const float CapsuleHalfHeight = Capsule->GetScaledCapsuleHalfHeight();
|
|
const FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(CapsuleRadius, CapsuleHalfHeight);
|
|
|
|
const bool bHit = World->SweepSingleByChannel(
|
|
OutHit,
|
|
Start,
|
|
End,
|
|
FQuat::Identity,
|
|
ECC_Visibility, // Adjust collision channel as needed
|
|
CapsuleShape
|
|
);
|
|
|
|
return bHit;
|
|
} |