アクタにコンポーネントを追加する

アクタにコンポーネントを追加するためのチュートリアルです。

コンテンツ

コンポーネントアクタ 内でサブオブジェクトとして使用されるように作られた オブジェクト のタイプです。

コンポーネントは、視覚効果の表示、サウンドの再生、動作ロジックの処理など、さまざまなクラス間において共通の動作を共有する上で役立ちます。

独自のコンポーネントの作成する場合に、Actor コンポーネントScene コンポーネント、および Primitive コンポーネント の 3 つのコンポーネントを使用することができます。

  • Actor コンポーネント (クラス UActorComponent) は、移動、インベントリ、または属性管理、およびその他の非物理的概念などの抽象的な動作に役立ちます。Actor コンポーネントにはトランスフォーム プロパティ (ワールドでの物理的な位置や回転) は含まれません。

  • Scene コンポーネント (クラス USceneComponent、UActorComponent の子) はジオメトリ表現を必要としない場所ベースのビヘイビアをサポートします。これには、スプリング アーム、カメラ、物理的な力、およびコンストレイント (物理オブジェクトは除く)、音声が含まれます。

  • Primitive コンポーネント (クラス UPrimitiveComponent、USceneComponent の子) は、ジオメトリ表現を備えた Scene コンポーネントです。これは、通常、ビジュアル要素のレンダリング、または物理オブジェクトとのコリジョンまたはオーバーラップに使用されます。これには、スタティック メッシュまたはスケルタル メッシュ、スプライトまたはビルボード、パーティクル システム、ボックス、カプセル、球体のコリジョン ボリュームが含まれます。

実装方法を選んでください。

Blueprints

C++

プロジェクトの設定

このチュートリアルでは、「HealthComponent」という名前のアクタ コンポーネントのゲームプレイ ロジックを作成するタスクに取り組みます。アクタにこのコンポーネントを接続すると、ダメージによってヘルスを減らす機能がアクタに搭載されます。

今回の例では、サードパーソン テンプレート プロジェクトに含まれているサードパーソン キャラクターを使用します。

  1. まず [New (新規)] > [Games (ゲーム)] > [Third Person (サードパーソン)] > [Blueprint (ブループリント)] プロジェクトの順に選択して、「Health Component」という名前のプロジェクトを作成します。

    クリックしてフルサイズで表示

  2. [Edit (編集)] > [Project Settings (プロジェクト設定)] > [Engine (エンジン)] > [Input (入力)] >[Bindings (バインディング)] > [Action Mappings (アクション マッピング)] の順に移動し、 [Add (追加) (+)] をクリックして「OnDamagePressed」という名前の新しいアクション マッピングを作成し、その値を 1 に設定します。

    クリックしてフルサイズで表示

入力値 には、アクション マッピングが含まれており、プレイヤーのキャラクターに対するダメージの発生など、イベント駆動の動作にボタンまたはキーの押下をマッピングすることができます。

アクタ コンポーネントを作成する:Health Component

このセクションでは、任意のアクタに接続できるアクタ コンポーネントである Health Component を作成します。

以下の手順に従って、プレイヤーのヘルスの値を維持および減少させるロジックの作成を開始します。

  1. コンテンツ ブラウザ[Add/New (新規/追加)] > [Blueprint Class (ブループリント クラス)] の順にクリックします。次に、 [Pick Parent Class (親クラスを選択)] メニューから、 [Actor Component (アクタ コンポーネント)] を選択し、「Bp_HealthComponent」という名前の新しいアクタ コンポーネントを作成します。

    03_BP_CreateBPActorComponentClass.png

  2. [Class Defaults (クラスのデフォルト)] で [My Blueprint (マイ ブループリント)] パネルに移動します。[Variables (変数)] カテゴリの [Add (+) (追加)] ボタンをクリックして、「Health」および「MaxHealth」という名前の 2 つの float 変数を作成します。

    04_BP_AddVariables.png

  3. Max Health 変数を選択し、[Details (詳細)] パネルに移動してデフォルトの Max Health の値を 100.0 に設定します。

    05_BP_MaxHealthDetails.png

イベント ディスパッチャーを作成する:Handle Damage

イベント ディスパッチャー を使用すると、アクタでイベント ディスパッチャーにバインドする (イベント ディスパッチャーをリッスンする) メソッドを呼び出すことができます。続いて、イベント ディスパッチャーがイベントを呼び出すと、イベント ディスパッチャーをリッスンしているアクタがそのイベントに応答します。

以下の手順に従って、Handle Take Damage イベント ディスパッチャーの作成を開始します。

  1. [My Blueprint] パネルから Event Dispatchers カテゴリへ移動し [Add (+)] ボタンをクリックして「HandleTakeDamage」という名前の イベント ディスパッチャー を作成します。

    06_BP_AddEventDispatcher.png

  2. [Details] パネルの Inputs カテゴリに移動して [Add (+)] ボタンをクリックし、次の変数を作成します。

    変数名

    説明

    DamageActor

    Bp_HealthComponent

    ダメージを受けるアクタ。

    Health

    Float

    アクタのベース ヘルス。

    Damage

    Float

    適用するベース ダメージ。

    DamageType

    Damage Type

    処理するダメージを説明するクラス。

    InstigatedBy

    Controller

    ダメージの原因となったコントローラー。手りゅう弾を投げたプレイヤーなどがその例です。

    DamageCauser

    Actor

    ダメージの原因を表すアクタ。爆発した手りゅう弾などがその例です。

    07_BP_AddDispatcherInputs.png

  3. [Compile (コンパイル)][Save (保存)] を順にクリックします。

    08_BP_CompileSaveButtons.png

Health コンポーネントのイベント開始スクリプトを作成する

  1. Max Health float のコピーを イベント グラフ にドラッグします。

    Copy Node Graph

    09_BPScript_01_01.png

  2. Health float を イベント グラフ にドラッグし、 [Set Health (Health を設定)] を選択して Set Health ノードを作成します。

    Copy Node Graph

    10_BPScript_01_02.png

  3. Max Health float の 出力 ピンを、 Set Health ノードの Health入力 ピンに接続します。次に、 Event Begin Play ノードの出力実行ピンを Set Health ノードの入力実行ピンに接続します。

    Copy Node Graph

    11_BPScript_01_03.png

  4. Set Health ノードから出力実行ピンを引き出します。[Actions] メニューから [Context Sensitive (状況依存)] ボックスをオフにし、 Bind Event to On Take Any Damage を検索して選択します。

    Copy Node Graph

    12_BPScript_01_04.png

  5. [Bind Event to On Take Any Damage] ノードから Target ピンを引き出し、 [Actions] メニューから Components カテゴリの Get Owner を検索して選択します。

    Copy Node Graph

    13_BPScript_01_05.png

  6. [Bind Event to On Take Any Damage] ノードから Target ピンを引き出し、 [Actions] メニューから Components カテゴリの Get Owner を検索して選択します。

    Copy Node Graph

    14_BPScript_01_06.png

  7. Create Event ノードで、 [Select Function (関数を選択)] ドロップダウン メニューをクリックし、関数 Create matching function を選択します。

    15_BPScript_01_07.png

関数を作成する:ダメージを受ける

Health コンポーネントのイベント開始スクリプトの作成が完了すると、最後に作成した関数が自動的に開かれます。

Player Character がダメージを受けたときにヘルスを減らすロジックを処理するための関数スクリプトを作成する必要があります。

これを行うには、以下の手順に従います。

  1. 作成した関数の名前を「Take Damage」に変更します。

    16_RenameFunction.png

  2. [My Blueprint] パネルで Variables カテゴリに移動し、 Health 変数を イベント グラフ にドラッグします。

    Copy Node Graph

    17_BPScript_02_01.png

  3. Take Damage ノードから Damage 変数を引き出します。次に、 [Actions] メニューで Subtract を検索して選択します。

    Copy Node Graph

    18_BPScript_02_02.png

  4. Health ピンからドラッグし、Subtract ノードの 減算浮動小数 に接続します。

    Copy Node Graph

    19_BPScript_02_03.png

  5. Subtract ノードから結果を引き出し、 [Actions] メニューで Clamp (float) を検索して選択します。

    Copy Node Graph

    20_BPScript_02_04.png

  6. [My Blueprint] パネルで Variables カテゴリに移動し、 Max Health 変数を Clamp (float) ノードの Max float 変数にドラッグします。

    Copy Node Graph

    21_BPScript_02_05.png

  7. Take Damage ノードから実行ピンを引き出し、 Actions メニューから Branch を検索して選択します。

    Copy Node Graph

    22_BPScript_02_06.png

  8. Take Damage ノードから Damage 変数を引き出します。次に、 [Actions] メニューで <= (Less Equal) を検索して選択します。

    Copy Node Graph

    23_BPScript_02_07.png

  9. Less Equal 演算子ノードから boolean リターン ピンを引き出し、 Branch ノードの Condition ピンに接続します。

    Copy Node Graph

    24_BPScript_02_08.png

  10. Branch ノードから False 実行ピンを引き出します。次に、 [Actions] メニューで Set Health を検索して選択します。

    Copy Node Graph

    25_BPScript_02_09.png

  11. Clamp (float) ノードに移動し、 Return Value からドラッグします。それを Set Health ノードの Health ピンに接続します。

    Copy Node Graph

    26_BPScript_02_10.png

  12. Set Health ノードから出力実行ピンを引き出し、 [Actions] メニューで Call Handle Take Damage を検索して選択します。

    Copy Node Graph

    27_BPScript_02_11.png

  13. Set Health ノードで、 Health 出力ピンを Call Handle Take Damage ノードの Health 入力ピンに接続します。

    Copy Node Graph

    28_BPScript_02_12.png

  14. Call Handle Take Damage ノードから Damaged Actor ピンを引き出し、 [Actions] メニューから Get a reference to self を検索して選択します。

    Copy Node Graph

    29_BPScript_02_13.png

  15. Take Damage ノードに移動し、 Damage ピン、 Damage Type ピン、 Instigated By ピン、および Damage Causer ピンを、Call Handle Take Damage ノードのそれぞれのピンに接続します。

    Copy Node Graph

    30_BPScript_02_14.png

  16. [Compile (コンパイル)][Save (保存)] を順にクリックします。

    31_CompileSaveButton.png

完成したブループリント

Take Damage 関数

Copy Node Graph

32_BPFinalScript1.png

Begin Play

Copy Node Graph

33_BPFinalScript2.png

Third Person Character に Health Component を追加する

Health Component クラスの作成が完了したら、そのアクタ コンポーネントを Third Person Character クラスに追加し、OnDamagePressed アクション マッピングをバインドしてプレイヤーがダメージを受けるようにする必要があります。

  1. Content」 > 「ThirdPersonBp」 > 「Blueprints」フォルダの順に移動し、 ThirdPersonCharacter をダブルクリックしてその [Class Defaults (クラスのデフォルト)] を開きます。

    34_OpenThirdPerCharacter.png

  2. [Components (コンポーネント)] パネルで [Add Component (コンポーネントを追加)] ボタンをクリックし、 Bp Health Component を検索して選択します。

    35_AddBPHealthComponent.png

  3. イベント グラフ を右クリックし、 [Actions] メニューから OnDamagePressed を検索して選択します。

    Copy Node Graph

    36_BPScript_03_01.png

  4. InputAction OnDamagePressed ノードから Pressed 実行ピンを引き出し、 [Actions] メニューから Apply Damage を検索して選択します。

    Copy Node Graph

    37_BPScript_03_02.png

  5. Apply Damage ノードから Damaged Actor ピンを引き出し、 [Actions] メニューから Get a reference to self を検索して選択します。Base Damage 浮動小数値を「20.0」に設定します。

    Copy Node Graph

    38_BPScript_03_03.png

    Apply Damage 関数は、ゲームプレイを目的とする便利な汎用関数を含む Gameplay Statics Library の一部です。

  6. イベント グラフ を右クリックし、 [Actions] メニューから Event Begin Play を検索して選択します。

    Copy Node Graph

    39_BPScript_03_04.png

  7. [Components (コンポーネント)] パネルから、 BP_HealthComponent のコピーを イベント グラフ にドラッグします。

    Copy Node Graph

    40_BPScript_03_05.png

  8. .Bp Health Component ピンを引き出し、 [Actions] メニューで Bind Event to Handle Take Damage を検索して選択します。

    Copy Node Graph

    41_BPScript_03_06.png

  9. Event BeginPlay ノードの出力実行ピンを、Bind Event to Handle Take Damage の入力実行ピンに接続します。

    Copy Node Graph

    42_BPScript_03_07.png

  10. Bind Event to Handle Take Damage から Event ピンを引き出し、 [Actions] メニューから Add Custom Event を検索して選択し、 OnHealthChanged という名前のカスタム イベントを作成します。

    Copy Node Graph

    43_BPScript_03_08.png

  11. OnHealthChanged ノードから Health ピンを引き出し、[Actions] メニューで <= (Less Equal) 演算子を検索して選択します。

    Copy Node Graph

    44_BPScript_03_09.png

  12. OnHealthChanged ノードから Execution ピンを引き出し、[Actions] メニューで Branch** を検索して選択します。

    Copy Node Graph

    45_BPScript_03_10.png

  13. <= (*Less Equal)** 演算子ノードから **boolean** リターン ピンを引き出し、 **Branch** ノードの **Condition** ピンに接続します。

    Copy Node Graph

    46_BPScript_03_11.png

  14. Branch ノードの True 実行ピンを引き出して、 [Actions] メニューで DestroyActor を検索して選択します。

    Copy Node Graph

    47_BPScript_03_12.png

    プレイヤーのヘルス値がゼロに達すると、プレイヤーはワールドから除去されます。

  15. OnHealthChanged ノードから Execution ピンを引き出し、 [Actions] メニューで Print String を検索して選択します。

    Copy Node Graph

    48_BPScript_03_13.png

    Print String は、プレイヤーのキャラクターがダメージを受けるたびに、ヘルスの現在値を画面に表示するために使用します。

  16. OnHealthChanged ノードの Health ピンを Print StringIn String ピンに接続します。

    49_BPScript_03_14.png

  17. [Compile (コンパイル)][Save (保存)] を順にクリックします。

    50_CompileSaveButton.png

完成したブループリント

Copy Node Graph

51_BPFinalScript3.png

最終結果

Health Component の機能をテストする準備が整いました。

WASD のキーを使用してキャラクターを動かすこともできます。数字キーの 1 を押すと、キャラクターはヘルスが 0 に達するまでダメージを受け、ヘルスが 0 に達するとワールドから消去されます。

ツールバー に移動し、 [Play (プレイ)] をクリックします。

52_PlayButton.png

プロジェクトの設定

このチュートリアルでは、「HealthComponent」という名前のアクタ コンポーネントのゲームプレイ ロジックを作成するタスクに取り組みます。アクタにこのコンポーネントを接続すると、ダメージによってヘルスを減らす機能がアクタに搭載されます。

今回の例では、Third Person Template プロジェクトに含まれている Third Person Character を使用します。

  1. まず [New (新規)] > [Games (ゲーム)] > [Third Person (サードパーソン)] > [CPP] プロジェクトの順に選択して、「Health Comp」という名前のプロジェクトを作成します。

    クリックしてフルサイズで表示

  2. [Edit (編集)] > [Project Settings (プロジェクト設定)] > [Engine (エンジン)] > [Input (入力)] >[Bindings (バインディング)] > [Action Mappings (アクション マッピング)] の順に移動し、[+Add (+追加)] をクリックして「OnDamagePressed」という名前の新しいアクション マッピングを作成し、その値を 1 に設定します。

    クリックしてフルサイズで表示

    [Input] には、アクション マッピングが含まれており、プレイヤーのキャラクターに対するダメージの発生など、イベント駆動の動作にボタンまたはキーの押下をマッピングすることができます。

アクタ コンポーネントを作成する:Health コンポーネント

デリゲート は、汎用的かつ型安全な方法で C++ オブジェクト上でメンバ関数の呼び出しを可能にします。アクタはデリゲートにバインドされると、デリゲートのメンバー関数イベントに応答するようになります。

以下の手順に従って、On Health Changed デリゲートの作成を開始します。

  1. [Tools (ツール)] > [New C++ Class (新規 C++ クラス)] をクリックして C++ クラス を作成し、[Choose a Parent Class (親クラスを選択)] メニューから [Actor Component (アクタ コンポーネント)] を選択して [Next (次へ)] をクリックします。

    クリックしてフルサイズで表示

  2. Actor Component クラスに「HealthComponent」という名前を付けて、[Create (作成)] をクリックします。

    クリックしてフルサイズで表示

  3. HealthComponent.h」ファイルで、次のデリゲートを宣言します。

        DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComponent, float, Health, float, DamageAmount, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
  4. [Class Defaults (クラスのデフォルト)] へ移動して以下のメソッドと変数を宣言します。

        public:
    
            UPROPERTY(BlueprintAssignable, Category = "Events")
            FOnHealthChangedSignature OnHealthChanged;
    
        protected:
    
            UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
            float Health;
    
            UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
            float MaxHealth;
    
            UFUNCTION(BlueprintCallable)
            void HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
  5. HealthComponent.cpp ファイルに移動し、HealthComponent コンストラクタ 内で次のクラスの変数を初期化します。

        UHealthComponent::UHealthComponent()
        {
            MaxHealth = 100.0f;
        }
  6. BeginPlay クラス メソッドの次の定義を実装します。

        void UHealthComponent::BeginPlay()
        {
            Super::BeginPlay();
            //このアクタ コンポーネントのオーナーを取得します。
            AActor* MyOwner = GetOwner();
    
            if (MyOwner)
            {
                //OnTakeAnyDamage Function に応答するように Owner Object がバインドされるようになりました。
                MyOwner->OnTakeAnyDamage.AddDynamic(this,&UHealthComponent::HandleTakeDamage);
            }
            //ヘルスを最大ヘルスと同等に設定します。
            Health = MaxHealth;
        }
  7. 次の HandleTakeDamage メソッドのコードを宣言します。

        void UHealthComponent::HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
        {
            if (Damage <= 0.0f)
            {
                return;
            }
            Health = FMath::Clamp(Health - Damage, 0.0f, MaxHealth); OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
        }
  8. このコードを コンパイル します。

完成コード

Health Component.h

    #pragma once

    #include "CoreMinimal.h"
    #include "Components/ActorComponent.h"
    #include "HealthComponent.generated.h"

    DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComponent, float, Health, float, DamageAmount, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);

    UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
    class HEALTHCOMP_API UHealthComponent : public UActorComponent
    {
    GENERATED_BODY()

    public:

        // このコンポーネントのプロパティにデフォルト値を設定します
        UHealthComponent();

    protected:

        // ゲーム開始時に呼び出されます
        virtual void BeginPlay() override;

    public:

        // フレームごとに呼び出されます
        virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

    public:

        UPROPERTY(BlueprintAssignable, Category = "Events")
        FOnHealthChangedSignature OnHealthChanged;

    protected:

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
        float Health;

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
        float MaxHealth;

        UFUNCTION(BlueprintCallable)
        void HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
    };

Health Component.cpp

    #include "HealthComponent.h"

    // このコンポーネントのプロパティにデフォルト値を設定します
    UHealthComponent::UHealthComponent()
    {
        // ゲーム開始時にこのコンポーネントが初期化され、フレームごとにティックされるように初期化します。これらの機能が必要ない場合は、
        // パフォーマンス向上のためにオフにすることができます。
        PrimaryComponentTick.bCanEverTick = true;

        MaxHealth = 100.0f;
    }

    // ゲーム開始時に呼び出されます
    void UHealthComponent::BeginPlay()
    {
        Super::BeginPlay();

        //このアクタ コンポーネントのオーナーを取得します。
        AActor* MyOwner = GetOwner();

        if(MyOwner)
        {
            //OnTakeAnyDamage Function に応答するように Owner Object がバインドされるようになりました。
            MyOwner->OnTakeAnyDamage.AddDynamic(this,&UHealthComponent::HandleTakeDamage);
        }
        //ヘルスを最大ヘルスと同等に設定します。
        Health = MaxHealth;
    }

    // フレームごとに呼び出されます
    void UHealthComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
    {
        Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    }

    void UHealthComponent::HandleTakeDamage(AActor* DamageActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
    {
        if (Damage <= 0.0f)
        {
            //ダメージ量が 0 以下でした。
            return;
        }
        Health = FMath::Clamp(Health - Damage, 0.0f, MaxHealth); OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
    }

HealthComp Character に Health Component を追加する

Health Component クラスの作成が完了したら、そのアクタ コンポーネントを Health Comp Character クラスに追加し、OnDamagePressed アクション マッピングをバインドしてプレイヤーがダメージを受けるようにする必要があります。

  1. コンテンツ ブラウザ から、「C++ Classes」 > 「HealthComp」に移動し、HealthComp Character をダブルクリックして「HealthCompCharacte`HealthCompCharacter.h`」ファイルを開きます。

  2. [Class Defaults] で、次のコードを宣言します。

        protected:
    
            virtual void BeginPlay() override;
    
            UPROPERTY(EditDefaultsOnly,BlueprintReadWrite)
            class UHealthComponent* HealthComponent;
    
            UFUNCTION()
            void OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
    
            //プレイヤーへのダメージを呼び出す関数
            UFUNCTION()
            void DamagePlayerCharacter();
    
            //プレイヤーに与えるダメージタイプのコンテナ
            UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
            TSubclassOf<UDamageType> GenericDamageType;
  3. HealthCompCharacter.cpp ファイルへ移動し、以下のクラス ライブラリをインクルードします。

        #include "HealthComponent.h"
        #include "Kismet/GameplayStatics.h"

    Gameplay 統計ライブラリには、多数のユーティリティ ヘルパー関数が用意されており、ゲームプレイを目的とするニーズに対応できます。この例では、ApplyDamage メソッドを利用します。

  4. AHealthCompCharacter コンストラクタ で、次のようにして Health Component クラスを初期化します。

        AHealthCompCharacter::AHealthCompCharacter()
        {
            HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent"));
        }
  5. AHealthCompChatacter::BeginPlay メソッドに移動し、次のコードを追加します。

        void AHealthCompCharacter::BeginPlay()
        {
            Super::BeginPlay();
            HealthComponent->OnHealthChanged.AddDynamic(this, &AHealthCompCharacter::OnHealthChanged);
        }
  6. AHealthCompCharacter::OnHealthChanged メソッドで次のロジックを実装し、ヘルスが 0 になった場合に Player Character を消去します。

        void AHealthCompCharacter::OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
        {
            if (Health <= 0.0f)
            {
                Destroy();
            }
            UE_LOG(LogTemp, Warning, TEXT("The Player's Current Health is: %f"), Health);
        }

    UE_LOG は、さまざまな 詳細タイプ を含むマクロで、出力ログでデータを視覚化するコマンドとともに使用します。

  7. 次のコードを追加し、AHealthCompCharacter::DamagePlayerCharacter メソッドを実装します。

        void AHealthCompCharacter::DamagePlayerCharacter()
        {
            UGameplayStatics::ApplyDamage(this, 20.0f, GetInstigatorController(),this,GenericDamageType);
        }
  8. AHealthCompCharacter::SetupPlayerInputComponent メソッドに移動し、OnDamagePressed バインディングを DamagePlayerCharacter 関数に割り当てます。

        void AHealthCompCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
        {
            //OnDamagePressed アクション イベントをバインドします
            PlayerInputComponent->BindAction("OnDamagePressed", IE_Pressed, this, &AHealthCompCharacter::DamagePlayerCharacter);
        }
  9. このコードを コンパイル します。

完成コード

HealthCompCharacter.h

    #pragma once

    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "HealthCompCharacter.generated.h"

    UCLASS(config=Game)
    class AHealthCompCharacter : public ACharacter
    {
        GENERATED_BODY()

        /** キャラクターの後ろにカメラを配置するカメラ ブーム*/
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
        class USpringArmComponent* CameraBoom;

        /** カメラをフォローします。*/
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
        class UCameraComponent* FollowCamera;

    public:

        AHealthCompCharacter();

        /** 基本回転速度 (度/秒)。最終的なターン率が他のスケーリングの影響を受ける場合があります。*/
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Input)
        float TurnRateGamepad;

    protected:

        /** 前方/後方入力のために呼び出されます。*/
        void MoveForward(float Value);

        /** 左右の入力のために呼び出されます。*/
        void MoveRight(float Value);

        /**
        * 任意の率でターンするよう、入力を介して呼び出されます。
        * @param Rate   これは正規化された率で、「1.0」は希望のターン率を 100% 実現していることを意味します。
        */
        void TurnAtRate(float Rate);

        /**
        * 任意の率でルックアップ/ルックダウンをターンするよう、入力を介して呼び出されます。
        * @param Rate   これは正規化された率で、「1.0」は希望のターン率を 100% 実現していることを意味します。
        */
        void LookUpAtRate(float Rate);

        /** タッチ入力が開始されたときのハンドラ。*/
        void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

        /** タッチ入力が停止したときのハンドラ。*/
        void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

    protected:

        // APawn インターフェース
        virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
        // APawn インターフェースの終了

    public:

        /** CameraBoom サブオブジェクトを返します。**/
        FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
        /** FollowCamera サブオブジェクトを返します。**/
        FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }

    protected:

        virtual void BeginPlay() override;

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
        class UHealthComponent* HealthComponent;

        UFUNCTION()
        void OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);

        //プレイヤーへのダメージを呼び出す関数
        UFUNCTION()
        void DamagePlayerCharacter();

        //プレイヤーに与えるダメージタイプのコンテナ
        UPROPERTY(EditDefaultsOnly,BlueprintReadOnly, Category = "Weapon")
        TSubclassOf<UDamageType> GenericDamageType;
    };

HealthCompCharacter.cpp

    #include "HealthCompCharacter.h"
    #include "HeadMountedDisplayFunctionLibrary.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CapsuleComponent.h"
    #include "Components/InputComponent.h"
    #include "GameFramework/CharacterMovementComponent.h"
    #include "GameFramework/Controller.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "HealthComponent.h"
    #include "Kismet/GameplayStatics.h"

    //////////////////////////////////////////////////////////////////////////
    // AHealthCompCharacter

    AHealthCompCharacter::AHealthCompCharacter()
    {
        // コリジョン カプセルのサイズを設定します。
        GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

        // 入力のターン率を設定します。
        TurnRateGamepad = 50.f;

        // コントローラーが回転するときは回転させないでください。影響を受けるのはカメラのみにします。
        bUseControllerRotationPitch = false;
        bUseControllerRotationYaw = false;
        bUseControllerRotationRoll = false;

        // キャラクターの動きを設定します。
        GetCharacterMovement()->bOrientRotationToMovement = true; // 入力した方向にキャラクターが移動します...
        GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f); // ...この回転速度で実行します。

        // 注:これらの変数のイテレーションをさらに高速化する場合などは、再コンパイルして調整するのではなく、キャラクターの
        // ブループリントで微調整できます
        GetCharacterMovement()->JumpZVelocity = 700.f;
        GetCharacterMovement()->AirControl = 0.35f;
        GetCharacterMovement()->MaxWalkSpeed = 500.f;
        GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
        GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;

        // カメラ ブームを作成します (コリジョンがある場合はプレイヤーに向かって引きます)。
        CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
        CameraBoom->SetupAttachment(RootComponent);
        CameraBoom->TargetArmLength = 400.0f; // カメラがキャラクターの後ろをこの距離で追跡します。
        CameraBoom->bUsePawnControlRotation = true; // コントローラーを基準にアームを回転させます。

        // 追跡するカメラを作成します。
        FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
        FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // ブームの最後にカメラをアタッチして、コントローラーの方向と一致するようブーム自身に調整させます。
        FollowCamera->bUsePawnControlRotation = false; // カメラは腕の動きに合わせて回転しません。

        // 注:メッシュ コンポーネント上のスケルタルメッシュと Anim ブループリントの参照 (キャラクターから継承) は、
        // MyCharacter という名前の、派生したブループリント アセットで設定されます (C++ での直接のコンテンツ参照を回避するため)。

        HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent"));
    }

    //////////////////////////////////////////////////////////////////////////
    // 入力

    void AHealthCompCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
    {
        // ゲームプレイ キー バインディングを設定します。
        check(PlayerInputComponent);
        PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
        PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
        PlayerInputComponent->BindAxis("Move Forward / Backward", this, &AHealthCompCharacter::MoveForward);
        PlayerInputComponent->BindAxis("Move Right / Left", this, &AHealthCompCharacter::MoveRight);

        // さまざまなデバイスをそれぞれ処理するための回転バインディングには 2 つのバージョンがあります。
        // 「turn」では、マウスなどの絶対デルタを提供するデバイスを処理します。
        // 「turnrate」は、アナログのジョイスティックなど、ユーザーが「変更率」として処理することに決めたデバイス向けです。
        PlayerInputComponent->BindAxis("Turn Right / Left Mouse", this, &APawn::AddControllerYawInput);
        PlayerInputComponent->BindAxis("Turn Right / Left Gamepad", this, &AHealthCompCharacter::TurnAtRate);
        PlayerInputComponent->BindAxis("Look Up / Down Mouse", this, &APawn::AddControllerPitchInput);
        PlayerInputComponent->BindAxis("Look Up / Down Gamepad", this, &AHealthCompCharacter::LookUpAtRate);

        // タッチ デバイスを処理します。
        PlayerInputComponent->BindTouch(IE_Pressed, this, &AHealthCompCharacter::TouchStarted);
        PlayerInputComponent->BindTouch(IE_Released, this, &AHealthCompCharacter::TouchStopped);

        //OnDamagePressed アクション イベントをバインドします
        PlayerInputComponent->BindAction("OnDamagePressed", IE_Pressed, this, &AHealthCompCharacter::DamagePlayerCharacter);
    }

    void AHealthCompCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
    {
        Jump();
    }

    void AHealthCompCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
    {
        StopJumping();
    }

    void AHealthCompCharacter::TurnAtRate(float Rate)
    {
        // 率に関する情報からこのフレームのデルタを計算します。
        AddControllerYawInput(Rate * TurnRateGamepad * GetWorld()->GetDeltaSeconds());
    }

    void AHealthCompCharacter::LookUpAtRate(float Rate)
    {
        // 率に関する情報からこのフレームのデルタを計算します。
        AddControllerPitchInput(Rate * TurnRateGamepad * GetWorld()->GetDeltaSeconds());
    }

    void AHealthCompCharacter::MoveForward(float Value)
    {
        if ((Controller != nullptr) && (Value != 0.0f))
        {
            // どちらが前方かを調べます。
            const FRotator Rotation = Controller->GetControlRotation();
            const FRotator YawRotation(0, Rotation.Yaw, 0);

            // get forward ベクター
            const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
            AddMovementInput(Direction, Value);
        }
    }

    void AHealthCompCharacter::MoveRight(float Value)
    {
        if ( (Controller != nullptr) && (Value != 0.0f) )
        {
            // どちらが右かを調べます。
            const FRotator Rotation = Controller->GetControlRotation();
            const FRotator YawRotation(0, Rotation.Yaw, 0);

            // get right ベクター
            const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
            // その方向に動きを追加します。
            AddMovementInput(Direction, Value);
        }
    }

    void AHealthCompCharacter::BeginPlay()
    {
        Super::BeginPlay();
        HealthComponent->OnHealthChanged.AddDynamic(this, &AHealthCompCharacter::OnHealthChanged);
    }

    void AHealthCompCharacter::OnHealthChanged(UHealthComponent* HealthComp, float Health, float DamageAmount, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
    {
        if (Health <= 0.0f)
        {
            Destroy();
        }
        UE_LOG(LogTemp, Warning, TEXT("The Player's Current Health is: %f"), Health);
    }

    void AHealthCompCharacter::DamagePlayerCharacter()
    {
        UGameplayStatics::ApplyDamage(this, 20.0f, GetInstigatorController(), this, GenericDamageType);
    }

最終結果

Health Component の機能をテストする準備が整いました。

WASD のキーを使用してキャラクターを動かすことができます。数字キーの 1 を押すと、キャラクターはヘルスが 0 に達するまでダメージを受け、ヘルスが 0 に達するとワールドから消去されます。

ツールバー に移動し、[Play (プレイ)] を押します。

05_PlayButton.png

追加リソース

ブループリントにコンポーネントを追加することに関する考え方を、以下のリンクで参照することができます。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
キャンセル