【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();
	}
}

找到.Build.cs文件,在PrivateDependencyModuleNames.AddRange中添加"UMG"模块,要不然编译器识别不了,无法通过编译。
在这里插入图片描述

然后以这个文件为父类创建蓝图,在蓝图细节面板中加入我们之前创建的界面:
在这里插入图片描述
打开主编辑界面,看到世界设置,在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设置

点击在这里插入图片描述细节面板中绑定进度条的值在这里插入图片描述

蓝图这么画:
在这里插入图片描述

然后我们最后再添加一个细节,就是恢复的时候是灰色的,还有体力的时候是黄色的。
在这个板块创建新绑定:
在这里插入图片描述

蓝图这么画:
在这里插入图片描述
前面一大推和之前一样,就是确保我们的角色获取到了,主要是后面这一段,通过判断体力值是否耗尽来选择我们要体现出来的颜色。

设置人物运动动画

先将我们之前设置的一维运动动画修改一下:
在这里插入图片描述
添加人物在什么速度应该是什么样的状态的动画:
在这里插入图片描述
动画蓝图添加如下:
在这里插入图片描述
完工!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值