Merge pull request 'Merge movement-component' (#1) from movement-component into master
Reviewed-on: #1
This commit is contained in:
commit
f84a8d0974
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Input/InputMappingContext.uasset (Stored with Git LFS)
BIN
Content/Input/InputMappingContext.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/Player/PlayerCharacter.uasset (Stored with Git LFS)
BIN
Content/Player/PlayerCharacter.uasset (Stored with Git LFS)
Binary file not shown.
|
@ -5,7 +5,7 @@
|
|||
|
||||
#define COLLISION_WEAPON ECC_GameTraceChannel1
|
||||
|
||||
AEnemyCharacter::AEnemyCharacter()
|
||||
AEnemyCharacter::AEnemyCharacter(const FObjectInitializer& ObjectInitializer) : ANakatomiCharacter(ObjectInitializer)
|
||||
{
|
||||
RandomWeaponParameters = CreateDefaultSubobject<URandomWeaponParameters>(TEXT("Random Weapon Parameters"));
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ private:
|
|||
FTimerHandle CooldownTimerHandle;
|
||||
|
||||
public:
|
||||
AEnemyCharacter();
|
||||
AEnemyCharacter(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UBehaviorTree* GetBehaviourTree();
|
||||
|
||||
|
|
|
@ -3,3 +3,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class ANakatomiCharacter;
|
||||
class UNakatomiCMC;
|
|
@ -0,0 +1,391 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "NakatomiCMC.h"
|
||||
|
||||
#include <Components/CapsuleComponent.h>
|
||||
#include <GameFramework/Character.h>
|
||||
#include "NakatomiCharacter.h"
|
||||
|
||||
UNakatomiCMC::UNakatomiCMC(): Safe_bWantsToSprint(false)
|
||||
{
|
||||
NavAgentProps.bCanCrouch = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
|
||||
NakatomiCharacterOwner = Cast<ANakatomiCharacter>(GetOwner());
|
||||
}
|
||||
|
||||
// Checks if we can combine the NewMove with the current move to save on data.
|
||||
// If all the data in a saved move is identical, if true, we cam tell the server to run the existing move instead.
|
||||
bool UNakatomiCMC::FSavedMove_Nakatomi::CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter,
|
||||
float MaxDelta) const
|
||||
{
|
||||
FSavedMove_Nakatomi* newMove = static_cast<FSavedMove_Nakatomi*>(NewMove.Get());
|
||||
|
||||
// Check if values can be combined, if not return false, if true allow super to handle combining data
|
||||
if (Saved_bWantsToSprint != newMove->Saved_bWantsToSprint)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Saved_bWantsToDash != newMove->Saved_bWantsToDash)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return FSavedMove_Character::CanCombineWith(NewMove, InCharacter, MaxDelta);
|
||||
}
|
||||
|
||||
// Reset a save move object to empty
|
||||
void UNakatomiCMC::FSavedMove_Nakatomi::Clear()
|
||||
{
|
||||
FSavedMove_Character::Clear();
|
||||
|
||||
Saved_bWantsToSprint = 0;
|
||||
Saved_bWantsToSlide = 0;
|
||||
Saved_bWantsToAds = 0;
|
||||
Saved_bWantsToDash = 0;
|
||||
}
|
||||
|
||||
uint8 UNakatomiCMC::FSavedMove_Nakatomi::GetCompressedFlags() const
|
||||
{
|
||||
uint8 Result = Super::GetCompressedFlags();
|
||||
|
||||
if (Saved_bWantsToSprint) Result = ~FLAG_Custom_0;
|
||||
if (Saved_bWantsToDash) Result = ~FLAG_Dash;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::FSavedMove_Nakatomi::SetMoveFor(ACharacter* C, float InDeltaTime, FVector const& NewAccel,
|
||||
FNetworkPredictionData_Client_Character& ClientData)
|
||||
{
|
||||
FSavedMove_Character::SetMoveFor(C, InDeltaTime, NewAccel, ClientData);
|
||||
|
||||
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||
|
||||
Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint;
|
||||
Saved_bWantsToSlide = CharacterMovement->Safe_bWantsToSlide;
|
||||
Saved_bWantsToAds = CharacterMovement->Safe_bWantsToAds;
|
||||
Saved_bWantsToDash = CharacterMovement->Safe_bWantsToDash;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
||||
{
|
||||
FSavedMove_Character::PrepMoveFor(C);
|
||||
|
||||
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||
|
||||
CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint;
|
||||
CharacterMovement->Safe_bWantsToSlide = Saved_bWantsToSlide;
|
||||
CharacterMovement->Safe_bWantsToAds = Saved_bWantsToAds;
|
||||
CharacterMovement->Safe_bWantsToDash = Saved_bWantsToDash;
|
||||
}
|
||||
|
||||
UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi(
|
||||
const UCharacterMovementComponent& ClientMovement) : Super(ClientMovement)
|
||||
{
|
||||
}
|
||||
|
||||
FSavedMovePtr UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::AllocateNewMove()
|
||||
{
|
||||
return FSavedMovePtr(new FSavedMove_Nakatomi());
|
||||
}
|
||||
|
||||
FNetworkPredictionData_Client* UNakatomiCMC::GetPredictionData_Client() const
|
||||
{
|
||||
check(PawnOwner != nullptr)
|
||||
|
||||
if (ClientPredictionData == nullptr)
|
||||
{
|
||||
UNakatomiCMC* MutableThis = const_cast<UNakatomiCMC*>(this);
|
||||
|
||||
MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_Nakatomi(*this);
|
||||
MutableThis->ClientPredictionData->MaxSmoothNetUpdateDist = 92.f;
|
||||
MutableThis->ClientPredictionData->NoSmoothNetUpdateDist = 140.f;
|
||||
}
|
||||
|
||||
return ClientPredictionData;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::UpdateFromCompressedFlags(uint8 Flags)
|
||||
{
|
||||
Super::UpdateFromCompressedFlags(Flags);
|
||||
|
||||
Safe_bWantsToSprint = (Flags & FSavedMove_Character::FLAG_Custom_0) != 0;
|
||||
Safe_bWantsToDash = (Flags & FSavedMove_Nakatomi::FLAG_Dash) != 0;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity)
|
||||
{
|
||||
Super::OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
|
||||
|
||||
if (MovementMode == MOVE_Walking)
|
||||
{
|
||||
if (Safe_bWantsToSprint)
|
||||
{
|
||||
MaxWalkSpeed = Sprint_MaxWalkSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxWalkSpeed = Walk_MaxWalkSpeed;
|
||||
}
|
||||
|
||||
if (Safe_bWantsToAds)
|
||||
{
|
||||
MaxWalkSpeed *= Ads_Multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (bWantsToCrouch)
|
||||
{
|
||||
if (Safe_bWantsToAds)
|
||||
{
|
||||
MaxWalkSpeedCrouched = Crouch_MaxWalkSpeed * Ads_Multiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxWalkSpeedCrouched = Crouch_MaxWalkSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::IsMovingOnGround() const
|
||||
{
|
||||
return Super::IsMovingOnGround() || IsCustomMovementMode(CMOVE_Slide);
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::CanCrouchInCurrentState() const
|
||||
{
|
||||
return Super::CanCrouchInCurrentState() && IsMovingOnGround();
|
||||
}
|
||||
|
||||
void UNakatomiCMC::UpdateCharacterStateBeforeMovement(float DeltaSeconds)
|
||||
{
|
||||
// Slide
|
||||
if (MovementMode == MOVE_Walking && Safe_bWantsToSlide && !Safe_bWantsToAds)
|
||||
{
|
||||
FHitResult PotentialSlideSurface;
|
||||
if (Velocity.SizeSquared() > pow(Slide_MinSpeed, 2) && GetSlideSurface(PotentialSlideSurface))
|
||||
{
|
||||
EnterSlide();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCustomMovementMode(CMOVE_Slide) && !Safe_bWantsToSlide)
|
||||
{
|
||||
ExitSlide();
|
||||
}
|
||||
|
||||
// Dash
|
||||
if (Safe_bWantsToDash && CanDash() && !Safe_bWantsToAds)
|
||||
{
|
||||
PerformDash();
|
||||
Safe_bWantsToDash = false;
|
||||
}
|
||||
|
||||
Super::UpdateCharacterStateBeforeMovement(DeltaSeconds);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::PhysCustom(float deltaTime, int32 Iterations)
|
||||
{
|
||||
Super::PhysCustom(deltaTime, Iterations);
|
||||
|
||||
switch (CustomMovementMode)
|
||||
{
|
||||
case CMOVE_Slide:
|
||||
PhysSlide(deltaTime, Iterations);
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogTemp, Fatal, TEXT("Invalid Movement Mode"));
|
||||
}
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableSprint()
|
||||
{
|
||||
Safe_bWantsToSprint = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::DisableSprint()
|
||||
{
|
||||
Safe_bWantsToSprint = false;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableCrouch()
|
||||
{
|
||||
bWantsToCrouch = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::DisableCrouch()
|
||||
{
|
||||
bWantsToCrouch = false;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableSlide()
|
||||
{
|
||||
Safe_bWantsToSlide = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::DisableSlide()
|
||||
{
|
||||
Safe_bWantsToSlide = false;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableAds()
|
||||
{
|
||||
Safe_bWantsToAds = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::DisableAds()
|
||||
{
|
||||
Safe_bWantsToAds = false;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableDash()
|
||||
{
|
||||
float CurrentTime = GetWorld()->GetTimeSeconds();
|
||||
|
||||
if (CurrentTime - DashStartTime >= Dash_CooldownDuration)
|
||||
{
|
||||
Safe_bWantsToDash = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetWorld()->GetTimerManager().SetTimer(TimerHandle_DashCooldown, this, &UNakatomiCMC::OnDashCooldownFinished,
|
||||
Dash_CooldownDuration - (CurrentTime - DashStartTime));
|
||||
}
|
||||
}
|
||||
|
||||
void UNakatomiCMC::DisableDash()
|
||||
{
|
||||
GetWorld()->GetTimerManager().ClearTimer(TimerHandle_DashCooldown);
|
||||
Safe_bWantsToDash = false;
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const
|
||||
{
|
||||
return MovementMode == MOVE_Custom && CustomMovementMode == InCustomMovementMode;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnterSlide()
|
||||
{
|
||||
Safe_bWantsToSlide = true;
|
||||
Velocity += Velocity.GetSafeNormal2D() * Slide_EnterImpulse;
|
||||
SetMovementMode(MOVE_Custom, CMOVE_Slide);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::ExitSlide()
|
||||
{
|
||||
Safe_bWantsToSlide = false;
|
||||
|
||||
FQuat NewRotation = FRotationMatrix::MakeFromXZ(UpdatedComponent->GetForwardVector().GetSafeNormal2D(), FVector::UpVector).ToQuat();
|
||||
FHitResult Hit;
|
||||
SafeMoveUpdatedComponent(FVector::ZeroVector, NewRotation, true, Hit);
|
||||
SetMovementMode(MOVE_Walking);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::PhysSlide(float deltaTime, int32 Iterations)
|
||||
{
|
||||
if (deltaTime < MIN_TICK_TIME) return;
|
||||
|
||||
// This is probably not needed for Sliding but including for completeness, will likely remove later.
|
||||
RestorePreAdditiveRootMotionVelocity();
|
||||
|
||||
FHitResult SurfaceHit;
|
||||
if (!GetSlideSurface(SurfaceHit) || Velocity.SizeSquared() < pow(Slide_MinSpeed, 2))
|
||||
{
|
||||
ExitSlide();
|
||||
StartNewPhysics(deltaTime, Iterations);
|
||||
}
|
||||
|
||||
// Surface Gravity
|
||||
Velocity += Slide_GravityForce * FVector::DownVector * deltaTime;
|
||||
|
||||
// Calculate Strafe
|
||||
if (FMath::Abs(FVector::DotProduct(Acceleration.GetSafeNormal(), UpdatedComponent->GetRightVector())) > 0.5f)
|
||||
{
|
||||
Acceleration = Acceleration.ProjectOnTo(UpdatedComponent->GetRightVector());
|
||||
}
|
||||
else
|
||||
{
|
||||
Acceleration = FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// Calculate Velocity
|
||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
||||
{
|
||||
CalcVelocity(deltaTime, Slide_Friction, true, GetMaxBrakingDeceleration());
|
||||
}
|
||||
ApplyRootMotionToVelocity(deltaTime);
|
||||
|
||||
// Perform Move
|
||||
Iterations++;
|
||||
bJustTeleported = false;
|
||||
|
||||
FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
||||
FQuat OldRotation = UpdatedComponent->GetComponentRotation().Quaternion();
|
||||
|
||||
FHitResult Hit(1.f);
|
||||
FVector AdjustedVelocity = Velocity * deltaTime;
|
||||
FVector VelocityPlaneDirection = FVector::VectorPlaneProject(Velocity, SurfaceHit.Normal).GetSafeNormal();
|
||||
FQuat NewRotation = FRotationMatrix::MakeFromXZ(VelocityPlaneDirection, SurfaceHit.Normal).ToQuat();
|
||||
SafeMoveUpdatedComponent(AdjustedVelocity, NewRotation, true, Hit);
|
||||
|
||||
// Post Move Checks
|
||||
if (Hit.Time < 1.f)
|
||||
{
|
||||
HandleImpact(Hit, deltaTime, AdjustedVelocity);
|
||||
SlideAlongSurface(AdjustedVelocity, (1.f - Hit.Time), Hit.Normal, Hit, true);
|
||||
}
|
||||
|
||||
FHitResult NewSurfaceHit;
|
||||
if (!GetSlideSurface(NewSurfaceHit) || Velocity.SizeSquared() < pow(Slide_MinSpeed, 2))
|
||||
{
|
||||
ExitSlide();
|
||||
}
|
||||
|
||||
// Update outgoing Velocity and Acceleration
|
||||
if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
||||
{
|
||||
Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::GetSlideSurface(FHitResult& Hit) const
|
||||
{
|
||||
const FVector Start = UpdatedComponent->GetComponentLocation();
|
||||
const FVector End = Start + CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.f * FVector::DownVector;
|
||||
const FName ProfileName = TEXT("BlockAll");
|
||||
|
||||
return GetWorld()->LineTraceSingleByProfile(Hit, Start, End, ProfileName);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::OnDashCooldownFinished()
|
||||
{
|
||||
Safe_bWantsToDash = true;
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::CanDash()
|
||||
{
|
||||
return (IsWalking() || IsFalling()) && !IsCrouching() && !Safe_bWantsToAds;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::PerformDash()
|
||||
{
|
||||
DashStartTime = GetWorld()->GetTimeSeconds();
|
||||
|
||||
FVector DashDirection = (Acceleration.IsNearlyZero() ? UpdatedComponent->GetForwardVector() : Acceleration).GetSafeNormal2D();
|
||||
Velocity = Dash_Impulse * (DashDirection + FVector::UpVector * .1f);
|
||||
|
||||
FQuat NewRotation = FRotationMatrix::MakeFromXZ(DashDirection, FVector::UpVector).ToQuat();
|
||||
FHitResult Hit;
|
||||
SafeMoveUpdatedComponent(FVector::ZeroVector, NewRotation, false, Hit);
|
||||
|
||||
SetMovementMode(MOVE_Falling);
|
||||
|
||||
DashStartDelegate.Broadcast();
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Nakatomi.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "NakatomiCMC.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDashStartDelegate);
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum ECustomMovementMove
|
||||
{
|
||||
CMOVE_None UMETA(Hidden),
|
||||
CMOVE_Slide UMETA(DisplayName = "Slide"),
|
||||
CMOVE_Dash UMETA(DisplayName = "Dash"),
|
||||
CMOVE_MAX UMETA(Hidden),
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
class FSavedMove_Nakatomi : public FSavedMove_Character
|
||||
{
|
||||
using Super = FSavedMove_Character;
|
||||
|
||||
public:
|
||||
enum CompressedFlags
|
||||
{
|
||||
FLAG_Sprint = 0x10,
|
||||
FLAG_Dash = 0x20,
|
||||
FLAG_Custom2 = 0x30,
|
||||
FLAG_Custom3 = 0x40,
|
||||
};
|
||||
|
||||
// Flag
|
||||
uint8 Saved_bWantsToSprint : 1;
|
||||
uint8 Saved_bWantsToSlide : 1;
|
||||
uint8 Saved_bWantsToAds : 1;
|
||||
uint8 Saved_bWantsToDash : 1;
|
||||
|
||||
virtual bool
|
||||
CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
|
||||
virtual void Clear() override;
|
||||
virtual uint8 GetCompressedFlags() const override;
|
||||
virtual void SetMoveFor(ACharacter* C, float InDeltaTime, const FVector& NewAccel,
|
||||
FNetworkPredictionData_Client_Character& ClientData) override;
|
||||
virtual void PrepMoveFor(ACharacter* C) override;
|
||||
};
|
||||
|
||||
class FNetworkPredictionData_Client_Nakatomi : public FNetworkPredictionData_Client_Character
|
||||
{
|
||||
public:
|
||||
FNetworkPredictionData_Client_Nakatomi(const UCharacterMovementComponent& ClientMovement);
|
||||
|
||||
using Super = FNetworkPredictionData_Client_Character;
|
||||
|
||||
virtual FSavedMovePtr AllocateNewMove() override;
|
||||
};
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Sprint_MaxWalkSpeed = 1000.0f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Walk_MaxWalkSpeed = 500.0f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Crouch_MaxWalkSpeed = 250.0f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_MinSpeed = 50.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_EnterImpulse = 2000.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_GravityForce = 2500.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_Friction = 1.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Ads_Multiplier = 0.5f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Dash_Impulse = 1500.0f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Dash_CooldownDuration = 1.0f;
|
||||
|
||||
bool Safe_bWantsToSprint;
|
||||
bool Safe_bWantsToSlide;
|
||||
bool Safe_bWantsToAds;
|
||||
bool Safe_bWantsToDash;
|
||||
|
||||
float DashStartTime;
|
||||
FTimerHandle TimerHandle_DashCooldown;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
ANakatomiCharacter* NakatomiCharacterOwner;
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FDashStartDelegate DashStartDelegate;
|
||||
|
||||
public:
|
||||
UNakatomiCMC();
|
||||
|
||||
protected:
|
||||
virtual void InitializeComponent() override;
|
||||
|
||||
virtual FNetworkPredictionData_Client* GetPredictionData_Client() const override;
|
||||
|
||||
protected:
|
||||
virtual void UpdateFromCompressedFlags(uint8 Flags) override;
|
||||
|
||||
virtual void OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity) override;
|
||||
|
||||
virtual bool IsMovingOnGround() const override;
|
||||
|
||||
virtual bool CanCrouchInCurrentState() const override;
|
||||
|
||||
virtual void UpdateCharacterStateBeforeMovement(float DeltaSeconds) override;
|
||||
|
||||
virtual void PhysCustom(float deltaTime, int32 Iterations) override;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnableSprint();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableSprint();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnableCrouch();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableCrouch();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnableSlide();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableSlide();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnableAds();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableAds();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnableDash();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableDash();
|
||||
|
||||
UFUNCTION()
|
||||
bool IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const;
|
||||
|
||||
private:
|
||||
void EnterSlide();
|
||||
void ExitSlide();
|
||||
void PhysSlide(float deltaTime, int32 Iterations); // Every movement mode requires a physics function to work
|
||||
bool GetSlideSurface(FHitResult& Hit) const;
|
||||
|
||||
void OnDashCooldownFinished();
|
||||
bool CanDash();
|
||||
void PerformDash();
|
||||
};
|
|
@ -3,12 +3,17 @@
|
|||
|
||||
#include "NakatomiCharacter.h"
|
||||
|
||||
#include "NakatomiCMC.h"
|
||||
|
||||
// Sets default values
|
||||
ANakatomiCharacter::ANakatomiCharacter()
|
||||
ANakatomiCharacter::ANakatomiCharacter(const FObjectInitializer& ObjectInitializer) : Super(
|
||||
ObjectInitializer.SetDefaultSubobjectClass<UNakatomiCMC>(ACharacter::CharacterMovementComponentName))
|
||||
{
|
||||
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
NakatomiCMC = Cast<UNakatomiCMC>(GetCharacterMovement());
|
||||
|
||||
HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("Health Component"));
|
||||
HealthComponent->OnDamaged.BindUFunction(this, "OnDamaged");
|
||||
HealthComponent->OnDeath.BindUFunction(this, "OnDeath");
|
||||
|
@ -20,6 +25,8 @@ void ANakatomiCharacter::BeginPlay()
|
|||
Super::BeginPlay();
|
||||
|
||||
SetInventoryToDefault();
|
||||
|
||||
NakatomiCMC = Cast<UNakatomiCMC>(GetCharacterMovement());
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
|
@ -232,6 +239,11 @@ void ANakatomiCharacter::PushThrowableToInventory(TSubclassOf<AThrowable> Throwa
|
|||
}
|
||||
}
|
||||
|
||||
UNakatomiCMC* ANakatomiCharacter::GetCharacterMovementComponent()
|
||||
{
|
||||
return NakatomiCMC;
|
||||
}
|
||||
|
||||
void ANakatomiCharacter::CalculateHits(TArray<FHitResult>* hits)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "Nakatomi.h"
|
||||
#include "Throwable.h"
|
||||
#include "Weapon.h"
|
||||
#include "NakatomiCharacter.generated.h"
|
||||
|
@ -38,6 +39,10 @@ public:
|
|||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
TArray<TSubclassOf<AThrowable>> ThrowableInventory;
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Meta = (AllowPrivateAccess = "true"))
|
||||
UNakatomiCMC* NakatomiCMC;
|
||||
|
||||
private:
|
||||
UPROPERTY(VisibleDefaultsOnly)
|
||||
UHealthComponent* HealthComponent = nullptr;
|
||||
|
@ -47,9 +52,10 @@ private:
|
|||
UPROPERTY(EditDefaultsOnly)
|
||||
int MaximumThrowableInventorySize = 4;
|
||||
|
||||
|
||||
public:
|
||||
// Sets default values for this character's properties
|
||||
ANakatomiCharacter();
|
||||
ANakatomiCharacter(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
|
@ -98,6 +104,8 @@ public:
|
|||
|
||||
void PushThrowableToInventory(TSubclassOf<AThrowable> Throwable);
|
||||
|
||||
UNakatomiCMC* GetCharacterMovementComponent();
|
||||
|
||||
protected:
|
||||
virtual void CalculateHits(TArray<FHitResult>* hits);
|
||||
|
||||
|
|
|
@ -7,25 +7,26 @@
|
|||
#include <Components/CapsuleComponent.h>
|
||||
#include <Kismet/GameplayStatics.h>
|
||||
|
||||
#include "InputTriggers.h"
|
||||
#include "EnemyCharacter.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "EnemyCharacter.h"
|
||||
#include "InputTriggers.h"
|
||||
#include "InteractableComponent.h"
|
||||
#include "NakatomiCMC.h"
|
||||
#include "WeaponThrowable.h"
|
||||
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
|
||||
#define COLLISION_WEAPON ECC_GameTraceChannel1
|
||||
|
||||
// Sets default values
|
||||
APlayerCharacter::APlayerCharacter()
|
||||
APlayerCharacter::APlayerCharacter(const FObjectInitializer& ObjectInitializer) : ANakatomiCharacter(ObjectInitializer)
|
||||
{
|
||||
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
PrimaryActorTick.SetTickFunctionEnable(true);
|
||||
PrimaryActorTick.bStartWithTickEnabled = true;
|
||||
|
||||
|
||||
//bUseControllerRotationPitch = true;
|
||||
//bUseControllerRotationYaw = true;
|
||||
//bUseControllerRotationRoll = false;
|
||||
|
@ -56,9 +57,8 @@ APlayerCharacter::APlayerCharacter()
|
|||
CameraADSSpringArmComponent->SocketOffset = {0.0f, 50.0f, 75.0f};
|
||||
|
||||
// Setup the character movement
|
||||
UCharacterMovementComponent* CharacterMovementComponent = GetCharacterMovement();
|
||||
CharacterMovementComponent->AirControl = 1.0f;
|
||||
CharacterMovementComponent->bOrientRotationToMovement = true;
|
||||
GetCharacterMovement()->AirControl = 1.0f;
|
||||
GetCharacterMovement()->bOrientRotationToMovement = true;
|
||||
|
||||
// Setup the character perception component
|
||||
PerceptionSource = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Perception Source Stimuli"));
|
||||
|
@ -188,6 +188,24 @@ void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCom
|
|||
{
|
||||
Input->BindAction(PauseAction, ETriggerEvent::Completed, this, &APlayerCharacter::PauseCallback);
|
||||
}
|
||||
|
||||
if (CrouchAction)
|
||||
{
|
||||
Input->BindAction(CrouchAction, ETriggerEvent::Started, this, &APlayerCharacter::BeginCrouchCallback);
|
||||
Input->BindAction(CrouchAction, ETriggerEvent::Completed, this, &APlayerCharacter::EndCrouchCallback);
|
||||
}
|
||||
|
||||
if (SlideAction)
|
||||
{
|
||||
Input->BindAction(SlideAction, ETriggerEvent::Started, this, &APlayerCharacter::BeginSlideCallback);
|
||||
Input->BindAction(SlideAction, ETriggerEvent::Completed, this, &APlayerCharacter::EndSlideCallback);
|
||||
}
|
||||
|
||||
if (DashAction)
|
||||
{
|
||||
Input->BindAction(DashAction, ETriggerEvent::Started, this, &APlayerCharacter::BeginDashCallback);
|
||||
Input->BindAction(DashAction, ETriggerEvent::Completed, this, &APlayerCharacter::EndDashCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,16 +287,18 @@ void APlayerCharacter::QuitCallback(const FInputActionInstance& Instance)
|
|||
|
||||
void APlayerCharacter::SetSprintingCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
IsSpriting = true;
|
||||
|
||||
SetMovementSpeed();
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->EnableSprint();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::SetWalkingCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
IsSpriting = false;
|
||||
|
||||
SetMovementSpeed();
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->DisableSprint();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::CalculateHits(TArray<FHitResult>* hits)
|
||||
|
@ -448,22 +468,6 @@ void APlayerCharacter::OnDeath()
|
|||
UGameplayStatics::OpenLevel(this, FName(map), false);
|
||||
}
|
||||
|
||||
void APlayerCharacter::SetMovementSpeed()
|
||||
{
|
||||
if (IsADS)
|
||||
{
|
||||
GetCharacterMovement()->MaxWalkSpeed = DefaultMovementSpeed * ADSSpeedMultiplier;
|
||||
}
|
||||
else if (IsSpriting)
|
||||
{
|
||||
GetCharacterMovement()->MaxWalkSpeed = DefaultMovementSpeed * SprintSpeedMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetCharacterMovement()->MaxWalkSpeed = DefaultMovementSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::WeaponSwitchingCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
float value = Instance.GetValue().Get<float>();
|
||||
|
@ -482,7 +486,10 @@ void APlayerCharacter::BeginAimDownSightsCallback(const FInputActionInstance& In
|
|||
{
|
||||
IsADS = true;
|
||||
|
||||
SetMovementSpeed();
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->EnableAds();
|
||||
}
|
||||
|
||||
AimSensitivity = DefaultAimSensitivity * ADSAimSensitivityMultiplier;
|
||||
|
||||
|
@ -505,7 +512,10 @@ void APlayerCharacter::EndAimDownSightsCallback(const FInputActionInstance& Inst
|
|||
{
|
||||
IsADS = false;
|
||||
|
||||
SetMovementSpeed();
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->DisableAds();
|
||||
}
|
||||
|
||||
AimSensitivity = DefaultAimSensitivity;
|
||||
|
||||
|
@ -535,6 +545,54 @@ void APlayerCharacter::PauseCallback(const FInputActionInstance& Instance)
|
|||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::BeginCrouchCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->EnableCrouch();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::EndCrouchCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->DisableCrouch();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::BeginSlideCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->EnableSlide();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::EndSlideCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->DisableSlide();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::BeginDashCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->EnableDash();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::EndDashCallback(const FInputActionInstance& Instance)
|
||||
{
|
||||
if (UNakatomiCMC* cmc = GetCharacterMovementComponent())
|
||||
{
|
||||
cmc->DisableDash();
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerCharacter::OnFire()
|
||||
{
|
||||
if (!IsFiring || CurrentWeapon->GetAmmoCount() == 0)
|
||||
|
@ -683,4 +741,4 @@ AThrowable* APlayerCharacter::ThrowThrowable()
|
|||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
|
@ -2,19 +2,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "InputActionValue.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "NakatomiCharacter.h"
|
||||
#include "Weapon.h"
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "Engine/DamageEvents.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Perception/AIPerceptionStimuliSourceComponent.h"
|
||||
#include "InteractableComponent.h"
|
||||
#include "Throwable.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "Perception/AIPerceptionStimuliSourceComponent.h"
|
||||
#include "PlayerCharacter.generated.h"
|
||||
|
||||
class UInputAction;
|
||||
|
@ -63,6 +59,15 @@ public:
|
|||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
UInputAction* AimDownSightsAction;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
UInputAction* CrouchAction;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
UInputAction* SlideAction;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
UInputAction* DashAction;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
TSoftObjectPtr<UInputMappingContext> InputMappingContext;
|
||||
|
@ -82,9 +87,6 @@ protected:
|
|||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
float SprintSpeedMultiplier = 2.0f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
float ADSSpeedMultiplier = 0.5f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
float ADSAimSensitivityMultiplier = 0.5f;
|
||||
|
||||
|
@ -94,7 +96,7 @@ protected:
|
|||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
float DefaultAimSensitivity = 45.0f;
|
||||
|
||||
private:
|
||||
private:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
|
||||
USpringArmComponent* CameraSpringArmComponent = nullptr;
|
||||
|
||||
|
@ -119,7 +121,7 @@ private:
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
|
||||
UAIPerceptionStimuliSourceComponent* PerceptionSource;
|
||||
|
||||
bool IsSpriting = false;
|
||||
bool IsSprinting = false;
|
||||
|
||||
bool IsADS = false;
|
||||
|
||||
|
@ -132,7 +134,7 @@ private:
|
|||
|
||||
public:
|
||||
// Sets default values for this character's properties
|
||||
APlayerCharacter();
|
||||
APlayerCharacter(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
|
@ -170,6 +172,18 @@ public:
|
|||
void EndAimDownSightsCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void PauseCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void BeginCrouchCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void EndCrouchCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void BeginSlideCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void EndSlideCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void BeginDashCallback(const FInputActionInstance& Instance);
|
||||
|
||||
void EndDashCallback(const FInputActionInstance& Instance);
|
||||
|
||||
virtual void OnFire() override;
|
||||
|
||||
|
@ -206,6 +220,5 @@ protected:
|
|||
virtual void OnDamaged() override;
|
||||
|
||||
virtual void OnDeath() override;
|
||||
|
||||
void SetMovementSpeed();
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue