캐릭터 ASC에 GA 부여
APPGASCharacterPlayer 헤더파일
// GAS Section
protected:
virtual void SetupGASPlayerInputComponent();
void GASInputPressed(int32 InputID);
void GASInputReleased(int32 InputID);
UPROPERTY(EditAnywhere, Category = "GAS")
TArray<TSubclassOf<class UGameplayAbility>> StartAbilites;
UPROPERTY(EditAnywhere, Category = "GAS")
TMap<EInputAbility, TSubclassOf<class UGameplayAbility>> StartInputAbilites;
- virtual void SetupGASPlayerInputComponent();
- GA를 활성화 시키는 인풋액션을 Bind하는 함수
- SetupPlayerInputComponent 함수, PossessedBy 함수에서 한번씩 실행
- 바인드 과정에서 GA에 부여된 ID를 인자로 넘겨줄 수 있음
- void GASInputPressed(int32 InputID);
void GASInputReleased(int32 InputID);- 입력 시작, 완료 이벤트 콜백함수 매개변수로 GA에 부여된 ID를 받음
- TArray<TSubclassOf<class UGameplayAbility>> StartAbilites;
- 입력과 상관없이 발동되는 GA
- TArray 자료형을 사용해 GA를 받음
- ex) 애니메이션 노티파이로 AttackHitCheck_GA 실행
- 애니메이션 노티파이로 GA를 실행할 경우 입력과 상관없이 GA가 발동
- TMap<EInputAbility, TSubclassOf<class UGameplayAbility>> StartInputAbilites;
- 입력을 통해 발동되는 GA
- TMap 자료형을 통해 InputID로 지정할 EInputAbility Enum 클래스와 GA를 받음
- EInputAbility는 따로 선언한 Enum 클래스
- int32로 선언하면 직접 번호를 입력 해야 됨
하지만 Enum클래스를 사용하면 Enum을 통해 선택하므로 좀더 알아보기 편함
- int32로 선언하면 직접 번호를 입력 해야 됨
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPriaveteAccess = "true"))
TObjectPtr<class UInputAction> JumpAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPriaveteAccess = "true"))
TObjectPtr<class UInputAction> LookAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPriaveteAccess = "true"))
TObjectPtr<class UInputAction> SprintAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPriaveteAccess = "true"))
TObjectPtr<class UInputAction> LeftAttackAction;
- GA 입력에 필요한 InputAction 변수들을 선언
EInputAbility
UENUM(BlueprintType)
enum class EInputAbility : uint8
{
None UMETA(DisplayName = "None"),
Jump = 10 UMETA(DisplayName = "Jump"),
Sprint UMETA(DisplayName = "Sprint"),
LeftAttack UMETA(DisplayName = "LAttack"),
RightAttack UMETA(DisplayName = "RAttack"),
Skill UMETA(DisplayName = "Skill")
};
- Enum 클래스 선언시 UENUM(BlueprintType)를 붙여야 함
- 첫 시작 변수는 반드시 None(다른 변수명도 가능)을 생성해 0 부터 시작해야함
- 두번째 변수부터 숫자를 지정할 수 있음
- ex) 10을 지정하면 그 다음부터 11, 12 순으로 이어짐
- UMETA(DisplayName = "None") 매크로는 에디터에 Enum 변수들이 표기되는 이름을 설정
APPGASCharacterPlayer Cpp 파일
생성자
APPGASCharacterPlayer::APPGASCharacterPlayer()
{
//GAS 인풋 설정
static ConstructorHelpers::FObjectFinder<UInputAction> JumpInputActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/Project_P/Input/Actions/IA_Jump.IA_Jump'"));
if (JumpInputActionRef.Object)
{
JumpAction = JumpInputActionRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction> LookInputActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/Project_P/Input/Actions/IA_Look.IA_Look'"));
if (LookInputActionRef.Object)
{
LookAction = LookInputActionRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction> SprintActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/Project_P/Input/Actions/IA_Sprint.IA_Sprint'"));
if (SprintActionRef.Object)
{
SprintAction = SprintActionRef.Object;
}
static ConstructorHelpers::FObjectFinder<UInputAction> LeftAttackActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/Project_P/Input/Actions/IA_LeftAttack.IA_LeftAttack'"));
if (LeftAttackActionRef.Object)
{
LeftAttackAction = LeftAttackActionRef.Object;
}
}
- GA 입력에 필요한 InputAction 변수들을 생성자에서 ConstructorHelpers를 이용해 애셋에서 불러옴
PossessedBy
void APPGASCharacterPlayer::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
APPGASPlayerState* GASPlayerState = GetPlayerState<APPGASPlayerState>();
if (GASPlayerState)
{
ASC = GASPlayerState->GetAbilitySystemComponent();
if (ASC)
{
ASC->InitAbilityActorInfo(GASPlayerState, this);
for (const TSubclassOf<UGameplayAbility>& StartAbility : StartAbilites)
{
//ASC는 직접적으로 GA를 접근, 관리하는게 아닌
//FGameplayAbilitySpec 구조체를 통해 간접적으로 관리함
FGameplayAbilitySpec Spec(StartAbility);
ASC->GiveAbility(Spec);
}
for (const TPair<EInputAbility, TSubclassOf<class UGameplayAbility>>& StartInputAbility : StartInputAbilites)
{
FGameplayAbilitySpec Spec(StartInputAbility.Value);
Spec.InputID = (int32)StartInputAbility.Key;
ASC->GiveAbility(Spec);
}
//서버에서도 GA바인드 함수가 실행되도록 실행
SetupGASPlayerInputComponent();
}
}
//콘솔 커멘드 코드로 입력하는 법
//ASC 디버그
APlayerController* PlayerController = CastChecked<APlayerController>(NewController);
PlayerController->ConsoleCommand(TEXT("showdebug abilitysystem"));
}
- for (const TSubclassOf<UGameplayAbility>& StartAbility : StartAbilites)
{
FGameplayAbilitySpec Spec(StartAbility);
ASC->GiveAbility(Spec);
}- for문을 사용해 StartAbilites에 있는 인자들을 StartAbility로 받음
- FGameplayAbilitySpec Spec(StartAbility);
- StartAbility를 갖고있는 FGameplayAbilitySpec을 생성
- ASC에 GA를 등록하려면 FGameplayAbilitySpec을 통해 간접적으로 등록 해야함
- ASC->GiveAbility(Spec);
- 만든 Spec을 가지고 ASC에 등록
- for (const TPair<EInputAbility, TSubclassOf<class UGameplayAbility>>& StartInputAbility : StartInputAbilites)
{
FGameplayAbilitySpec Spec(StartInputAbility.Value);
Spec.InputID = (int32)StartInputAbility.Key;
ASC->GiveAbility(Spec);
}- 위 반복문과 동일하게 Spec 생성
- Spec.InputID = (int32)StartInputAbility.Key;
- Spec에 선언되어 있는 InputID에 ID 등록
- EInputAbility로 선언해 int32로 형변환을 해야함
- SetupGASPlayerInputComponent();
- GA를 사용하는 인풋 액션 바인드 함수
- 서버에서도 GA바인드 함수가 실행되도록 PossessedBy함수에서도 실행
- APlayerController* PlayerController = CastChecked<APlayerController>(NewController);
PlayerController->ConsoleCommand(TEXT("showdebug abilitysystem"));- 에디터에서 `를 누른뒤 showdebug abilitysystem 입력하면 GAS 디버깅을 할 수 있음
- 매번 입력하기 힘드니 위와 같은 코드로도 커맨드를 입력할 수 있음
SetupGASPlayerInputComponent
void APPGASCharacterPlayer::SetupGASPlayerInputComponent()
{
if (IsValid(ASC) && IsValid(InputComponent))
{
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent);
//Jump
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &APPGASCharacterPlayer::GASInputPressed, (int32)EInputAbility::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &APPGASCharacterPlayer::GASInputReleased, (int32)EInputAbility::Jump);
//Sprint
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Triggered, this, &APPGASCharacterPlayer::GASInputPressed, (int32)EInputAbility::Sprint);
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &APPGASCharacterPlayer::GASInputReleased, (int32)EInputAbility::Sprint);
//Attack
EnhancedInputComponent->BindAction(LeftAttackAction, ETriggerEvent::Triggered, this, &APPGASCharacterPlayer::GASInputPressed, (int32)EInputAbility::LeftAttack);
EnhancedInputComponent->BindAction(LeftAttackAction, ETriggerEvent::Completed, this, &APPGASCharacterPlayer::GASInputReleased, (int32)EInputAbility::LeftAttack);
}
}
- if (IsValid(ASC) && IsValid(InputComponent))
- GA를 사용하는 인풋액션이므로 ASC와 인풋컴포넌트가 존재하는지 확인
- EnhancedInputComponent->
BindAction(JumpAction, ETriggerEvent::Triggered, this, &APPGASCharacterPlayer::GASInputPressed,
(int32)EInputAbility::Jump);
EnhancedInputComponent->
BindAction(JumpAction, ETriggerEvent::Completed, this, &APPGASCharacterPlayer::GASInputReleased,
(int32)EInputAbility::Jump);- Jump, Sprint, Attack GA에 대해 Tirggered, Completed 이벤트 바인드
GASInputPressed
void APPGASCharacterPlayer::GASInputPressed(int32 InputID)
{
FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputID);
if (Spec)
{
Spec->InputPressed = true;
if (Spec->IsActive())
{
//어빌리티가 실행중이면 GA의 InputPressed 함수 실행
ASC->AbilitySpecInputPressed(*Spec);
}
else
{
//어빌리티 Activate 실행
//어빌리티의 실행 등 ASC로부터 GA를 다루는건 Handle을 통해 컨트롤
ASC->TryActivateAbility(Spec->Handle);
}
}
}
- FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputID);
- PossessedBy 함수에서 ASC에 GA를 등록할때 스펙에 부여한 InputID를 통해
ASC로 부터 Spec을 찾아올 수 있음
- PossessedBy 함수에서 ASC에 GA를 등록할때 스펙에 부여한 InputID를 통해
- if (Spec)
- 스펙이 존재하면
- Spec->InputPressed = true;
- 해당 GA가 인풋이 들어왔다고 true로 변경
- Spec 자체에 선언되어 있음
- if (Spec->IsActive())
- ASC->AbilitySpecInputPressed(*Spec);
- 어빌리티가 실행중이면 GA의 InputPressed 함수 실행
- AbilitySpecInputPressed 함수에선 Spec.GetAbilityInstances() 함수로 인스턴스를 가져와
해당 인스턴스로 Instance->InputPressed() 함수를 실행
- ASC->AbilitySpecInputPressed(*Spec);
- else
- ASC->TryActivateAbility(Spec->Handle);
- 어빌리티 Activate 실행
- 어빌리티의 실행 등 ASC로부터 GA를 다루는건 Handle을 통해 컨트롤
- ASC->TryActivateAbility(Spec->Handle);
GASInputReleased
void APPGASCharacterPlayer::GASInputReleased(int32 InputID)
{
FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputID);
if (Spec)
{
Spec->InputPressed = false;
if (Spec->IsActive())
{
//어빌리티가 실행중이면 GA의 InputReleased 실행
ASC->AbilitySpecInputReleased(*Spec);
}
}
}
- FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputID);
- InputID로 Spec가져오기
- if (Spec)
- Spec->InputPressed = false;
- 입력이 끝났다고 false로 변경
- if (Spec->IsActive())
- ASC->AbilitySpecInputReleased(*Spec);
- 어빌리티가 실행중이면 GA의 InputReleased 실행
- ASC->AbilitySpecInputReleased(*Spec);
- Spec->InputPressed = false;
캐릭터 블루프린트에 GA 부여
- Start Input Abilites에 + 버튼을 눌러 element 추가
- 추가한 element 에 추가할 GA에 맞는 키값(Enum)을 부여
- 오른쪽에 밸류값(GA) 설정
'포트폴리오 제작 > Project_P' 카테고리의 다른 글
Project_P GA 블루프린트 생성 및 태그 설정 (0) | 2024.08.28 |
---|---|
Project_P 게임플레이 태그 관리 및 추가 (0) | 2024.08.27 |
Project_P 캐릭터 달리기 구현 Sprint GA 생성 (0) | 2024.08.23 |
Project_P 캐릭터 애니메이션 설정(5) Upper Body Layer와 애니메이션 마무리 (0) | 2024.07.31 |
Project_P 캐릭터 애니메이션 설정(4) Locomotion 설정 (0) | 2024.07.30 |