Ability System Component

Lee Raccoon·2024년 8월 28일
0

Ability System Component

컴포넌트 생성

이전 포스트에서 환경을 설정 했으니 컴포넌트 생성을 해보았다.

현재 Enemy와 플레이어 캐릭터가 같은 Base를 상속받는 설계이다.
Base에다가 만들어주자.

전에 알아봤던대로 플레이어의 ASC는 플레이어 스테이트에 위치하게 될 것이긴한데 나중에 처리하도록 한다.

UPROPERTY()
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

UPROPERTY()
TObjectPtr<UAttributeSet> AttributeSet;

현재 플레이어와 몬스터 공용으로 쓸 캐릭터 클래스에 생성을 해주었다.
그리고 생성자에서 이들을 초기화해주자

//PlayerState 생성자 내 코드 예시
AbilitySystemComponent = CreateDefaultSubobject<UAuraAbilitySystemComponent>("AbilitySystemComponent");
AbilitySystemComponent->SetIsReplicated(true);
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);

AttributeSet = CreateDefaultSubobject<UAuraAttributeSet>("AbttributeSet");

멀티플레이를 전제로 게임을 만들기 때문에 Replicated를 true로 해준다.
여기서 SetReplicationMode에서 GamePlayEffectReplication을 설정할 수 있는데

아직 GamePlayEffect에 대해서는 배운게 없기 때문에 일단 아래 표를 보고 설정을 해주었다.

UseCase를 따라서 플레이어는 Mixed를, Enemy들은 Minimal Mode로 설정하기로한다.

주의할 점은 MixedReplicationMode로 설정하게 되면 오너 액터의 오너는 반드시 컨트롤러여야한다.
그러니까, ASC의 오너인 액터는 컨트롤러가 오너여야한다는 것이다.

지금 상황에서는 ASC의 오너는 Player State이다.
다행히 PlayerState의 경우, 자동으로 Controller가 오너가 되기 때문에 신경을 쓸 필요가 없다.
하지만 반드시 알아두어야 할 주의사항이다.
PlayerState를 오너로 하지 않는 경우, 꼭 SetOwner를 사용해서 Controller를 Owner로 지정해주자!

AbilitySystemInterface

UCLASS(Abstract)
class AURA_API AAuraCharacterBase : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	AAuraCharacterBase();
	
    //~Begin AbilitySystemInterface
	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
	UAttributeSet* GetAttributeSet() const { return AttributeSet; }
}

Getter가 하나 들어있는 인터페이스이다. 이걸로 해당 액터가 ASC를 구현하는 지 확인할 수 있어 유용하게 사용할 수 있다.
인터페이스에 포함되어 있지는 않지만 GetAttributeSet도 만들어 둔다면 유용하게 사용할 수 있다.

만약 추후에도 ASC를 사용하게 된다면 이렇게 Getter를 설정해두는 것이 일종의 보일러 플레이트이다.

Ability Actor Info

어빌리티 시스템은 항상 이 시스템을 소유하고 있는 액터의 정보를 알 수 있다.

이 ActorInfo는 Owner Actor와 Avatar Actor로 나뉘게 된다.

Owner Actor는 말 그대로 이 시스템을 소유한 액터를 나타낸다.
Avatar Actor는 월드에서 이 시스템을 대표하는 액터를 나타낸다. 실제로 게임 내에서 보이게 될 액터라고 생각하면 편하다.
중요한 것은, 이 둘이 다를 수도 있다는 것이다.

예를 들어보자면,
현재 Enemy의 경우 생성자에서 직접 ASC를 생성하기 때문에 Owner Actor라고 할 수 있고, 또한 Avatar Actor도 Enemy이다.

하지만 플레이어 캐릭터의 경우,
현재 ASC는 플레이어 스테이트에서 생성되어 Owner Actor는 플레이어 스테이트다.
그런데 월드에서 이 시스템을 대표하여 활동하게 되는 것은 플레이어 캐릭터이기 때문에 캐릭터가 Avatar Actor가 된다.

이들은 각각
UAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor);
위 함수를 통해서 이를 정해줄 수 있다.

근데 이 함수를 어디서 불러야하는가? 를 알아보자.

Actor Info 설정

  • 빙의가 끝난 후 호출되어야 한다. (컨트롤러가 pawn에 set 된 상태여야한다.)

Pawn이 소유자, 아바타인 경우

  • Server에서 호출한다면 PossessedBy에서 호출
  • Client에서 호출한다면 AcknowledgePossession에서 호출

위 방법으로 빙의를 보장할 수 있다.

문제는 지금은 Pawn이 소유자가 아닌 경우라는 것.

PlayerState가 소유자, 캐릭터가 아바타인 경우

  • Server에서 호출한다면 PossessedBy에서 호출
  • Client에서 호출한다면 OnRep_PlayerState에서 호출

PlayerState가 소유자인 경우, 컨트롤러가 set되는 것만이 아니라 PlayerState도 valid한지 확인해주어야하기 때문
(OnRep_함수들은 Replicated 되었을 때 호출되는 함수이다.)

AI 캐릭터의 경우

  • 그냥 BeginPlay에서 호출하면 된다.
//플레이어 캐릭터의 경우
void AAuraCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	//Init Ability Actor Info for the Server
	InitAbilityActorInfo();
}

void AAuraCharacter::OnRep_PlayerState()
{
	Super::OnRep_PlayerState();

	//Init Ability Actor Info for the Cilent
	InitAbilityActorInfo();
}

void AAuraCharacter::InitAbilityActorInfo()
{
	AAuraPlayerState* AuraPlayerState = GetPlayerState<AAuraPlayerState>();
	check(AuraPlayerState);
	AuraPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(AuraPlayerState, this);
	AbilitySystemComponent = AuraPlayerState->GetAbilitySystemComponent();
	AttributeSet = AuraPlayerState->GetAttributeSet();
}

//AI의 경우
void AAuraEnemy::BeginPlay()
{
	Super::BeginPlay();
	AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
profile
영차 영차

0개의 댓글