캐릭터 동작 연결/추가하기

InputMappingContext에 연결하기


코드로 연결하기
Character.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "DCCharacter.generated.h"
class UInputMappingContext;
class UInputAction;
class UAnimMontage;
UCLASS()
class DC_API ADCCharacter : public ACharacter
{
GENERATED_BODY()
public:
ADCCharacter();
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputMappingContext> DefaultMappingContext;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> MoveAction;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> LookAction;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> JumpAction;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> DanceAction;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> AttackAction;
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputAction> SlideAction;
UPROPERTY(EditDefaultsOnly, Category="Anim")
TObjectPtr<UAnimMontage> AttackMontage;
UFUNCTION(BlueprintPure, Category="State")
bool GetIsDancing() const
{
return bIsDancing;
}
UFUNCTION(BlueprintPure, Category="State")
bool GetCanAttack() const
{
return bCanAttack;
}
UFUNCTION(BlueprintPure, Category="State")
bool GetIsSliding() const
{
return bIsSliding;
}
protected:
UPROPERTY(Replicated)
float CurrentHealth = 100.f;
UPROPERTY(Replicated)
bool bIsCriminal = false;
UPROPERTY(ReplicatedUsing=OnRep_IsDancing)
bool bIsDancing = false;
UPROPERTY(Replicated)
bool bCanAttack = false;
UPROPERTY(ReplicatedUsing=OnRep_IsSliding)
bool bIsSliding = false;
FTimerHandle AttackTimerHandle;
protected:
void Move(const struct FInputActionValue& Value);
void Look(const struct FInputActionValue& Value);
void Dance(const struct FInputActionValue& Value);
void Attack(const struct FInputActionValue& Value);
void StartSlide(const struct FInputActionValue& Value);
void EndSlide(const struct FInputActionValue& Value);
UFUNCTION(Server, Reliable)
void Server_SetIsDancing(bool NewValue);
UFUNCTION(Server, Reliable)
void Server_SetIsSliding(bool NewValue);
UFUNCTION()
void OnRep_IsSliding();
UFUNCTION()
void OnRep_IsDancing();
void EnableAttack();
public:
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
protected:
float CurrentHP = 100.f;
float MaxHP = 100.f;
float MaxSpeed = 700.f;
public:
float GetCurrentHP() const { return CurrentHP; }
float GetMaxHP() const { return MaxHP; }
void SetCurrentHP(float NewHP);
float GetMaxSpeed() const { return MaxSpeed; }
};
Character.cpp
#include "Character/DCCharacter.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Net/UnrealNetwork.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Components/CapsuleComponent.h"
#include "Components/PrimitiveComponent.h"
#include "GameFramework/Character.h"
#include "TimerManager.h"
ADCCharacter::ADCCharacter()
{
PrimaryActorTick.bCanEverTick = true;
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.f);
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);
}
void ADCCharacter::BeginPlay()
{
Super::BeginPlay();
if (APlayerController* PC = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
}
void ADCCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADCCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
EIC->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ADCCharacter::Move);
EIC->BindAction(LookAction, ETriggerEvent::Triggered, this, &ADCCharacter::Look);
EIC->BindAction(DanceAction, ETriggerEvent::Started, this, &ADCCharacter::Dance);
EIC->BindAction(AttackAction, ETriggerEvent::Started, this, &ADCCharacter::Attack);
EIC->BindAction(SlideAction, ETriggerEvent::Started, this, &ADCCharacter::StartSlide);
EIC->BindAction(SlideAction, ETriggerEvent::Completed, this, &ADCCharacter::EndSlide);
}
}
void ADCCharacter::Move(const FInputActionValue& Value)
{
if (bIsDancing)
{
return;
}
const FVector2D Axis = Value.Get<FVector2D>();
if (Controller)
{
const FRotator ControlRot = Controller->GetControlRotation();
const FVector Forward = FRotationMatrix(ControlRot).GetUnitAxis(EAxis::X);
const FVector Right = FRotationMatrix(ControlRot).GetUnitAxis(EAxis::Y);
AddMovementInput(Forward, Axis.Y);
AddMovementInput(Right, Axis.X);
}
}
void ADCCharacter::Look(const FInputActionValue& Value)
{
const FVector2D Axis = Value.Get<FVector2D>();
if (Controller)
{
AddControllerYawInput(Axis.X);
AddControllerPitchInput(Axis.Y);
}
}
void ADCCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ADCCharacter, CurrentHealth);
DOREPLIFETIME(ADCCharacter, bIsCriminal);
DOREPLIFETIME(ADCCharacter, bIsSliding);
DOREPLIFETIME(ADCCharacter, bIsDancing);
DOREPLIFETIME(ADCCharacter, bCanAttack);
}
void ADCCharacter::SetCurrentHP(float NewHP)
{
CurrentHP = FMath::Clamp(NewHP, 0.f, MaxHP);
if (CurrentHP <= 0.f)
{
}
}
void ADCCharacter::Dance(const FInputActionValue& )
{
if (bIsDancing)
{
return;
}
if (HasAuthority())
{
Server_SetIsDancing(true);
}
else
{
Server_SetIsDancing(true);
}
UE_LOG(LogTemp, Warning, TEXT("춤 시작"));
GetWorldTimerManager().SetTimer(AttackTimerHandle, this, &ADCCharacter::EnableAttack, 5.0f, false);
}
void ADCCharacter::Attack(const FInputActionValue& )
{
if (!bCanAttack)
{
UE_LOG(LogTemp, Warning, TEXT("공격 불가"));
return;
}
UE_LOG(LogTemp, Warning, TEXT("공격!"));
bCanAttack = false;
if (AttackMontage)
{
if (UAnimInstance* AnimInst = GetMesh() ? GetMesh()->GetAnimInstance() : nullptr)
{
AnimInst->Montage_Play(AttackMontage, 1.0f);
}
}
}
void ADCCharacter::EnableAttack()
{
if (HasAuthority())
{
Server_SetIsDancing(false);
}
else
{
Server_SetIsDancing(false);
}
bCanAttack = true;
UE_LOG(LogTemp, Warning, TEXT("춤 종료, 공격 가능"));
}
void ADCCharacter::Server_SetIsDancing_Implementation(bool NewValue)
{
bIsDancing = NewValue;
if (bIsDancing)
{
GetCharacterMovement()->StopMovementImmediately();
GetCharacterMovement()->DisableMovement();
}
else
{
GetCharacterMovement()->SetMovementMode(MOVE_Walking);
}
OnRep_IsDancing();
}
void ADCCharacter::Server_SetIsSliding_Implementation(bool NewValue)
{
bIsSliding = NewValue;
OnRep_IsSliding();
}
void ADCCharacter::OnRep_IsSliding()
{
if (bIsSliding)
{
UE_LOG(LogTemp, Warning, TEXT("슬라이드 시작"));
GetCharacterMovement()->MaxWalkSpeed = 300.f;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("슬라이드 종료"));
GetCharacterMovement()->MaxWalkSpeed = 600.f;
}
}
void ADCCharacter::OnRep_IsDancing()
{
}
void ADCCharacter::StartSlide(const FInputActionValue& )
{
const FVector Center = GetActorLocation();
const float Radius = 200.f;
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
TArray<AActor*> ActorsToIgnore;
ActorsToIgnore.Add(this);
TArray<AActor*> OutActors;
UKismetSystemLibrary::SphereOverlapActors(
GetWorld(),
Center,
Radius,
ObjectTypes,
AActor::StaticClass(),
ActorsToIgnore,
OutActors
);
for (AActor* OverlappedActor : OutActors)
{
if (ACharacter* OtherCharacter = Cast<ACharacter>(OverlappedActor))
{
FVector LaunchDir = OtherCharacter->GetActorLocation() - GetActorLocation();
LaunchDir.Normalize();
const float CurrentSpeed = GetVelocity().Size();
const float PushStrength = FMath::Clamp(CurrentSpeed * 1.5f, 500.f, 1500.f);
OtherCharacter->LaunchCharacter(LaunchDir * PushStrength, true, true);
}
}
if (HasAuthority())
{
Server_SetIsSliding(true);
}
else
{
Server_SetIsSliding(true);
}
}
void ADCCharacter::EndSlide(const FInputActionValue& )
{
if (HasAuthority())
{
Server_SetIsSliding(false);
}
else
{
Server_SetIsSliding(false);
}
}