在这个教程中,我们将学习在虚幻引擎中如何使用C++创建第一人称角色。

1、第一人称游戏机制

在视频游戏中,第一人称(First Person)是对游戏玩家角色视点的图形渲染。当今最流行的第一人称游戏类型包括第一人称射击游戏、基于模拟的系统如飞行模拟器等。在这里,游戏玩家无法看到实际的游戏角色网格。虽然他们可能会看到一些零件,如手,武器等。此外,具有第一人称视角的游戏也不需要复杂的动画。

2、第一人称游戏示例

Village — BioHazard 8 (2021)
Halo Infinite(2021)
BioHazard 7(2017)
Doom(1993)

3、使用虚幻引擎创建第一人称角色

我们将使用C++创建一个第一人称角色,然后基于该C++类创建子蓝图类。我们要创建的角色将如下所示:

这里你可以看到摄像机充当了视点,并为玩家提供第一人称视角视图。胶囊组件以及骨架网格组件、角色移动组件提供了有关角色移动的属性,如行走速度、跳跃Z速度、重力等,默认情况下与虚幻引擎中的角色类一起出现。

打开C++类文件夹,然后右键单击创建新C++类

选择角色类并为C++类命名,然后单击"创建"。

现在,虚幻编辑器将打开源代码编辑器。

打开C++类的头文件,可以看到它已经附带了一些用于构造函数和覆盖方法的模板代码,例如在游戏启动时调用的BeginPlay()和为每帧调用的Tick()在public或protected部分中添加以下函数声明。在这里,每种方法都对应于角色的特定运动。

然后为UCameraComponent声明一个实例,该实例充当摄像机以提供第一人称视角。在这里,我们指定了UPROPERTY()宏,它告诉虚幻引擎的反射系统,给定的属性应该在基于这个C++类创建的蓝图类中可访问。

UPROPERTY(EditAnywhere,Category="Components")
UCameraComponent* Camera;

注意:请确保导入必要的头文件。

整个头文件代码如下所示:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "FirstPersonPlayerCharacter.generated.h"

UCLASS()
class FIRSTPERSONCHARACTER_API AFirstPersonPlayerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AFirstPersonPlayerCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere,Category="Components")
	UCameraComponent* Camera;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	
	void LookRightLeft(float axisvalue);

	
	void LookUpDown(float axisvalue);


	void MoveForwardBackward(float axisvalue);

	
	void MoveRightLeft(float axisvalue);


	void BeginCrouch();

	
	void EndCrouch();

};

现在打开项目设置,在input部分,我们添加键绑定以使用键盘和鼠标作为输入设备来控制角色:

现在打开FirstPerson角色类的CPP文件,该文件具有在头文件中声明的构造函数,BeginPlay()和Tick()函数的实现。

现在,我们需要在构造函数中初始化相机实例:

AFirstPersonPlayerCharacter::AFirstPersonPlayerCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
  
	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("PlayerCamera"));
	Camera->SetupAttachment(RootComponent);
        this->GetCharacterMovement()->GetNavAgentPropertiesRef().bCanCrouch = true;
}

在这里,我们使用 CreateDefaultSubobject<T>() 模板方法来创建实际的相机组件,该方法通过指定组件类类型来创建实际组件,在我们的例子中它是一个相机组件,所以 使用UCameraComponent 类,并在 TEXT() 宏中传入组件的名称。然后,我们将相机附加到根组件,该组件是角色类中的胶囊组件。然后,为了让我们的角色蹲下,我们将角色移动类的蹲伏属性(crouch)设置为 true。

接下来,为头文件中声明的方法创建实现代码:

void AFirstPersonPlayerCharacter::LookRightLeft(float axisvalue) 
{
	this->AddControllerYawInput(axisvalue);
}

void AFirstPersonPlayerCharacter::LookUpDown(float axisvalue) 
{
	this->AddControllerPitchInput(axisvalue);
}

void AFirstPersonPlayerCharacter::MoveForwardBackward(float axisvalue) 
{
	this->AddMovementInput(this->GetActorForwardVector() * axisvalue);
}

void AFirstPersonPlayerCharacter::MoveRightLeft(float axisvalue) 
{
	this->AddMovementInput(this->GetActorRightVector() * axisvalue);
}

void AFirstPersonPlayerCharacter::BeginCrouch() 
{
	this->Crouch();
	
}

void AFirstPersonPlayerCharacter::EndCrouch() 
{
	this->UnCrouch();
}

AddMovementInput()此方法沿给定的世界方向矢量(通常归一化)添加移动输入,按ScaleValue的值缩放。如果 ScaleValue < 0,则移动方向相反。scale值是函数中的轴值参数。其值范围为 +1.0f 至 -1.0f。

此方法有一个FVector类型的参数 WorldDirection。对于前后移动,我们获取角色的前向向量并将其乘以比例值。在我们的例子中,当玩家按W时,比例值将为+1.0f,乘以向前矢量,它成为+ve矢量,玩家向前移动类似,当玩家按S时,比例值将为-1.0f,乘以向前矢量,它成为-ve矢量,玩家向后移动相同的概念应用于左右移动。

  • AddControllerPitchInput():围绕Y轴的旋转被称为俯仰,它处理角色的上下观察。
  • AddControllerYawInput():旋转的Z轴称为偏航,它处理角色的左右观察。
  • Crouch()Uncrouch()这两个方法是角色类的内置方法,用于执行蹲伏和取消蹲伏操作。

接下来,我们需要将输入键与这些函数挂钩。它可以通过使用角色类的SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)方法来完成,因为角色类是pawn类的子类。在该函数中,在下面添加此代码行:

PlayerInputComponent->BindAxis(TEXT("Horizontal"),this,&AFirstPersonPlayerCharacter::LookRightLeft);
	PlayerInputComponent->BindAxis(TEXT("Vertical"),this,&AFirstPersonPlayerCharacter::LookUpDown);
	PlayerInputComponent->BindAxis(TEXT("ForwardBackward"),this,&AFirstPersonPlayerCharacter::MoveForwardBackward);
	PlayerInputComponent->BindAxis(TEXT("RightLeft"),this,&AFirstPersonPlayerCharacter::MoveRightLeft);
	PlayerInputComponent->BindAction(TEXT("Jump"),IE_Pressed,this,&ACharacter::Jump);
	PlayerInputComponent->BindAction(TEXT("Crouch"),IE_Pressed,this,&AFirstPersonPlayerCharacter::BeginCrouch);
	PlayerInputComponent->BindAction(TEXT("Crouch"),IE_Released,this,&AFirstPersonPlayerCharacter::EndCrouch);

在这里,我们设置实际的轴输入和动作输入,并传递要调用的函数引用将它们与移动函数挂钩。

现在编译代码并在ue4编辑器中打开C++文件夹,右键单击并基于此C++类创建蓝图。

打开蓝图,确保勾选相机选项中的Use Pawn Control Rotation。这将允许相机在充当控制器时根据鼠标移动进行旋转。

完整的 FirtPersonPlayerCharacter.cpp 代码:

// Fill out your copyright notice in the Description page of Project Settings.


#include "FirstPersonPlayerCharacter.h"
#include "DrawDebugHelpers.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/InputComponent.h"

// Sets default values
AFirstPersonPlayerCharacter::AFirstPersonPlayerCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("PlayerCamera"));
	Camera->SetupAttachment(RootComponent);

	
    this->GetCharacterMovement()->GetNavAgentPropertiesRef().bCanCrouch = true;
    
	PhysicsHandle = CreateDefaultSubobject<UPhysicsHandleComponent>(TEXT("Hand"));
	HoldingSocket = CreateDefaultSubobject<USceneComponent>(TEXT("HoldingSocket"));

	


   
}

// Called when the game starts or when spawned
void AFirstPersonPlayerCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	if(PhysicsHandle == nullptr)
	{
		UE_LOG(LogTemp,Warning,TEXT("Got it"));
	}
	
}

// Called every frame
void AFirstPersonPlayerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

		
		  
}
	

}

// Called to bind functionality to input
void AFirstPersonPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("Horizontal"),this,&AFirstPersonPlayerCharacter::LookRightLeft);
	PlayerInputComponent->BindAxis(TEXT("Vertical"),this,&AFirstPersonPlayerCharacter::LookUpDown);
	PlayerInputComponent->BindAxis(TEXT("ForwardBackward"),this,&AFirstPersonPlayerCharacter::MoveForwardBackward);
	PlayerInputComponent->BindAxis(TEXT("RightLeft"),this,&AFirstPersonPlayerCharacter::MoveRightLeft);
	PlayerInputComponent->BindAction(TEXT("Jump"),IE_Pressed,this,&ACharacter::Jump);
	PlayerInputComponent->BindAction(TEXT("Crouch"),IE_Pressed,this,&AFirstPersonPlayerCharacter::BeginCrouch);
	PlayerInputComponent->BindAction(TEXT("Crouch"),IE_Released,this,&AFirstPersonPlayerCharacter::EndCrouch);
	
	

}

void AFirstPersonPlayerCharacter::LookRightLeft(float axisvalue) 
{
	this->AddControllerYawInput(axisvalue);
}

void AFirstPersonPlayerCharacter::LookUpDown(float axisvalue) 
{
	this->AddControllerPitchInput(axisvalue);
}

void AFirstPersonPlayerCharacter::MoveForwardBackward(float axisvalue) 
{
	this->AddMovementInput(this->GetActorForwardVector() * axisvalue);
}

void AFirstPersonPlayerCharacter::MoveRightLeft(float axisvalue) 
{
	this->AddMovementInput(this->GetActorRightVector() * axisvalue);
}

void AFirstPersonPlayerCharacter::BeginCrouch() 
{
	this->Crouch();
	
	
}

void AFirstPersonPlayerCharacter::EndCrouch() 
{
	this->UnCrouch();
}

原文链接:Create a First Person character in Unreal Engine using C++

BimAnt翻译整理,转载请标明出处