// 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(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; }