跳过正文

CoopGame04-伤与挂

··1389 字·3 分钟
coopgame - 这篇文章属于一个选集。
§ 4: 本文

CoopGame04-伤与挂
#

跟随B站up主“技术宅阿棍儿”的教程制作的笔记。教程连接 ###0.简介 解决的问题

Actor对伤害做出反应,管理生命值玩家的死亡

知识点

自定义组件自定义事件死亡动画的使用材质

挑战

会爆炸的汽油桶

###1.创建生命值组件

1.创建继承ActorComponent的C++类SHealthComponent。文件目录可以加一层Component文件夹。

###2.生命值组件的使用

1.删除Tick相关代码,使用组件处理伤害事件

SHealthComponent.h

1
2
3
4
5
6
7
8
9
    //当前生命值
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="HealthComponent")
	float Health;
	//默认最大生命值
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="HealthComponent")
	float DefaultHealth;
	//受任何伤害的函数
	UFUNCTION()
	void HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType,class AController* InstigatedBy, AActor* DamageCauser);

SHealthComponent.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
USHealthComponent::USHealthComponent()
{
	DefaultHealth =100;
}

void USHealthComponent::BeginPlay()
{
	Super::BeginPlay();
	AActor* MyOwner = GetOwner();
	//当Actor收到伤害时调用OnTakeAnyDamage绑定的HandleTakeAnyDamage函数
	if (MyOwner) MyOwner->OnTakeAnyDamage.AddDynamic(this,&USHealthComponent::HandleTakeAnyDamage);
	//当前生命值等于默认最大生命值100
	Health = DefaultHealth;

}

void USHealthComponent::HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType,
	AController* InstigatedBy, AActor* DamageCauser)
{
	if (Damage <= 0)return;
	//限定受伤后的生命值在0-默认最大生命值之间,包括这两个数
	Health = FMath::Clamp(Health-Damage,0.0f,DefaultHealth);
	//打印受伤后的生命值
	UE_LOG(LogTemp,Log,TEXT("Health Changed:%s"),*FString::SanitizeFloat(Health));
}

###3.创建自定义事件。

1.定义六个参数的自定义事件宏,定义生命值改变的自定义事件.

SHealthComponent.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/*
 *DYNAMIC:可以在蓝图里被序列化后定义和绑定操作。
 *MULTICAST:可实现一个事件类型多函数广播(事件类型必须声明为蓝图类型)
 *XXXParams:(使用DYNAMIC时)参数个数,宏定义参数里一个参数类型对应一个参数名字。
 */
//动态多播代理,主要是可用于蓝图的委托绑定.可以作为变量给蓝图绑定调用,委托代理这块建议单独学习。
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, OwningHealthComp, float,
                                             Health, float, HealthDelta, const class UDamageType*, DamageType,
                                             class AController*, InstigatedBy, AActor*, DamageCauser);

class COOPGAMEPLUS_API USHealthComponent : public UActorComponent
{
	GENERATED_BODY()
    //...
	//声明动态代理对象,自定义事件——生命值改变事件(BlueprintAssignable仅能用于Multicast代理)
	UPROPERTY(BlueprintAssignable,Category="Events")
	FOnHealthChangedSignature OnHealthChanged;
};

SHealthComponent.cpp

1
2
3
4
5
6
7
void USHealthComponent::HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType,
	AController* InstigatedBy, AActor* DamageCauser)
{
    //...
	//执行多播调用
	OnHealthChanged.Broadcast(this,Health,Damage,DamageType,InstigatedBy,DamageCauser);
}

2.调用流程:组件受伤–>调用OnTakeAnyDamage事件绑定的函数HandleTakeAnyDamage(),函数下面执行多播调用Broadcast。

###4.角色死亡动画。

1.给角色类SCharacter添加上生命值组件。

SCharacter.h

1
2
3
4
5
6
7
8
9
    //添加创建的健生命值组件
	UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Components")
	class USHealthComponent* HealthComp;
	//生命值更新函数
	UFUNCTION()
	void OnHealthChanged(class USHealthComponent* OwningHealthComp,float Health,float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser );
	//角色是否死亡,这个布尔值可以用于在角色蓝图判断角色是否死亡。
	UPROPERTY(BlueprintReadOnly, Category = "Player")
	bool bDied;

SCharacter.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ASCharacter::ASCharacter()
{
	PrimaryActorTick.bCanEverTick = true;
    //...
	//创建生命值组件
	HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp"));
}

void ASCharacter::BeginPlay()
{
	Super::BeginPlay();
    //...
	//生命值组件中我们自定义的生命值改变的事件绑定调用角色身上的生命值更新函数OnHealthChanged()
    //受伤时会调用OnHealthChanged函数。
	HealthComp->OnHealthChanged.AddDynamic(this,&ASCharacter::OnHealthChanged);
}

void ASCharacter::OnHealthChanged(USHealthComponent* OwningHealthComp, float Health, float HealthDelta,
	const UDamageType* DamageType, AController* InstigatedBy, AActor* DamageCauser)
{
	if (Health<=0 && !bDied){
		//当生命值小于0,并且当前状态不是死亡时,设置为死亡状态
		bDied = true;
		//运动组件停止运动
		GetMovementComponent()->StopMovementImmediately();
		//移除胶囊体所有碰撞
		GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	}
}

2.设置角色的动画蓝图UE4ASP_HeroTPP_AnimBlueprint

1.拿到角色类中的bDied并提升为变量,以便动画蓝图判断角色死亡。

CoopGame04-伤与挂1.webp

2.动画图标中混合死亡动画序列,记得关闭死亡动画序列的循环。

CoopGame04-伤与挂2.webp

###5.创建战争机器风格的生命指示材质和控件

略 ###6.挑战:会爆炸的汽油桶 略

coopgame - 这篇文章属于一个选集。
§ 4: 本文