Compare commits

...

2 Commits

Author SHA1 Message Date
baz 9d4dc1b4f2 Add Input Actions to Dash on character 2024-01-17 02:17:38 +00:00
baz 1986bd2092 Implement basic dash in NakatomiCMC 2024-01-17 02:17:17 +00:00
7 changed files with 160 additions and 27 deletions

BIN
Content/Input/Actions/IA_Dash.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Input/InputMappingContext.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Player/PlayerCharacter.uasset (Stored with Git LFS)

Binary file not shown.

View File

@ -31,6 +31,11 @@ bool UNakatomiCMC::FSavedMove_Nakatomi::CanCombineWith(const FSavedMovePtr& NewM
{ {
return false; return false;
} }
if (Saved_bWantsToDash != newMove->Saved_bWantsToDash)
{
return false;
}
return FSavedMove_Character::CanCombineWith(NewMove, InCharacter, MaxDelta); return FSavedMove_Character::CanCombineWith(NewMove, InCharacter, MaxDelta);
} }
@ -41,6 +46,9 @@ void UNakatomiCMC::FSavedMove_Nakatomi::Clear()
FSavedMove_Character::Clear(); FSavedMove_Character::Clear();
Saved_bWantsToSprint = 0; Saved_bWantsToSprint = 0;
Saved_bWantsToSlide = 0;
Saved_bWantsToAds = 0;
Saved_bWantsToDash = 0;
} }
uint8 UNakatomiCMC::FSavedMove_Nakatomi::GetCompressedFlags() const uint8 UNakatomiCMC::FSavedMove_Nakatomi::GetCompressedFlags() const
@ -48,6 +56,7 @@ uint8 UNakatomiCMC::FSavedMove_Nakatomi::GetCompressedFlags() const
uint8 Result = Super::GetCompressedFlags(); uint8 Result = Super::GetCompressedFlags();
if (Saved_bWantsToSprint) Result = ~FLAG_Custom_0; if (Saved_bWantsToSprint) Result = ~FLAG_Custom_0;
if (Saved_bWantsToDash) Result = ~FLAG_Dash;
return Result; return Result;
} }
@ -62,6 +71,7 @@ void UNakatomiCMC::FSavedMove_Nakatomi::SetMoveFor(ACharacter* C, float InDeltaT
Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint; Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint;
Saved_bWantsToSlide = CharacterMovement->Safe_bWantsToSlide; Saved_bWantsToSlide = CharacterMovement->Safe_bWantsToSlide;
Saved_bWantsToAds = CharacterMovement->Safe_bWantsToAds; Saved_bWantsToAds = CharacterMovement->Safe_bWantsToAds;
Saved_bWantsToDash = CharacterMovement->Safe_bWantsToDash;
} }
void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C) void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
@ -73,6 +83,7 @@ void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint; CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint;
CharacterMovement->Safe_bWantsToSlide = Saved_bWantsToSlide; CharacterMovement->Safe_bWantsToSlide = Saved_bWantsToSlide;
CharacterMovement->Safe_bWantsToAds = Saved_bWantsToAds; CharacterMovement->Safe_bWantsToAds = Saved_bWantsToAds;
CharacterMovement->Safe_bWantsToDash = Saved_bWantsToDash;
} }
UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi( UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi(
@ -106,6 +117,7 @@ void UNakatomiCMC::UpdateFromCompressedFlags(uint8 Flags)
Super::UpdateFromCompressedFlags(Flags); Super::UpdateFromCompressedFlags(Flags);
Safe_bWantsToSprint = (Flags & FSavedMove_Character::FLAG_Custom_0) != 0; 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) void UNakatomiCMC::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity)
@ -154,6 +166,7 @@ bool UNakatomiCMC::CanCrouchInCurrentState() const
void UNakatomiCMC::UpdateCharacterStateBeforeMovement(float DeltaSeconds) void UNakatomiCMC::UpdateCharacterStateBeforeMovement(float DeltaSeconds)
{ {
// Slide
if (MovementMode == MOVE_Walking && Safe_bWantsToSlide && !Safe_bWantsToAds) if (MovementMode == MOVE_Walking && Safe_bWantsToSlide && !Safe_bWantsToAds)
{ {
FHitResult PotentialSlideSurface; FHitResult PotentialSlideSurface;
@ -167,6 +180,13 @@ void UNakatomiCMC::UpdateCharacterStateBeforeMovement(float DeltaSeconds)
{ {
ExitSlide(); ExitSlide();
} }
// Dash
if (Safe_bWantsToDash && CanDash() && !Safe_bWantsToAds)
{
PerformDash();
Safe_bWantsToDash = false;
}
Super::UpdateCharacterStateBeforeMovement(DeltaSeconds); Super::UpdateCharacterStateBeforeMovement(DeltaSeconds);
} }
@ -225,6 +245,27 @@ void UNakatomiCMC::DisableAds()
Safe_bWantsToAds = false; 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 bool UNakatomiCMC::IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const
{ {
return MovementMode == MOVE_Custom && CustomMovementMode == InCustomMovementMode; return MovementMode == MOVE_Custom && CustomMovementMode == InCustomMovementMode;
@ -322,3 +363,29 @@ bool UNakatomiCMC::GetSlideSurface(FHitResult& Hit) const
return GetWorld()->LineTraceSingleByProfile(Hit, Start, End, ProfileName); 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();
}

View File

@ -7,12 +7,15 @@
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "NakatomiCMC.generated.h" #include "NakatomiCMC.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDashStartDelegate);
UENUM(BlueprintType) UENUM(BlueprintType)
enum ECustomMovementMove enum ECustomMovementMove
{ {
CMOVE_None UMETA(Hidden), CMOVE_None UMETA(Hidden),
CMOVE_Slide UMETA(DisplayName = "Slide"), CMOVE_Slide UMETA(DisplayName = "Slide"),
CMOVE_MAX UMETA(Hidden), CMOVE_Dash UMETA(DisplayName = "Dash"),
CMOVE_MAX UMETA(Hidden),
}; };
/** /**
@ -25,19 +28,29 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
class FSavedMove_Nakatomi : public FSavedMove_Character class FSavedMove_Nakatomi : public FSavedMove_Character
{ {
typedef FSavedMove_Character Super; using Super = FSavedMove_Character;
public:
enum CompressedFlags
{
FLAG_Sprint = 0x10,
FLAG_Dash = 0x20,
FLAG_Custom2 = 0x30,
FLAG_Custom3 = 0x40,
};
// Flag // Flag
uint8 Saved_bWantsToSprint:1; uint8 Saved_bWantsToSprint : 1;
uint8 Saved_bWantsToSlide : 1;
uint8 Saved_bWantsToSlide:1; uint8 Saved_bWantsToAds : 1;
uint8 Saved_bWantsToDash : 1;
uint8 Saved_bWantsToAds:1; virtual bool
CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
virtual void Clear() override; virtual void Clear() override;
virtual uint8 GetCompressedFlags() const override; virtual uint8 GetCompressedFlags() const override;
virtual void SetMoveFor(ACharacter* C, float InDeltaTime, FVector const& NewAccel, FNetworkPredictionData_Client_Character& ClientData) override; virtual void SetMoveFor(ACharacter* C, float InDeltaTime, const FVector& NewAccel,
FNetworkPredictionData_Client_Character& ClientData) override;
virtual void PrepMoveFor(ACharacter* C) override; virtual void PrepMoveFor(ACharacter* C) override;
}; };
@ -46,7 +59,7 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
public: public:
FNetworkPredictionData_Client_Nakatomi(const UCharacterMovementComponent& ClientMovement); FNetworkPredictionData_Client_Nakatomi(const UCharacterMovementComponent& ClientMovement);
typedef FNetworkPredictionData_Client_Character Super; using Super = FNetworkPredictionData_Client_Character;
virtual FSavedMovePtr AllocateNewMove() override; virtual FSavedMovePtr AllocateNewMove() override;
}; };
@ -56,10 +69,10 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float Walk_MaxWalkSpeed = 500.0f; float Walk_MaxWalkSpeed = 500.0f;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float Crouch_MaxWalkSpeed = 250.0f; float Crouch_MaxWalkSpeed = 250.0f;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float Slide_MinSpeed = 50.f; float Slide_MinSpeed = 50.f;
@ -74,21 +87,36 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float Ads_Multiplier = 0.5f; float Ads_Multiplier = 0.5f;
UPROPERTY(EditDefaultsOnly)
float Dash_Impulse = 1500.0f;
UPROPERTY(EditDefaultsOnly)
float Dash_CooldownDuration = 1.0f;
bool Safe_bWantsToSprint; bool Safe_bWantsToSprint;
bool Safe_bWantsToSlide; bool Safe_bWantsToSlide;
bool Safe_bWantsToAds; bool Safe_bWantsToAds;
bool Safe_bWantsToDash;
float DashStartTime;
FTimerHandle TimerHandle_DashCooldown;
UPROPERTY(Transient) UPROPERTY(Transient)
ANakatomiCharacter* NakatomiCharacterOwner; ANakatomiCharacter* NakatomiCharacterOwner;
public:
UPROPERTY(BlueprintAssignable)
FDashStartDelegate DashStartDelegate;
public: public:
UNakatomiCMC(); UNakatomiCMC();
protected: protected:
void InitializeComponent() override; virtual void InitializeComponent() override;
virtual FNetworkPredictionData_Client* GetPredictionData_Client() const override;
FNetworkPredictionData_Client* GetPredictionData_Client() const override;
protected: protected:
virtual void UpdateFromCompressedFlags(uint8 Flags) override; virtual void UpdateFromCompressedFlags(uint8 Flags) override;
@ -101,7 +129,7 @@ protected:
virtual void UpdateCharacterStateBeforeMovement(float DeltaSeconds) override; virtual void UpdateCharacterStateBeforeMovement(float DeltaSeconds) override;
virtual void PhysCustom(float deltaTime, int32 Iterations) override; virtual void PhysCustom(float deltaTime, int32 Iterations) override;
public: public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void EnableSprint(); void EnableSprint();
@ -127,16 +155,22 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void DisableAds(); void DisableAds();
UFUNCTION(BlueprintCallable)
void EnableDash();
UFUNCTION(BlueprintCallable)
void DisableDash();
UFUNCTION() UFUNCTION()
bool IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const; bool IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const;
private: private:
void EnterSlide(); void EnterSlide();
void ExitSlide(); void ExitSlide();
void PhysSlide(float deltaTime, int32 Iterations); // Every movement mode requires a physics function to work void PhysSlide(float deltaTime, int32 Iterations); // Every movement mode requires a physics function to work
bool GetSlideSurface(FHitResult& Hit) const; bool GetSlideSurface(FHitResult& Hit) const;
void OnDashCooldownFinished();
bool CanDash();
void PerformDash();
}; };

View File

@ -199,6 +199,12 @@ void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCom
Input->BindAction(SlideAction, ETriggerEvent::Started, this, &APlayerCharacter::BeginSlideCallback); Input->BindAction(SlideAction, ETriggerEvent::Started, this, &APlayerCharacter::BeginSlideCallback);
Input->BindAction(SlideAction, ETriggerEvent::Completed, this, &APlayerCharacter::EndSlideCallback); 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);
}
} }
} }
@ -570,6 +576,22 @@ void APlayerCharacter::EndSlideCallback(const FInputActionInstance& Instance)
} }
} }
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() void APlayerCharacter::OnFire()
{ {
if (!IsFiring || CurrentWeapon->GetAmmoCount() == 0) if (!IsFiring || CurrentWeapon->GetAmmoCount() == 0)

View File

@ -70,6 +70,9 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
UInputAction* SlideAction; UInputAction* SlideAction;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
UInputAction* DashAction;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
TSoftObjectPtr<UInputMappingContext> InputMappingContext; TSoftObjectPtr<UInputMappingContext> InputMappingContext;
@ -185,6 +188,10 @@ public:
void BeginSlideCallback(const FInputActionInstance& Instance); void BeginSlideCallback(const FInputActionInstance& Instance);
void EndSlideCallback(const FInputActionInstance& Instance); void EndSlideCallback(const FInputActionInstance& Instance);
void BeginDashCallback(const FInputActionInstance& Instance);
void EndDashCallback(const FInputActionInstance& Instance);
virtual void OnFire() override; virtual void OnFire() override;