C++で作成するPlayer 

## 概要
UEにおけるC++の学習として、PlayerをC++で作成し、内容を簡単に纏めました。

#### 開発環境
Windows 11
Unreal Engine 5.3
言語 日本語

## ステップ１：PlayerのCharacterクラス作成
CharacterクラスをベースにPlayerを作成します。
ツールメニュー＞ [新規 C++ クラス] をクリックして、新しい親クラスを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/85d54b3f-4b91-bf4b-ddde-5cc7af3f11d2.png)
[親クラスを選択] メニューが開いたら、[ Character ] を選択し、[次へ] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/a6cf234f-fc29-6796-816b-8f673497bf12.png)
適当に名前を付けたら、[クラスを作成] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/87089eda-379b-5c1f-a3c6-84ab01cf8dd4.png)
Visual Studio を起動すると、Projectに今作成した.cppと.hがあることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/56d452b7-f09d-6665-962a-75210ae0bad9.png)
コンパイルし、コンテンツブラウザにも表示されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/13bd0f8e-3a51-14a6-0707-ffc146e289d3.png)

## ステップ２：移動の実装
#### 軸マッピング設定
１．[編集] ＞ [プロジェクト設定] を選択します。
２．タブの左側にある [エンジン] から [インプット] をクリックします。
３．[バインディング] の [軸マッピング] の隣にあるプラス記号をクリックします。
４．[軸マッピング] の左側にある矢印をクリックします。
５．テキスト欄に "MoveForward" と入力し、左側の矢印をクリックして軸のバインディングオプションを展開します。
６．ドロップダウン メニューでキーボードマークをクリックし、[W]キーを押します。
以下、前後左右の設定を同様に行います。
入力設定は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/2c70c1ec-bf45-e249-7ebc-0f48c528db9c.png)

#### C++での関数実装
MyCharacter.h で、以下の関数の宣言を`SetupPlayerInputComponent` の下に追加します。
```cpp:MyCharacter.h
UFUNCTION()
void MoveForward(float value);

UFUNCTION()
void MoveRight(float value);
```
MyCharacter.cppでは、以下の関数を追加します。
```cpp:MyCharacter.cpp
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	PlayerInputComponent->BindAxis("MoveForward", this, &AMyCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyCharacter::MoveRight);
}

void AMyCharacter::MoveForward(float value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
	AddMovementInput(Direction, value);
}

void AMyCharacter::MoveRight(float value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
	AddMovementInput(Direction, value);
}
```

## ステップ３：PlayerControllerの実装
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/eb789ed6-a234-5954-4792-8d7936582a39.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/70677c21-b1a0-5bd1-e89f-5d98bc9d916f.png)

１．コンストラクタ を追加
２．操作する Character のポインタを保存する AMyCharacter* m_pAMyCharacter を追加
３．操作する Character を開始時に保存するため BeginPlay() を override
４．「MoveForward」の入力をバインドするために SetupInputComponent() を override
５．「MoveForward」の入力を処理をする void MoveForward_Axis(float axisValue) を追加
```cpp:MyPlayerController.h
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyPlayerController.generated.h"
#include "MyCharacter.h"
#include "MyCharacter.generated.h"

UCLASS()
class MYPROJECT_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()
public:
    AMyPlayerController();

protected:
    AMyCharacter* m_pAMyCharacter;

protected:
    virtual void BeginPlay() override;
    virtual void SetupInputComponent() override;

    void MoveForward_Axis(float axisValue);
    void MoveRight_Axis(float axisValue);
};
```

```cpp:MyPlayerController.cpp
#include "MyPlayerController.h"

AMyPlayerController::AMyPlayerController()
    : APlayerController()
    , m_pAMyCharacter(nullptr)
{

}

void AMyPlayerController::BeginPlay()
{
    Super::BeginPlay();
    APawn* pPawn = GetPawn();
    ensure(pPawn != nullptr);
    m_pAMyCharacter = Cast<AMyCharacter>(pPawn);
    ensure(m_pAMyCharacter != nullptr);
}

void AMyPlayerController::SetupInputComponent()
{
    Super::SetupInputComponent();
    InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward_Axis);
}

void AMyPlayerController::MoveForward_Axis(float axisValue)
{
    check(m_pAMyCharacter != nullptr);
    m_pAMyCharacter->MoveForward(axisValue);
}

void AMyPlayerController::MoveRight_Axis(float axisValue)
{
    check(m_pAMyCharacter != nullptr);
    m_pAMyCharacter->MoveRight(axisValue);
}
```
### ゲームモードにCharacterとPlayerControllerをセットする
コンテンツ内で右クリックし、[ブループリントクラス]＞[GameModeBase]を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/97a4bac1-296e-2406-8400-c7f3121145d7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/fa038ebe-d678-448d-1a0c-2ec4785af757.png)
「ウィンドウ」メニューから「ワールドセッティング」にチェックを入れ、タブを開きます。
開かれたワールドセッティングで、「ゲームモードオーバーライド」の項目を先ほどのゲームモードに変更します。
以下、PawnとPlayerControllerにも先ほど作成したものを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/0717edc0-9e7a-b027-8cb1-944bf923402a.png)


## ステップ４：メッシュの設定
自身のPlayerにメッシュを追加します。
まず、コンテンツブラウザの[C++クラス]から自身の作成したクラスを右クリックして、ブループリントを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/df3481fd-8974-ec75-cc16-13a8a340609e.png)
名前を付けてブループリントを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/57a1d605-832a-20b7-649a-e626941331a5.png)
[コンポーネント] タブで Mesh コンポーネントをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/01a7576b-d264-457d-09bb-2b0408ad51fc.png)
[詳細]＞[メッシュ]から、スケルタルメッシュを入れます。ない場合は、アセットなどを利用してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/0bb87f65-6b42-e0ac-1b59-2b21f7095849.png)

## ステップ５：カメラの変更
カメラの位置をC++側で調整します。
MyCharacter.hに、カメラにアクセスするためのインクルードなどを行います。
```cpp:MyCharacter.h
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"

UPROPERTY(VisibleAnywhere)
UCameraComponent* CameraComponent;
```
MyCharacter.cpp では、次のコードをコンストラクタ内に追記します。
```cpp:MyCharacter.cpp
CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
check(CameraComponent != nullptr);

CameraComponent->SetupAttachment(CastChecked<USceneComponent, UCapsuleComponent>(GetCapsuleComponent()));

CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));

CameraComponent->bUsePawnControlRotation = true;
```

## ステップ６：ジャンプを追加してみる
移動の復習として、ジャンプを作ります。
まずインプットを設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600523/acbe59db-85af-1fcc-d49b-dbfcf59b5480.png)

MyCharacterに以下の関数を追加します。
```cpp:MyCharacter.h
UFUNCTION()
void MoveForward(float value);

UFUNCTION()
void MoveRight(float value);
```
```cpp:MyCharacter.cpp
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	PlayerInputComponent->BindAxis("MoveForward", this, &AMyCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyCharacter::MoveRight);
}

void AMyCharacter::MoveForward(float value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
	AddMovementInput(Direction, value);
}

void AMyCharacter::MoveRight(float value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
	AddMovementInput(Direction, value);
}
```
PlayerControllerにも追記します。
```cpp:MyPlayerController.h
    void StartJump_Input();
    void StopJump_Input();
```
```cpp:MyPlayerController.cpp
void AMyPlayerController::SetupInputComponent()
{
    //Super::SetupInputComponent();
    InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward_Axis);
    InputComponent->BindAction("Jump", IE_Pressed, this, &AMyPlayerController::StartJump_Input);
    InputComponent->BindAction("Jump", IE_Released, this, &AMyPlayerController::StopJump_Input);
}

void AMyPlayerController::StartJump_Input()
{
    check(m_pAMyCharacter != nullptr);
    m_pAMyCharacter->StartJump();
}

void AMyPlayerController::StopJump_Input()
{
    check(m_pAMyCharacter != nullptr);
    m_pAMyCharacter->StopJump();
}
```


## おわりに
以上が今回のまとめになります。閲覧ありがとうございました。

#### 参考資料
▼Unreal Engine　チュートリアル　キャラクター実装
https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/ProgrammingWithCPP/CPPTutorials/FirstPersonShooter/2/

▼Lyra Starter Game
https://www.youtube.com/watch?v=Fj1zCsYydD8&t=8s