UE 角色基础学习之路
本文最后更新于211 天前,其中的信息可能已经过时,如有错误请联系作者

移动与相机跟随

1. 创建玩家类

在创建自定义的玩家类前,先简要了解一下UE中的常用class:

Object 所有UE对象的基类
Actor 可以在世界中放置或生成的object
Pawn 可以被玩家或AI控制的Actor
Character 实现了双脚行走的Pawn
PlayerController 玩家与对应Pawn之间的接口
GameModeBase 定义游戏的基础规则
GameStateBase 记录游戏的状态

创建完成后,UE会在相应目录自动创建相应的.h和.cpp文件

打开.h文件后查看文件内容,在开头会看见类似下面的语句:

class ACTIONROGUELIKE_API ASCharacter : public ACharacter

可以发现UE在创建代码时,自动在原本的SurCharacter和Character类前添加了前缀A。这是因为UE遵守一系列代码编写规范,规定通过基类的种类或类的类型来确定前缀,进而可以区分类和实例。

基类 前缀 类型 前缀
UObject U 界面 Interfaces I
AAcor A 枚举 Enums E
SWidget S 模板 Templates T

2. 相机跟随

在创建相机跟随玩家前,首先需要建立一个关卡。

然后需要创建玩家。在内容浏览器中右键 -> 蓝图类

创建完毕后,将角色从内容浏览器拖拽进世界中。此时的角色是个没有任何模型,由数根线条围成的胶囊体。最后在角色的细节面板中搜索Pawn,将“自动控制玩家”设置为玩家0,这样在运行关卡时就可以控制该角色。当然,目前还没有实现控制方法,所以在此处运行时,角色是不会对键盘输入有任何反应的。

要实现相机跟随,可以通过代码直接创建UE中的弹簧臂对象和相机对象,并将弹簧臂attach(attach可理解为父子关系,你的确可以在角色的完整蓝图左上角的“组件”看到各个组件的层级关系)到自定义角色上、再把相机attach到弹簧臂上。

这个场景可以想象成角色后面连着一根直线(弹簧臂),直线的另一端是相机。这样做的好处有两个:1. 相机与角色通过弹簧臂相连,实现了相机跟随; 2. 弹簧臂是碰撞体,因此我们的角色在靠近墙壁时,相机不会穿模到墙壁的另一边,从而保证玩家视野中不会因为墙壁遮挡自己的角色。同时,在代码中声明的对象可以利用UPROPERTY宏定义,使得该对象可以在UE中直接修改。

//SCharacter.h
class USpringArmComponent;
class UCameraComponent;

UCLASS()
class ACTIONROGUELIKE_API ASCharacter : public ACharacter
{
	GENERATED_BODY()
	
	protected:

	UPROPERTY(VisibleAnywhere)
	UCameraComponent* CameraComp;

	UPROPERTY(VisibleAnywhere)
	USpringArmComponent* SpringArmComp;
		
}
//SCharacter.cpp
ASCharacter::ASCharacter()
{
	SpringArmComp = CreateDefaultSubobject<USpringArmComponent>("SpringarmComp");
	SpringArmComp->SetupAttachment(RootComponent);
	SpringArmComp->bUsePawnControlRotation = true;

	CameraComp = CreateDefaultSubobject<UCameraComponent>("CameraComp");
	CameraComp->SetupAttachment(SpringArmComp);
	
}

此时运行关卡(注意是保存在Maps中的关卡,而不是打开UE默认显示的关卡),可以发现角色和相机已经通过弹簧臂连接。

通过在角色和相机的中间插入移除正方体进行阻挡相机的实验,可以更好地理解弹簧臂在其中的作用。如果不添加弹簧臂,正方体就可能从角色和相机中间穿过,从而阻挡玩家视线。

3. 人物移动与转向

人物移动的相关代码需要编写在自动生成的SetupPlayerInputComponent函数中。这个函数中已经传入了PlayerInputComponent组件,所以不需要像上面自己创建新的弹簧臂和相机控件。人物移动对应UE中的轴(Axis)绑定,因为移动的幅度是个连续值,如使用游戏手柄时,不同程度推动摇杆可能对应不同的移动速度。

//SCharacter.cpp

// 实现角色向前移动
void ASCharacter::MoveForward(float value)
{
	// 朝某个方向前进value,GetActorForwardVector指向角色正前方
	AddMovementInput(GetActorForwardVector(), value);
}

void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	// “UE中调用的名称”,this指针表示移动这个角色,&自定义移动方法
	PlayerInputComponent->BindAxis("MoveForward", this, &ASCharacter::MoveForward);

}

随后,需要在UE中设置MoveForward的具体输入。在编辑 -> 项目设置 -> 输入 -> 绑定中添加轴映射 -> 输入MoveForward,即与BindAxis函数中第一个参数一致 -> 添加键盘输入W和S,两者的value分别为1.0和-1.0。这样设置后,在按下S的时候会调用MoveForward函数,传入-1.0,即角色前进负值,等同于后退。

此时运行关卡,就可以发现角色能够进行前进后退,且相机始终保持跟随。同理,利用UE中提供的GetActorRightVector()方法,可以实现角色的左右移动。

//SCharacter.cpp

void ASurCharacter::MoveRight(float value)
{
	AddMovementInput(GetActorRightVector(), value);
}

void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	// “UE中调用的名称”,this指针表示移动这个角色,&自定义移动方法
	PlayerInputComponent->BindAxis("MoveRight", this, &ASurCharacter::MoveRight);

}

最后,要实现角色通过鼠标转向则更简单。类似平移可以用XYZ轴度量,旋转也可以分解成这三个方向,UE中的Yaw方向表示绕Z轴旋转、即水平旋转。利用UE提供的AddControllerYawInput()函数可以得到Yaw方向的偏转;AddControllerPitchInput()函数可以得到Pitch方向的旋转。

//SCharacter.cpp
PlayerInputComponent->BindAxis("Turn",this,&APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("LookUp",this,&APawn::AddControllerPitchInput);

然后,同样需要在UE设置输入如下,鼠标X表示鼠标的横向(horizontal)移动,鼠标Y表示纵向(vertical)移动:

此外,在设置LookUp输入后,还需要在弹簧臂的“摄像机设置”属性中 勾选 “使用Pawn控制旋转”。

或者添加代码

ASCharacter::ASCharacter()
{
	SpringArmComp->bUsePawnControlRotation = true;
}

添加模型和动画

1. 为角色添加网格体

网格体可以理解为由一组多边形组成的中空的三维模型,UE中的网格体分为两种:骨骼网格体静态网格体。前者包括构成一组多边形组成的模型,和使多边形顶点产生动画的的骨骼;后者只包含一组多边形组成的模型。两者的区别在于是否有骨骼可以绑定动画

在UE中打开自定义角色Player的完整蓝图 -> 左上角“组件”中点击网格体 -> 右侧“细节”面板 -> 网格体 -> 选择Gideon模型。

但此时进入世界会发现,角色悬空,且没有朝向胶囊体的正前方(蓝色箭头)。

因此需要在Player的网格体组件的变换属性中,对位置和旋转两个参数进行相应调整。

2. 为角色添加动画

在网格体的动画属性中指定对应的Gideon角色动画

控制旋转

控制角色旋转

到目前为止,我们已经实现了初步的角色运动和旋转。但细看就会发现,角色的朝向和摄像机的旋转是一起的,即我们移动鼠标,角色也跟着旋转。但参考游戏经验,摄像机旋转和角色旋转应该是两个独立的事件。

因此,我们需要分离控制相机的鼠标控制旋转(ControlRotation)和角色旋转(Pawn’s Rotation)。只需要在Player(自身)的Pawn属性里取消勾选Use Controller Rotation Yaw;并把弹簧臂中的“摄像机设置”的“使用Pawn控制旋转”开启。

这在区分摄像机与角色旋转的同时,我们也不能再控制角色旋转。此外,还需要把Player的“角色移动”中的“将旋转朝向运动”勾选,这样在我们按下A/D进行左右移动时,角色会转向相应的方向,而不是侧着身子漂移。

或者在代码中添加 一劳永逸

//SCharacter.cpp

ASCharacter::ASCharacter()
{
	SpringArmComp->bUsePawnControlRotation = true;
	GetCharacterMovement()->bOrientRotationToMovement = true;
	bUseControllerRotationYaw = false;
}

此时运行关卡,按下左移不松手,会发现角色一直转圈圈。因为每当向左移动,角色也朝向左边,后续的左移会在这个基础之上,所以结果就是这样的圆周运动。

我们目前需要实现的操作方式,是在按下前进后,角色转向相机的方向,然后直线移动;在按下左移时,角色在初始朝向的基础上,转向左方,然后一直朝固定的方向直线移动。也就是在移动时需要一个用来表示空间方向的方向向量vector,且这个vector在按下键盘的时间段内是一个定值。因此,前后移动的实现如下:

//SCharacter.cpp

void ASCharacter::MoveForward(float value)
{
	FRotator ControlRot = GetControlRotation();
    // 转向只关注水平Yaw方向,因此置0防止影响
	ControlRot.Pitch = 0.0f;
	ControlRot.Roll = 0.0f;
    
	// 获取相机(鼠标控制器)的朝向,并朝这个方向移动
	AddMovementInput(ControlRot.Vector(),value);
}

同理,左右移动只需要在相机朝向的基础上向左/右转90°就可以实现。需要额外说明,在UE中XYZ轴的正向分别对应前方、右方和上方,显示的箭头颜色分别为红色、绿色和蓝色(三基色的习惯顺序)。

void ASCharacter::MoveRight(float value)
{

	FRotator ControlRot = GetControlRotation();
	ControlRot.Pitch = 0.0f;
	ControlRot.Roll = 0.0f;
	
    // 获取相机(鼠标控制器)的朝向,转向右侧,并朝这个方向移动;传入的Y表示右侧
	FVector RightVector = FRotationMatrix(ControlRot).GetScaledAxis(EAxis::Y);
	
	AddMovementInput(RightVector,value);
}

再次运行关卡,发现角色可以正确的移动和转向了。

评论

  1. shenmiren
    Windows Chrome
    12 月前
    2024-5-22 1:36:27

    不是,哥们?

    来自天津
    • Avatar photo
      博主
      shenmiren
      Windows Chrome
      12 月前
      2024-5-22 16:09:20

      旭哥,快和我玩守望先锋!!!😫

      来自海南

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇