玩家輸入與Pawn
這個時組件和碰撞的提前知識預備,最好在之前了解組件相關(guān)東西,重要的概念對于軸映射和操作映射。
首先介紹兩個概念
- Actor類——可以放到游戲場景中的游戲?qū)ο蟮幕绢愋汀D闳绻敕胖萌魏螙|西到游戲場景中,必須繼承Actor類
- Pawn類——代表你或者代表電腦的人工智能的游戲?qū)ο?/strong>,它是可以在屏幕上控制的游戲?qū)ο蟆awn類是從Actor類中繼承的,它可以通過玩家的設(shè)備(鍵盤、鼠標等)控制或者被人工智能腳本控制。如果它是被玩家控制的,我們通常稱之為controller(控制器);如果它是被人工智能腳本控制的,我們通常稱之為AI(Artificial Intelligence,人工智能),如果你經(jīng)常玩游戲,那些NPC(Non-player Characters,非玩家角色)就通常具有AI行為。
自己定義Pawn
- 打開UE4的C++項目,添加C++類,命名為MyPawn
- 在cpp中設(shè)置玩家控制
// 將該Pawn設(shè)為由最小編號玩家控制
AutoPossessPlayer = EAutoReceiveInput::Player0;
- 構(gòu)建幾個組件,在MyPawn.h底部添加
UPROPERTY(EditAnywhere)
USceneComponent* OurVisibleComponent;
《Inside UE4》-GamePlay架構(gòu)系列博客
首先要知道一個對象要在3D世界中的表示,必然要攜帶一個Transform來表示其位置。但是在UE看來,Actor并不只是3D中的表示,一些不在世界中展示的“不可見對象”也可以是Actor,比如AInfo的派生類等,所以Actor也就沒有自帶Transform了。
而SceneComponent則封裝了Transform,當作RootComponent,所以需要位置表示的Actor就可以向Actor中添加ScenetComponent作為其RootComponent.比如,pawn就自動創(chuàng)建了SceneComponent.
還有一點需要注意的是,實際中大部分的Actor是有Transform的,所以我們會經(jīng)常設(shè)置獲取它的坐標,常理來說,我們的需要先獲取下SceneComponent,然后才能操作其Transform等相應(yīng)接口,但是這樣太過繁瑣,因此UE為我們直接提供了基于Actor的接口,如Get/Set ActorLocation,但其實這些接口內(nèi)部也是轉(zhuǎn)發(fā)到RootComponent(SceneComponent)的。
- 將下面代碼添加到cpp中構(gòu)造函數(shù)AMyPawn::AMyPawn
這里需要在開頭添加
#include "Camera/CameraComponent.h"
// 創(chuàng)建可附加內(nèi)容的虛擬根組件。
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
// 創(chuàng)建相機和可見對象
UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("OurCamera"));
OurVisibleComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("OurVisibleComponent"));
// 將相機和可見對象附加到根組件。偏移并旋轉(zhuǎn)相機。
OurCamera->SetupAttachment(RootComponent);
OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
OurVisibleComponent->SetupAttachment(RootComponent);
- 現(xiàn)在便擁有響應(yīng)游戲輸入的自定義Pawn,需定義此輸入的內(nèi)容。為此,將在 虛幻編輯器 中配置項目的 輸入設(shè)置。
配置游戲輸入
輸入的映射有兩種——操作和軸
操作映射
適用于"是/否"輸入,例如鼠標或手柄上的按鈕。被按下、松開、雙擊或短時長按時,其將進行報告。跳躍、射擊或與物體互動等離散操作是這類映射的理想對象。
軸映射
是連續(xù)的,可將其視為"程度"輸入,例如手柄上的搖桿,或者鼠標光標的位置。其會逐幀報告自身的值,即使未移動也進行報告。通常使用此方法處理如行走、四處查看和操縱車輛等有量級或方向的對象。
雖然可直接在代碼中定義輸入映射,但常用方法是在 虛幻引擎 編輯器中定義,本教程也將使用此方法。
- 在 虛幻引擎編輯器中,在 編輯 下拉菜單下,點擊 項目設(shè)置(Project Settings) 選項。
- 在此界面左側(cè)的 引擎(Engine) 部分中選擇 輸入 選項。之后,展開右側(cè)顯示的 綁定 類別,添加 操作映射(Action Mapping) 和兩個軸映射(Axis Mappings)。
[圖片上傳失敗...(image-76b742-1623143400720)] - 輸入現(xiàn)已配置完成,接下來在關(guān)卡中設(shè)置MyPawn。MyPawn 類將在 內(nèi)容瀏覽器 中顯示,并可被拖入 關(guān)卡編輯器。[圖片上傳失敗...(image-76a21f-1623143400720)]
- 設(shè)置MyPawn還需一個步驟。需向其指定 靜態(tài)網(wǎng)格體,以便其可在游戲中顯示。具體操作:選擇剛創(chuàng)建的MyPawn,在 細節(jié)面板 中選擇名為 OurVisibleComponent (Inherited) 的組件,并利用 靜態(tài)網(wǎng)格體 類別中的下拉框向其指定資源。在本教程中,Shape_Cylinder 為現(xiàn)成資源。 [圖片上傳失敗...(image-62bd6a-1623143400720)]
- 現(xiàn)在保存關(guān)卡,返回 Visual Studio 編寫代碼,使剛剛放置的MyPawn對定義的輸入做出反應(yīng)。
編寫和綁定游戲操作
- 在 Visual Studio 中,打開MyPawn.h并將以下代碼添加到MyPawn類定義的底部:
四個輸入函數(shù)將被綁定到輸入事件。其運行時,將對新輸入變量中存儲的值進行更新,MyPawn將使用此類值決定游戲期間應(yīng)執(zhí)行的操作。
//輸入函數(shù)
void Move_XAxis(float AxisValue);
void Move_YAxis(float AxisValue);
void StartGrowing();
void StopGrowing();
//輸入變量
FVector CurrentVelocity;
bool bGrowing;
- 切換到MyPawn.cpp,并對剛才聲明的四個函數(shù)編碼。
使用 FMath::Clamp 約束輸入中得到的值,將其約束在-1到+1的范圍內(nèi)。雖然本例中不存在此問題,但若有會對軸產(chǎn)生相同影響的多個鍵,則玩家同時按下此類輸入時會將累加這些值。例如,如W鍵和向上方向鍵均映射到MoveX,且縮放均為1.0,同時按下這兩個鍵會得到2.0的AxisValue。如不進行限制,玩家將以兩倍速度移動。
void AMyPawn::Move_XAxis(float AxisValue)
{
// 以100單位/秒的速度向前或向后移動
CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}
void AMyPawn::Move_YAxis(float AxisValue)
{
// 以100單位/秒的速度向右或向左移動
CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}
void AMyPawn::StartGrowing()
{
bGrowing = true;
}
void AMyPawn::StopGrowing()
{
bGrowing = false;
}
可以看到,兩個"Move"函數(shù)將軸值視作浮點,而"Grow"則不同。這是因為其映射到MoveX和MoveY,均為軸映射,因此擁有浮點參數(shù)。操作映射無此參數(shù)。
- 現(xiàn)在已定義輸入函數(shù),接下來需進行綁定,以便對相應(yīng)輸入做出反應(yīng)。將以下代碼添加到 AMyPawn::SetupPlayerInputComponent 中:
// 在按下或松開"Grow"鍵時做出響應(yīng)。
InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);
// 對兩個移動軸"MoveX"和"MoveY"的值逐幀反應(yīng)。
InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);
- 變量現(xiàn)在將根據(jù)配置的輸入進行更新。接下來只需編寫代碼使其完成部分操作。將以下代碼添加到 AMyPawn::Tick:
// 根據(jù)"Grow"操作處理增長和縮減
{
float CurrentScale = OurVisibleComponent->GetComponentScale().X;
if (bGrowing)
{
// 一秒內(nèi)增長到兩倍大小
CurrentScale += DeltaTime;
}
else
{
// 以增長速度縮減一半
CurrentScale -= (DeltaTime * 0.5f);
}
// 確保不會降至初始大小以下,或者增至兩倍大小以上。
CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
}
// 根據(jù)"MoveX"和"MoveY"軸處理移動
{
if (!CurrentVelocity.IsZero())
{
FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
SetActorLocation(NewLocation);
}
}
- 編譯代碼后,可返回 虛幻編輯器 并按 運行。應(yīng)可使用WASD鍵控制 Pawn,同時可通過長按 空格 鍵來使其增長,松開空格鍵時看到縮小。