愛をもってゲームをつくるゴリラのブログ

UE4初心者のゴリラがいろいろ頑張ります。

GameplayAbility - GameplayAbility と コンポーネント の準備編

こんばんは、ごりです。
今日は、こちらの記事の続きからです。
goolee.hatenablog.com

今回は、実際に使う GameplayAbility と Component のクラスを作っていきます。

f:id:m-goolee-y:20181129224335p:plain

コンテンツブラウザの 新規C++クラスをクリック。
全てのクラスを表示にチェックし、 GameplayAbility と打ちます。

f:id:m-goolee-y:20181201182725p:plain

GameplayAbility を選択し、次へ。
ファイル名は 「GameplayAbilityBase」 とします。

続いて、新規C++クラスから 「AbilitySystemComponent」と打ちます。
ファイル名は 「AbilitySystemComponentBase 」とします。

f:id:m-goolee-y:20181201183413p:plain

作成が終わったら、
Component に処理を追加していきます。
今回もソースコードを記述します。

まず AbilitySystemComponentBase.h

/**
*@file	 AbilitySystemComponentBase.h
*@brief  GameplayAbility を用いるためのComponent
*@author goolee
*@date	 2018/12/01
*/
#pragma once

#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "GameplayTagContainer.h"
#include "AbilitySystemComponentBase.generated.h"

class UGameplayAbilityBase;

/**
 * GameplayAbility を扱う Component 
 * ゲーム中に指定したデータを扱うために、AbilitySystemComponent を拡張
 */
UCLASS()
class GPASTUDY_API UAbilitySystemComponentBase : public UAbilitySystemComponent
{
	GENERATED_BODY()
	
public:

	/**
	 *@fn
	 *コンストラクタ
	 */
	UAbilitySystemComponentBase();

	/**
         *@fn
         *現在実行中の Ability の中から指定した GameplayTag と一致するものすべて取得
         *@param  (GameplayTagContainer) 指定するGameplayTagの集まり
         *@return (ActiveAbilities) 指定したタグと一致したAbility
         */
	void GetActiveAbilitiesWithTags( const FGameplayTagContainer& GameplayTagContainer, TArray<UGameplayAbilityBase*>& ActiveAbilities );
	
	
};

つづいて AbilitySystemComponent.cpp

#include "AbilitySystemComponentBase.h"
#include "GameplayAbilityBase.h"

UAbilitySystemComponentBase::UAbilitySystemComponentBase() {}

void UAbilitySystemComponentBase::GetActiveAbilitiesWithTags(const FGameplayTagContainer& GameplayTagContainer, TArray<UGameplayAbilityBase*>& ActiveAbilities) {

	TArray<FGameplayAbilitySpec*> AbilitiesToActivate;
	GetActivatableGameplayAbilitySpecsByAllMatchingTags( GameplayTagContainer, AbilitiesToActivate, false );

	// Iterate the list of all ability specs
	for (FGameplayAbilitySpec* Spec : AbilitiesToActivate)
	{
		// Iterate all instances on this ability spec
		TArray<UGameplayAbility*> AbilityInstances = Spec->GetAbilityInstances();

		for (UGameplayAbility* ActiveAbility : AbilityInstances)
		{
			ActiveAbilities.Add(Cast<UGameplayAbilityBase>(ActiveAbility));
		}
	}
}

GameplayAbilityBase には今回は処理を追加しません。

ではこのComponentとAbility をキャラクターに持たせて、
GameplayAbilityを使えるようにしていきます。

CharacterBase.h と CharacterBase.cpp です。

/**
*@file	 CharacterBase.h
*@brief  GameplayAbility を用いる キャラクターの基底クラス
*@author goolee
*@date	 2018/12/01
*/
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AttributeSetBase.h"
#include "AbilitySystemInterface.h"
#include "AbilitySystemComponentBase.h"
#include "CharacterBase.generated.h"

UCLASS()
class GPASTUDY_API ACharacterBase : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	
	/**
	 * @fn
	 * コンストラクタ
	 */
	ACharacterBase();

  /**
	 *@fn
	 *コントローラ所有された際の処理
	 *@param このキャラクターを所有するコントローラ
	 *
	 *前回、この処理書いてなかったです、すみません。
	 */
	virtual void PossessedBy(AController* NewController) override;

protected:

	/**
	 * GameplayAbilityを扱うコンポーネント
	 */
	UPROPERTY()
	UAbilitySystemComponentBase* AbilitySystem;

	/**
	 * キャラクターのステータス 
	 * ブループリントから呼び出しはできないが、
	 * ガベージコレクションに追加するため UPROPERTY() を記述
	 */
	UPROPERTY()
	UAttributeSetBase* AttributeSet;

	/**
	 *キャラクター生成時から実行可能なAbility
	 */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Abilities")
	TArray<TSubclassOf<UGameplayAbilityBase>> Abilities;

	/**
	 * @fn
	 * ゲーム開始時や、生成時に呼ばれる処理
	 */
	virtual void BeginPlay() override;

	/**
	 * @fn
	 * キャラクターの体力を取得
	 * @return キャラクターの体力
	 */
	UFUNCTION(BlueprintCallable)
	virtual float GetHealth() const;

public:	

	/**
	 * @fn
	 * 毎フレーム呼ばれる処理
	 */
	virtual void Tick(float DeltaTime) override;

	/**
	 *@fn
	 *AbilitySystemComponentを取得
	 *@return AbilitySystemComponent
	 */
	UAbilitySystemComponent* GetAbilitySystemComponent() const override;

	/**
	 *@fn
	 *指定したタグと一致するAbilityを実行
	 *@param  (AbilityTags)				実行するAilityがもつGameplayTag
	 *@param  (bAllowRemoteActivation)	true...ローカル/サーバーで実行 false...ローカルでのみ実行
	 *@return true...実行に成功 false...失敗
	 */
	UFUNCTION(BlueprintCallable, Category = "Abilities")
	bool ActivateAbilitiesWithTags(FGameplayTagContainer AbilityTags, bool bAllowRemoteActivation = true);

	/**
	*@fn
	*キャラクターが現在実行中の Ability の中から指定した GameplayTag と一致するものすべて取得
	*@param  (AbilityTags)     指定するGameplayTagの集まり
	*@return (ActiveAbilities) 指定したタグと一致したAbility
	*/
	UFUNCTION(BlueprintCallable, Category = "Abilities")
	void GetActivateAbilitiesWithTags( FGameplayTagContainer AbilityTags, TArray<UGameplayAbilityBase*>& ActiveAbilities);

};
#include "CharacterBase.h"
#include "GameplayAbilityBase.h"


ACharacterBase::ACharacterBase(){
    //trueにすると毎フレームTick関数を呼び出す設定
	PrimaryActorTick.bCanEverTick = true;
	
	//AbilitySystemConponentの生成
	AbilitySystem = CreateDefaultSubobject<UAbilitySystemComponentBase>(TEXT("AbilitySystem"));
	//マルチプレイヤー用の設定
	AbilitySystem->SetIsReplicated(true);

	//AttributeSet の生成
	AttributeSet = CreateDefaultSubobject<UAttributeSetBase>(TEXT("AttributeSet"));
}

void ACharacterBase::PossessedBy(AController* NewController) {
	Super::PossessedBy( NewController );

	if (AbilitySystem) {
		//AbilitySytemを持つ Actor情報と このAbilitySystemで動く Actor情報の初期化 
		AbilitySystem->InitAbilityActorInfo(this, this);
	}
}

void ACharacterBase::BeginPlay() {

	Super::BeginPlay();
	
	/**
	 * AbilitySytemに使えるAbilityを登録
	 * これをしないとTagでAbilityを指定しても実行されない。
	 */
	if (AbilitySystem) {
		for (auto Ability : Abilities) {
			AbilitySystem->GiveAbility(FGameplayAbilitySpec(Ability, 1, INDEX_NONE, this));
		}
	}

}

void ACharacterBase::Tick(float DeltaTime){

	Super::Tick(DeltaTime);

}

float ACharacterBase::GetHealth() const {
	return AttributeSet->GetHealth();
}

UAbilitySystemComponent* ACharacterBase::GetAbilitySystemComponent() const {
	return AbilitySystem;
}

bool ACharacterBase::ActivateAbilitiesWithTags(FGameplayTagContainer AbilityTags, bool bAllowRemoteActivation) {

	if (AbilitySystem) {
		return AbilitySystem->TryActivateAbilitiesByTag( AbilityTags, bAllowRemoteActivation );
	}
	return false;

}

void ACharacterBase::GetActivateAbilitiesWithTags(FGameplayTagContainer AbilityTags, TArray<UGameplayAbilityBase*>& ActiveAbilities) {
	
	if (AbilitySystem) {
		AbilitySystem->GetActiveAbilitiesWithTags( AbilityTags, ActiveAbilities );
	}

}

ここまで出来たら、ビルドして BP_CharacterBase を見てみましょう。
コンポーネントに AbilitySystemが追加され、
f:id:m-goolee-y:20181201195815p:plain

デフォルトの詳細に、Abilitiesが増えているのがわかりますね。
f:id:m-goolee-y:20181201200113p:plain

これで GameplayAbilityを使う準備は整いました。

次回から使い方を書いていきたいと思います。
その都度、機能拡張をしていきます。

ソースコードのコメントに、説明書きましたが、
不明な点があれば、ご連絡ください。

ではでは。