在这一篇里,我们将制作一个范围魔法,释放魔法时,我们将在鼠标拾取位置绘制一个魔法光圈,用于显示技能释放时攻击的范围,然后再次点击可以释放技能。
创建贴花类
魔法范围标识的光圈,我们采用贴花实现,首先我们创建一个类,用于作为这种类型的贴花的基类,贴花是组件对象,我们需要创建一个基于Actor的类,用于挂载贴花组件。
命名
在类里增加一个贴花组件
UCLASS()
class RPG_API AMagicCircle : public AActor
{
GENERATED_BODY()
public:
AMagicCircle();
virtual void Tick(float DeltaTime) override;
//魔法光环法阵贴花
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
TObjectPtr<UDecalComponent> MagicCircleDecal;
protected:
virtual void BeginPlay() override;
};
在构造函数里,初始化贴花,并附加到根组件上
AMagicCircle::AMagicCircle()
{
PrimaryActorTick.bCanEverTick = true;
MagicCircleDecal = CreateDefaultSubobject<UDecalComponent>("MagicCircleDecal");
MagicCircleDecal->SetupAttachment(GetRootComponent());
}
编译代码,创建一个基于贴花类的蓝图
在贴花组件上设置贴花材质
我们可以设置贴花组件范围缩放,来设置贴花的显示范围,注意,贴花会基于x轴的方向贴到表面,所以,如果想让贴花贴到地面,我们需要x轴垂直到地面。
将其放置到场景内查看效果。
实现贴花的显示隐藏以及跟随鼠标移动
接下来,我们要实现贴花的显示隐藏,由于贴花需要跟随鼠标移动,鼠标移动拾取是在PlayerController里实现的,我们将其实例放到PlayerController类里。
在PlayerController里,我们增加两个属性,用于设置贴花的类,并在需要显示时,设置保存贴花实例的属性,并增加一个更新贴花位置的函数,在帧回调里调用。
//创建奥数光圈使用的类
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AMagicCircle> MagicCircleClass;
//存储魔法光圈的属性,不需要暴露给蓝图
UPROPERTY()
TObjectPtr<AMagicCircle> MagicCircle;
void UpdateMagicCircleLocation() const; //每一帧调用,更新魔法光圈的位置
增加两个public函数,用于玩家角色类调用显示和隐藏贴花
//显示魔法光圈 并设置光圈贴花材质
UFUNCTION(BlueprintCallable)
void ShowMagicCircle(UMaterialInterface* DecalMaterial);
//隐藏魔法光圈
UFUNCTION(BlueprintCallable)
void HideMagicCircle() const;
在显示贴花时,我们将在实例不存在的情况下创建一个,并修改它的材质。
在隐藏时,我们将贴花销毁掉。
void ARPGPlayerController::ShowMagicCircle(UMaterialInterface* DecalMaterial)
{
if(!IsValid(MagicCircle)) MagicCircle = GetWorld()->SpawnActor<AMagicCircle>(MagicCircleClass);
//设置贴花材质
if(DecalMaterial != nullptr)
{
MagicCircle->MagicCircleDecal->SetMaterial(0, DecalMaterial);
}
}
void ARPGPlayerController::HideMagicCircle() const
{
if(IsValid(MagicCircle)) MagicCircle->Destroy();
}
接着就是更新贴图的位置,如果贴花实例存在,我们将鼠标拾取的位置设置给贴花
void ARPGPlayerController::UpdateMagicCircleLocation() const
{
if(IsValid(MagicCircle))
{
MagicCircle->SetActorLocation(CursorHit.ImpactPoint);
}
}
并在每一帧更新里去调用更新贴花位置
接下来,我们在PlayerController里设置贴花的类
在playerController里编写一些测试节点,测试贴花是否能够正确显示隐藏
接着运行测试效果
我们想让贴花能够自动旋转,先在贴花里,将组件设置为蓝图可视
然后在贴花类里的帧回调设置基于x轴旋转,每一帧修改,贴花会自己旋转起来。
这个贴花的显示隐藏不应该是PlayerController的功能,所以,我们将在玩家角色类增加对应的函数。为了方便后续调用,我们将其作为角色接口的函数,后面只需要通过接口调用即可。
我们在player interface里增加两个函数,用于显示和隐藏贴花
//显示魔法光圈,并设置魔法光圈的贴花材质
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void ShowMagicCircle(UMaterialInterface* DecalMaterial = nullptr);
//隐藏魔法光圈
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void HideMagicCircle();
玩家角色类继承PlayerInterface接口,我们直接覆写
virtual void ShowMagicCircle_Implementation(UMaterialInterface* DecalMaterial) override;
virtual void HideMagicCircle_Implementation() override;
并实现对应的函数,函数内获取到PlayerController并调用对应的函数
void ARPGHero::ShowMagicCircle_Implementation(UMaterialInterface* DecalMaterial)
{
if(ARPGPlayerController* RPGPlayerController = Cast<ARPGPlayerController>(GetController()))
{
RPGPlayerController->ShowMagicCircle(DecalMaterial);
}
}
void ARPGHero::HideMagicCircle_Implementation()
{
if(ARPGPlayerController* RPGPlayerController = Cast<ARPGPlayerController>(GetController()))
{
RPGPlayerController->HideMagicCircle();
}
}
将PlayerController里的测试节点删除,在玩家角色蓝图里增加使用接口函数调用,并修改一个贴花测试修改材质的函数。
我们设置一个新的贴花,并将颜色修改掉,运行查看效果即可。