UE4 C++角色与道具技能的互动(下)
Posted Vincent_0000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4 C++角色与道具技能的互动(下)相关的知识,希望对你有一定的参考价值。
前言
上一章已经把道具实现好了,现在就把界面做一下,让角色和道具之间具有联系,并且给角色一个加速的技能。
功能介绍:
我们点击运行之后,左上角会出现血条和体力条,右上角会出现金币数。
当我们角色按下左shift键的时候会消耗体力条,并且人会加速。
当体力条耗尽的时候体力条会处于恢复状态,在这个状态下无法使用加速按钮。
当拾取金币时金币数会增加,道具消失(为啥金币上有火???),碰到爆炸物的时候会扣血。
制作HUD UI
先将上边的这个界面做一下。
界面上有血条、体力条、金币数。
金币数UI实现
右击空白处新建小装置蓝图:
重命名为WB_Coin
,命名要遵守命名规范,WB为Widget Blueprint的简写,下划线后为我们所取的名字。
双击打开界面, 看到右上角,打开Panel:
将Canvas Panel删除
把Horizontal Box 拉到他的位置,Size Box拉到它的下面,点击Fill,填充整个区域;在Common中找到Image,拉到Size Box的下面,这里使用Size Box的好处在于它不会将图片进行拉伸,把图片弄的很难看
找到右边的细节面板,找到下面这个界面,将选择我们的图片。
如果之前没有图片资源,那么到网上下载好我们想要的图片之后,找到下图界面,点击 Import即可。
找到下图界面,将Text Box 拖到与 Size Box 同级的位置。
点击Fill,下面两个也可以按照我那样操作,可以让文本处于区域的中间位置。
他们之间的层级关系如下:
效果:
体力条、血条UI实现
这两个就更简单了:
按照这个层级关系摆放:
以血条为例:
Progress Bar 在Common里面。
Progress 点击 Fill
进度先设置为一个
20
%
20\\%
20%
血条颜色我们设置为红色:
再新建一个体力条,和这个也是类似的。
总界面UI实现
层级关系如下:
先拉入两个水平盒子:
都点击填充, 第一个水平盒子设置为需要这样设置一下:
代表的是我们的那个血条、体力条等UI的总共区域。
再添加三个垂直盒子
都点击Fill, 第一个第二个第三个。
在第一个垂直盒子中放入两个水平盒子:
代表的是血条的位置和体力条的位置,他们之间是有间隙的,所以将间隙设置为10
然后放入我们的血条和体力条,在用户创建这个地方可以找到我们之前创建的。
都点击填充。
第三个位置放入我们硬币界面,点击Fill。
UI界面制作完成,接下来我们要让这个界面显示到屏幕中。
创建玩家控制器C++文件
右键新建C++类,创建一个继承PlayerController的类,我这里命名为:MainPlayerController
。
打开之后会看到什么功能函数也没有。
.h 文件
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<UUserWidget> HUDAsset;
UUserWidget* HUD;
protected:
virtual void BeginPlay() override;
HUDAsset
就是储存widget Blueprint的变量,就是我们刚刚创建的那些界面资源。
HUD
就是一个用户控件对象
重写BeginPlay()函数。
.cpp文件
- BeginPlay
添加头文件: #include "Blueprint/UserWidget.h"
如果蓝图中设置了HUDAsset
变量,那么就可以创建一个HUD 实例, 然后让它设置在我们的界面中能够看到我们的空间对象。
void AMainPlayerController::BeginPlay()
{
if (HUDAsset) {
HUD = CreateWidget<UUserWidget>(this, HUDAsset);
}
if (HUD) {
HUD->AddToViewport();
}
}
然后以这个文件为父类创建蓝图,在蓝图细节面板中加入我们之前创建的界面:
打开主编辑界面,看到世界设置,在Game Mode 中选择我们新建的玩家控制器。
这样界面中就能显示啦!
接下来就要设置界面的动态变化了。
角色C++文件设置
.h文件
- 声明血量、最大血量、体力值、最大体力值、硬币数。
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Health; // 当前血量
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float MaxHealth; // 最大血量值
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Stamina; // 体力值
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float MaxStamina; // 最大体力值
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 Coins; // 硬币数
写int
的时候最好写int32
,如果写int
,电脑会根据配置来设置int
的占位情况,就有动态的变化了,不方便后期维护。
- 声明受到伤害之后的反应函数
void SufferDamage(float Damage);
(代表消极影响) - 声明死亡函数
void Die();
- 声明拾取金币函数(代表积极影响)
void Pickup(EPickupType Type, uint32 Count);
EPickupType
代表的是类型,需要在前面声明:
enum EPickupType {
PT_Coin
};
当前只有一个类型看不出来优势,但是随着类型的越来越多,他的优势就体现出来了,这是一种项目思想,为后期维护做好准备。
- 声明角色当前状态
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
EStatus CurrentStatus;
EStatus
需要在前面声明一下:
UENUM(BlueprintType) // 可蓝图化
enum class EStatus : uint8 {
ES_Normal UMETA(DisplayName = "Normal"),
ES_Sprint UMETA(DisplayName = "Sprint")
};
这个声明就是让类型可蓝图化,在蓝图中显示类型的东西就标签后面显示的名字:“Normal”、“Sprint”
代表的是角色是处于平常状态,还是加速状态。
- 声明设置角色状态
void SetStatus(EStatus Status);
- 声明普通跑步速度
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float RunSpeed;
- 声明加速跑步速度
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float SprintSpeed;
- 声明加速开始、加速结束做出的反应函数
UFUNCTION()
void BeginSprint();
UFUNCTION()
void EndSprint();
- 声明是否已经耗尽体力
UPROPERTY(EditAnywhere, BlueprintReadOnly)
bool IsExhausted;
- 声明恢复体力的速度
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float StaminaDrainRate;
.cpp 文件
- BeginSprint()
开始冲刺的时候,只要他不是耗尽状态,那么我们就把他的状态设置为冲刺状态。
如果是耗尽状态,按Shift键是没有任何响应的。
if (!IsExhausted) {
SetStatus(EStatus::ES_Sprint);
}
- EndSprint()
冲刺结束,将状态设置为平常状态。
SetStatus(EStatus::ES_Normal);
- Tick(float DeltaTime)
因为我们的体力是可以恢复的,而这个恢复状态是动态的,所以要每一帧都要更新它。
我们首先要将恢复体力的值计算出来。
如果是平常状态,那么我们的体力值就可以恢复,先将恢复的体力值计算出来,如果超过了最大体力值,就直接设置为最大值,并且要维护是否耗尽变量,让他保持非耗尽状态。如果没有超过最大体力值,计算出来的值就是当前的体力值。
如果是加速状态,那么我们的体力值就处于消耗的状态,先将消耗之后的体力值计算出来,如果小于零(已经消耗完了),就直接设置为0,并且要维护是否耗尽变量,让他保持耗尽状态, 加速状态改为非冲刺状态。如果没有小于零,计算出来的值就是当前的体力值。
float Delta = StaminaDrainRate * DeltaTime;
switch (CurrentStatus) {
case EStatus::ES_Normal:
{
float Tmp = Stamina + Delta;
if (Tmp < MaxStamina) {
Stamina = Tmp;
}
else {
Stamina = MaxStamina;
IsExhausted = false;
}
break;
}
case EStatus::ES_Sprint:
{
float Tmp = Stamina - Delta;
if (Tmp > 0) {
Stamina = Tmp;
}
else {
Stamina = 0;
IsExhausted = true;
SetStatus(EStatus::ES_Normal);
}
break;
}
}
- SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
设置键盘输入,我们加速是要按键的,所以将左shift与人物加速要绑定起来。
打开UE4编辑界面,点击Edit,点击项目设置,
点击Input,按照下图设置
添加下面的内容,将按键与角色冲刺绑定起来。
PlayerInputComponent->BindAction("Sprint", IE_Pressed, this, &ARole::BeginSprint);
PlayerInputComponent->BindAction("Sprint", IE_Released, this, &ARole::EndSprint);
- SufferDamage(float Damage)
先预计算一个生命值并将他约束在0 到 MaxHealth 之间。如果声明值小于等于零,调用死亡函数。
float Tmp = Health - Damage;
Tmp = FMath::Clamp(Tmp, 0.f, MaxHealth); // 约束到 0 - max 之间
Health = Tmp;
if (Health <= 0) {
Die();
}
死亡函数暂时没有做什么功能。
void ARole::Die()
{
}
- Pickup(EPickupType Type, uint32 Count)
拾取金币函数实现
根据拾取的类型增加金币数量。
switch (Type) {
case PT_Coin:
Coins += Count;
break;
default:
break;
}
- SetStatus(EStatus Status)
设置人物状态
普通状态就让他的奔跑速度为普通的奔跑速度,冲刺状态就设置速度为冲刺速度。
CurrentStatus = Status;
switch (CurrentStatus) {
case EStatus::ES_Normal:
GetCharacterMovement()->MaxWalkSpeed = RunSpeed;
break;
case EStatus::ES_Sprint:
GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
break;
default:
break;
}
爆炸类设置
.h文件
- 增加储存爆炸伤害的变量
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Damage;
.cpp文件
-
构造函数 增加
Damage = 10;
-
OnOverlapBegin
增加,如果与爆炸物碰撞的是角色,那么就要调用角色的伤害函数。
Cast为类型转换,转换成功返回地址,失败返回空指针。
if (OtherActor) {
ARole* role = Cast<ARole>(OtherActor);
if (role) {
role->SufferDamage(Damage);
}
}
拾取类设置
.cpp文件
- OnOverlapBegin
重叠之后让角色的金币数+1,这里可以拓展,设置我们增加的金币数,后期可以增加食物加血之类的……
if (OtherActor) {
ARole* role = Cast<ARole>(OtherActor);
if (role) {
role->Pickup(PT_Coin, 1);
}
}
接下来就是将这些反应和我们的HUD结合起来了。
WB_Coin设置
点击我们显示硬币数的文本控件,
在细节面板中,找到内容,创建绑定:
蓝图这么画:
整体思路就是:创建一个角色变量RefRole, 开始的时候判断这个变量是否储存了值,如果没有,那么就通过获取玩家操控的pawn来类型转换为Role类并且赋值给RefRole变量,转换失败就按照默认的来。
转换成功之后,现在已经拿到了我们当前控制的角色,那么通过获取角色的硬币数传值给我们的文本。
WB_Health设置
点击在细节面板中绑定进度条的值
蓝图这么画:
思路和上面一样,注意一下进度计算就好了。
WB_Stamina设置
点击细节面板中绑定进度条的值
蓝图这么画:
然后我们最后再添加一个细节,就是恢复的时候是灰色的,还有体力的时候是黄色的。
在这个板块创建新绑定:
蓝图这么画:
前面一大推和之前一样,就是确保我们的角色获取到了,主要是后面这一段,通过判断体力值是否耗尽来选择我们要体现出来的颜色。
设置人物运动动画
先将我们之前设置的一维运动动画修改一下:
添加人物在什么速度应该是什么样的状态的动画:
动画蓝图添加如下:
完工!
以上是关于UE4 C++角色与道具技能的互动(下)的主要内容,如果未能解决你的问题,请参考以下文章
基于C++代码的UE4学习—— 自定义代理结合Timer实现道具的消失与重生