斯坦福UE4 + C++课程学习记录 20:位移技能

目录

1. 创建粒子类

2. 实现传送

3. 动画设置


        这节将会完成课程设置的第二次作业之一 —— 实现角色的粒子位移技能,即发射出一个特殊的粒子,经过一定时间后,该粒子会爆炸并将角色传送到爆炸位置。

1. 创建粒子类

        考虑到后面制作的粒子都需要实现爆炸效果,所以在SurProjectileBase中添加实现爆炸的函数和OnActorHit事件函数,爆炸函数仅包括最基本的爆炸后销毁自身的功能,方便子类可以根据自己的需求来进行重写。绑定事件的方法已经在第6、12节的爆炸桶内容出现过,重写函数的内容已经在第7节打开宝箱的文章中出现过。

// SurProjectileBase.h

UPROPERTY(EditDefaultsOnly, Category = "Effects")
UParticleSystem* ImpactVFX;//VFX指Visual effects, 即视觉特效,负责爆炸时的特效

UFUNCTION()
virtual void OnActorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void Explode(); // 爆炸函数


// SurProjectileBase.cpp

void ASurProjectileBase::OnActorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	Explode();
}

// BlueprintNativeEvent需要加上后缀_Implementation
void ASurProjectileBase::Explode_Implementation()
{
	// IsPendingKill确保对象有效,防止重复destroy
	if (ensure(IsPendingKill()))
	{
		// 触发爆炸时的特效,特效样式在UE中设置ImpactVFX变量
		UGameplayStatics::SpawnEmitterAtLocation(this, ImpactVFX, GetActorLocation(), GetActorRotation());

		Destroy();
	}
}

        由于这个技能需要实现额外的传送角色代码,因此我们要在UE中创建一个新的粒子类SurDashProjectile,在创建时选择“显示所有类”,并通过搜索选择,从上一节创建的基类SurProjectileBase派生出来。

        课程中在DashProjectile中设置两个时间,经过DetonateDelay后生成爆炸特效,然后再经过TeleportDelay后传送角色。将控制爆炸的TimerHandle_DelayedDetonate声明为类的保护成员,当粒子提前遇到障碍物爆炸调用Explode函数时,我们可以手动清除这个Timer,从而防止触发两次。相对的,控制传送延迟的Timer不涉及这个问题,因此定义为局部变量即可:

#pragma once

#include "CoreMinimal.h"
#include "SurProjectileBase.h"
#include "SurDashProjectile.generated.h"


UCLASS()
class SURKEAUE_API ASurDashProjectile : public ASurProjectileBase
{
	GENERATED_BODY()

public:

	ASurDashProjectile();

protected:
	
	UPROPERTY(EditDefaultsOnly, Category = "Teleport")
	float TeleportDelay; // 传送延迟

	UPROPERTY(EditDefaultsOnly, Category = "Teleport")
	float DetonateDelay; // 爆炸延迟

	// hit后清除计时器
	FTimerHandle TimerHandle_DelayedDetonate;

	virtual void Explode_Implementation() override;

	void TeleportInstigator();

	virtual void BeginPlay() override;

};

2. 实现传送

        实现角色的传送,可以直接使用UE的TeleportTo函数接口。这部分需要注意的是,一进入Explode就要清除控制爆炸的Timer,防止提前触发Hit事件爆炸后、原有的计时器结束再次触发。

#include "SurDashProjectile.h"
#include "Kismet/GameplayStatics.h"
#include "Particles/ParticleSystemComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"


ASurDashProjectile::ASurDashProjectile()
{
	TeleportDelay = 0.2f;
	DetonateDelay = 0.2f;

	MoveComp->InitialSpeed = 6000.f;
}

void ASurDashProjectile::BeginPlay()
{
	Super::BeginPlay();

	// 到爆炸时间后,触发Explode()
	GetWorldTimerManager().SetTimer(TimerHandle_DelayedDetonate, this, &ASurDashProjectile::Explode, DetonateDelay);
}

void ASurDashProjectile::Explode_Implementation()
{
	// 可能有碰到障碍物提前爆炸的情况,因此要清除Timer防止被调用两次
	GetWorldTimerManager().ClearTimer(TimerHandle_DelayedDetonate);
	// 爆炸特效
	UGameplayStatics::SpawnEmitterAtLocation(this, ImpactVFX, GetActorLocation(), GetActorRotation());

	// 粒子爆炸后关闭系统、停止移动、停止碰撞
	EffectComp->DeactivateSystem();
	MoveComp->StopMovementImmediately();
	SetActorEnableCollision(false);

	// 到传送时间后,触发传送
	FTimerHandle TimerHandle_DelayedTeleport;
	GetWorldTimerManager().SetTimer(TimerHandle_DelayedTeleport, this, &ASurDashProjectile::TeleportInstigator, TeleportDelay);

	// 不调用base中的Explode中的destroy自身,因为传送时间计时器需要一点时间
	//Super::Explode_Implementation();
}

void ASurDashProjectile::TeleportInstigator()
{
	AActor* ActorToTeleport = GetInstigator();
	if (ensure(ActorToTeleport))
	{
		// 传送时保持角色原始Rotation
		ActorToTeleport->TeleportTo(GetActorLocation(), ActorToTeleport->GetActorRotation(), false, false);
	}
	// 之前没有调用,现在销毁
	Destroy();
}

        接下来就是常规的绑定按键操作,在UE中创建蓝图类,然后设置发射的粒子为该蓝图类,这已经在之前的内容出现过很多次,故不再赘述。


3. 动画设置

        最后,在创建的蓝图类中设置粒子的动画。一共需要设置两个动画:一是发射出去粒子的样子,对应ProjectileBase中的Effect Comp;二是爆炸时的动画,对应刚刚声明的ImpactVFX。

        我设置的特效分别为P_Gideon_Burden_Projectile和P_Gideon_Burden_DoT2_End,注意ImpactVFX要设置名字带有End或Destroy等会自动结束的动画,否则爆炸后的粒子会一直停留在世界中,大家可以根据喜好任意选择粒子特效。

图20-1 运行测试

        在C++中我们将两个延迟使用UPROPERTY暴露到了UE中,所以此时可以很方便地调节数据。我将爆炸延迟设置为1,传送延迟设置为0.2,即正常情况下粒子飞行1s后再经过0.2s,角色会传送到粒子最终位置。但如果粒子遇到障碍物,则代码中清除Timer的语句就会发挥作用,在0.2s后直接传送角色,效果如下:

图20-2 提前Explode

        最后我想说的是,课程的作业部分由于没有足够的指引,复现的难度确实比课程内容更大,但同时也给了我很多迫使自己摸索解决问题的机会。所以也十分建议大家可以先自行探索尝试实现作业内容,这对加深对UE的理解十分有用。

猜你喜欢

转载自blog.csdn.net/surkea/article/details/127487971