UE4

UE4/C++ プレイヤーコントローラーを修正する2(4/)

行動の遷移処理(Action)の実装

CppPlayerController.cppの修正

まずは全文

/**
 * @file CppPlayerController.cpp
 * @brief プレイヤーコントローラー
 * @author     inuvatico
 * @date        2020/10/17
 * @version     1.0
 * @copyright   2020 inuvatico
 * Released under the MIT license.
 *   see https://opensource.org/licenses/MIT
 * @par (new/Add/Change : 2020/10/17)
 *
*/

#include "CppPlayerController.h"
#include "CppPlyBase.h"
#include "../../../uty/ArmCamera.h"
#include "../../../uty/AnmStateComponent.h"
#include "GameFramework/CharacterMovementComponent.h"

//----------------------------------------------------------------
/// コンストラクタ
//----------------------------------------------------------------
ACppPlayerController::ACppPlayerController() {

    PrimaryActorTick.bCanEverTick = true; //Tickを呼ばれるようにする
}
//----------------------------------------------------------------
/// BeginPlay()
//----------------------------------------------------------------
void ACppPlayerController::BeginPlay() {

    Super::BeginPlay();

    MyActor = dynamic_cast <ACppPlyBase*> (GetCharacter());
    if (!MyActor) return;

    // カメラをセットアップする
    ArmCamera = UArmCamera::Create(MyActor);

    FVector ofs(0, 0, 100);//注視点を1m高くする
    ArmCamera->SetRelativeLocation(ofs);

    //移動方向を向かせる
    {
        MyActor->bUseControllerRotationPitch = false;
        MyActor->bUseControllerRotationYaw = false;
        MyActor->bUseControllerRotationRoll = false;

        auto cmove = MyActor->GetCharacterMovement();
        cmove->bOrientRotationToMovement = true;
        cmove->RotationRate = FRotator(0.0f, 360*2, 0.0f);
    }

    SetAction(ActType::Init);
}
//----------------------------------------------------------------
///Tick
//----------------------------------------------------------------
void ACppPlayerController::Tick(float DeltaTime) {

    if (GEngine)
        GEngine->AddOnScreenDebugMessage(-1, 1.0f / 560.f, FColor::Orange, FString::Printf(TEXT("Tick")));

    PadInput.update(this); //Key入力の更新

    //カメラ の更新
    if (PadInput.JoyRdist) {
        ArmCamera->AddRotation(PadInput.JoyR_X, PadInput.JoyR_Y);
    }

    if (CurrentAction) {
        (this->*CurrentAction)(CallType::ACT);
    }
}
//----------------------------------------------------------------
///PAD入力による移動
//----------------------------------------------------------------
void ACppPlayerController::PadMove(void) {
    float speedRate = PadInput.JoyLdist;
    if (PadInput.JoyLdist) {

        // カメラアームの 方向 を取得
        FRotator Rotation = ArmCamera->GetRelativeRotation();
        FRotator YawRotation(0, Rotation.Yaw, 0);
        // PADの 方向 を取得
        float angl = atan2(PadInput.JoyL_Y, -PadInput.JoyL_X);
        // 移動方向を計算
        angl += FMath::DegreesToRadians(-90 + Rotation.Yaw);

        UPawnMovementComponent* MovementComponent = MyActor->GetMovementComponent();
        if (MovementComponent->Velocity.Z != 0) {
            angl = atan2(MovementComponent->Velocity.Y, MovementComponent->Velocity.X);
        }

        FVector vec(0, 0, 0);
        vec.X = cos(angl);
        vec.Y = sin(angl);
        MyActor->AddMovementInput(vec, speedRate);
    }
}
//-------------------------------------------------------------------------------
// アクション関係
//-------------------------------------------------------------------------------
void ACppPlayerController::ActInit(CallType type) {
    if (type == CallType::ACT) {
        SetAction(ActType::IdleRun);
    }
}
void ACppPlayerController::ActIdleRun(CallType type) {

    if (CallType::INIT == type) {
        MyActor->AnmStateComponent->SetAnmIndex(UAnmIndex::ANMID_IDLE_RUN);
    }if (CallType::ACT == type) {
        //移動
        PadMove();
        MyActor->AnmStateComponent->BPAnmState.Speed = PadInput.JoyLdist;

        if (PadInput.BtnOn&BTN_R_L) {
            SetAction(ActType::Attack1);
        }
    }
}

//-------------------------------------------------
//! 攻撃(SHOOT)
//-------------------------------------------------
void ACppPlayerController::ActAttack1(CallType type) 
{
    if (CallType::INIT == type) {
        MyActor->AnmStateComponent->SetAnmIndex(UAnmIndex::ANMID_ATTACK1);
    }if (CallType::ACT == type) {

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_SHOOT1))) {
            GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Orange, FString::Printf(TEXT("SHOOT1")));
        }

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_SHOOT2))) {
            GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Orange, FString::Printf(TEXT("SHOOT2")));
        }

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_END))) {
            SetAction(ActType::IdleRun);
            return;
        }
    }
}

処理の概要

  1. 処理が開始さるとBeginPlay()でActType::Init指定されます
  2. ActInit()はすぐにActIdleRun()に遷移します
  3. ActIdleRun()は移動/カメラ制御と攻撃(ActAttack1)への遷移を行います
  4. ActAttack1()は攻撃が終了するとActIdleRun()に遷移します

各メソッドについて

BeginPlay()

BeginPlay() では最初のActionSetAction(ActType::Init)
を呼び出します。

void ACppPlayerController::BeginPlay() {
    ---
    ---
    SetAction(ActType::Init);
}

Tick()

現在有効なActionを呼び出します。

void ACppPlayerController::Tick(float DeltaTime) {
    ---
    ---
    if (CurrentAction) {
        (this->*CurrentAction)(CallType::ACT);
    }
}

ActInit()

いまは、ActType::IdleRunに切り替えるだけです。

ActIdleRun()

・開示時(CallType::INIT)にSetAnmIndexを使って待機&移動アニメーション(ANMID_IDLE_RUN)を設定します。
・BPAnmState.Speedにジョイスティックのdistを入れることで待機/移動のアニメーション遷移を行います。
・攻撃ボタン(BTN_R_L)が押下されるとActionが攻撃(Attack1)に遷移します。

void ACppPlayerController::ActInit(CallType type) {
    if (type == CallType::ACT) {
        SetAction(ActType::IdleRun);
    }
}
void ACppPlayerController::ActIdleRun(CallType type) {

    if (CallType::INIT == type) {
        MyActor->AnmStateComponent->SetAnmIndex(UAnmIndex::ANMID_IDLE_RUN);
    }if (CallType::ACT == type) {
        //移動
        PadMove();
        MyActor->AnmStateComponent->BPAnmState.Speed = PadInput.JoyLdist;

        if (PadInput.BtnOn&BTN_R_L) {
            SetAction(ActType::Attack1);
        }
    }
}

ActAttack1()

銃を撃つ処理です。
初期処理(CallType::INIT)でアニメーションを指定します。
アニメーション通知のST_SHOOT1/ST_SHOOT2で弾丸を発射します。(予定)
アニメーション通知の終了(ST_END)を受け取ると待機状態(SetAction(ActType::IdleRun))に戻ります。

//-------------------------------------------------
//! 攻撃(SHOOT)
//-------------------------------------------------
void ACppPlayerController::ActAttack1(CallType type) 
{
    if (CallType::INIT == type) {
        MyActor->AnmStateComponent->SetAnmIndex(UAnmIndex::ANMID_ATTACK1);
    }if (CallType::ACT == type) {

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_SHOOT1))) {
            GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Orange, FString::Printf(TEXT("SHOOT1")));
        }

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_SHOOT2))) {
            GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Orange, FString::Printf(TEXT("SHOOT2")));
        }

        if (MyActor->AnmStateComponent->AnmEventBit& (1 << static_cast<int>(UAnmEvent::ST_END))) {
            SetAction(ActType::IdleRun);
            return;
        }
    }
}









digitalize
  始めました。