接口不能够被实例化,不能够在内部书写函数的逻辑和设置属性,只能够被继承使用。它能够让不同的类实现有相同的函数,继承接口的类必须实现接口的函数。
并且,我们可以在不同的类里面的函数实现也不同,比如A类描边是红色,B类的描边是绿色的,描边的调用都使用一个函数调用。
创建接口类
右键添加c++类,在常见类中找到Unreal接口,创建一个Enemy的接口类
cpp
// 版权归暮志未晚所有。
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "EnemyInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UEnemyInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class AURA_API IEnemyInterface
{
GENERATED_BODY()
// 向此类添加接口函数(虚函数),继承此接口的类都将需要继承并实现这些函数。
public:
virtual void HighlightActor() = 0; //高亮
virtual void UnHighlightActor() = 0; //取消高亮
};
在接口类EnemyInterface.h中,我们增加了两个虚函数,继承此接口的类需要实现高亮函数和取消高亮函数
类实现接口
接着让敌人类继承接口
如果你只继承,不实现相关函数,会发现编译时提示报错。
cpp
// 版权归暮志未晚所有。
#pragma once
#include "CoreMinimal.h"
#include "Character/CharacterBase.h"
#include "Interaction/EnemyInterface.h"
#include "Enemy.generated.h"
/**
*
*/
UCLASS()
class AURA_API AEnemy : public ACharacterBase, public IEnemyInterface
{
GENERATED_BODY()
public:
virtual void HighlightActor() override; //高亮
virtual void UnHighlightActor() override; //取消高亮
UPROPERTY(BlueprintReadOnly) //蓝图可读
bool bHighlighted = false; //是否高亮
};
我们需要在类里面继承函数,并在cpp里面定义相关逻辑。这里先定义了一个变量,用来获取当前角色是否需要高亮
cpp
// 版权归暮志未晚所有。
#include "Character/Enemy.h"
void AEnemy::HighlightActor()
{
bHighlighted = true;
}
void AEnemy::UnHighlightActor()
{
bHighlighted = false;
}
在cpp中,高亮将此值设置为true,取消高亮设置为false。
通过鼠标拾取设置敌人是否高亮
设置敌人高亮,我们可以通过在帧更新里面,通过获取鼠标拾取到的对象,对对象进行判断是否设置高亮。
在playercontroller中,我们覆盖帧更新回调,鼠标位置追踪拾取函数,以及两个变量去记录当前鼠标拾取到的内容。
cpp
//帧更新
void APlayerControllerBase::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
CursorTrace();
}
帧更新里面,只需要增加对鼠标帧更新的调用。
cpp
//鼠标位置追踪
void APlayerControllerBase::CursorTrace()
{
FHitResult CursorHit;
GetHitResultUnderCursor(ECC_Visibility, false, CursorHit); //获取可视的鼠标命中结果
if(!CursorHit.bBlockingHit) return; //如果未命中直接返回
LastActor = ThisActor;
ThisActor = Cast<IEnemyInterface>(CursorHit.GetActor());
/**
* 射线拾取后,会出现的几种情况
* 1. LastActor is null ThisActor is null 不需要任何操作
* 2. LastActor is null ThisActor is valid 高亮ThisActor
* 3. LastActor is valid ThisActor is null 取消高亮LastActor
* 4. LastActor is valid ThisActor is valid LastActor != ThisActor 取消高亮LastActor 高亮ThisActor
* 5. LastActor is valid ThisActor is valid LastActor == ThisActor 不需要任何操作
*/
if(LastActor == nullptr)
{
if(ThisActor != nullptr)
{
//case 2
ThisActor->HighlightActor();
} // else case 1
}
else
{
if(ThisActor == nullptr)
{
//case 3
LastActor->UnHighlightActor();
}
else
{
if(LastActor != ThisActor)
{
//case 4
LastActor->UnHighlightActor();
ThisActor->HighlightActor();
} //else case 5
}
}
}
而鼠标位置追踪拾取函数,首先就是先通过函数获取可视的内容,对拾取的内容判断是否继承至IEnemyInterface,然后根据情况进行高亮和非高亮的设置。
在蓝图中根据变量设置可视效果
首先,我需要先在debug模式下测试设置高亮是否有效果,有了变量bHighlighted后,我们可以在敌人的蓝图中获取它的变量,如果为true,我们将在敌人身上添加一个球代表它需要高亮。
在敌人的事件图表中,帧更新中,增加对Hightlighted的判断,如果为true,则在敌人位置创建一个球
为了能够被鼠标拾取到,我们需要将敌人模型的检测相应可视设置为阻挡。
运行点击~ 输入show Collision将会显示所有的碰撞体,再输入一次,将隐藏掉所有没必要的碰撞体显示。
接下来放置几个敌人进行测试,会发现鼠标悬浮在谁身上,就会生成一个球。
使用后处理实现对模型的描边
在ue里面实现描边有多种方法,大家经常使用的方法就是使用后处理描边。
首先在场景内添加一个后处理体积
将后处理体积影响范围设置为无限
然后在后期处理材质这里,将材质添加进来
后处理材质逻辑大概如此,这里不再展开将了,原理就是通过卷积的方式,采样进行比对,分析出描边区域,然后根据设置的颜色显示。需要用到自定义深度功能。
在项目设置里面开启基于模版的自定义深度
在材质中,如果自定义深度为250,那么它的模型周围会出现描边效果,那么,最后一步,我们将需要描边的模型的自定义深度开启,并设置为250,则实现当前效果。
在前面,我们在敌人的基类里面实现了设置高亮以及取消高亮,只要我们在代码中实现,对自定义深度通道修改以及自定义深度模板值的修改,就可以实现当前的高亮效果。
cpp
// 版权归暮志未晚所有。
#include "Character\EnemyBase.h"
#include "Aura/Aura.h"
AEnemyBase::AEnemyBase()
{
GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); //设置可视为阻挡
}
void AEnemyBase::HighlightActor()
{
GetMesh()->SetRenderCustomDepth(true);
GetMesh()->SetCustomDepthStencilValue(CUSTOM_DEPTH_RED);
Weapon->SetRenderCustomDepth(true);
Weapon->SetCustomDepthStencilValue(CUSTOM_DEPTH_RED);
}
void AEnemyBase::UnHighlightActor()
{
GetMesh()->SetRenderCustomDepth(false);
Weapon->SetRenderCustomDepth(false);
}
设置角色的模型和武器的模型的自定义深度和自定义深度模版值,为了方便以后迭代修改,红色的值直接定义在了CUSTOM_DEPTH_RED宏中。
并且,为了爆炸角色模型能够被鼠标拾取到,我们直接在构造时直接修改了设置可见性的拾取。