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++角色与道具技能的互动(下)的主要内容,如果未能解决你的问题,请参考以下文章

UE4 C++角色拾取替换武器(上)

基于C++代码的UE4学习—— 自定义代理结合Timer实现道具的消失与重生

UE4 C++角色拾取替换武器(下)

UE4 C++ Slate 初探: Editor UI 与 Game UI

UE4 C++第三人称人物创建的基本代码(上)

UE4在C++中使用OnComponentBeginOverlap之类的时间