UE4接口的使用及对象回收机制

自己现在在做的demo中,用到了大量的UObject对象,战斗的过程中会频繁的new出这些对象,无疑会消耗很大的cpu,为了减少和现有架构的耦合性,本想用继承的方式写个基类,发现ue中不能同时继承两个UObject。根据answerhub里的提示,就是用接口来做。

接口的弊端是里面的成员不能用UPROPERTY宏标记给蓝图识别,不过可以在子类中写个方法来“曲线救国”

这个回收机制的相关类

1、ObjInter这个是给要回收对象继承的接口

ObjInter.h

#include "ObjInter.generated.h"

class UObjMgr;

UINTERFACE()
class UObjInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};

class IObjInterface
{
GENERATED_IINTERFACE_BODY()
public:
IObjInterface();

virtual void Reset() = 0; //抽象接口,要求子类必须重写
virtual void SetObj(UObject* _obj);
virtual void Recycle();

private:
UObjMgr* mObjMgr; //回收中心,类似cocos里Node里的一系列mgr
UObject* mOwnObj; //宿主对象
};


ObjInter.cpp

#include "MySlate.h"
#include "ObjInter.h"

#include "./ObjMgr.h"

UObjInterface::UObjInterface(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
UE_LOG(ObjLogger, Warning, TEXT("--- UObjInterface::UObjInterface 111111"));
}


IObjInterface::IObjInterface()
: mOwnObj(nullptr)
{
UE_LOG(ObjLogger, Warning, TEXT("--- IObjInterface::IObjInterface"));
}

void IObjInterface::SetObj(UObject* _obj)
{
UE_LOG(ObjLogger, Warning, TEXT("--- IObjInterface::SetObj, construct - %s"), *_obj->GetClass()->GetName());
mObjMgr = UObjMgr::GetInstance();
mOwnObj = _obj;
Reset();
}
void IObjInterface::Recycle()
{
UE_LOG(ObjLogger, Warning, TEXT("--- IObjInterface::Recycle - %s"), *mOwnObj->GetClass()->GetName());
Reset();
mObjMgr->Recycle(mOwnObj);
}


2、ObjMgr是回收中心,里面有个回收池

回收池以类名为key,ue中的反射机制可以获取UObject具体的类名,value为对象数组 
ObjMgr.h

UCLASS()
class UObjMgr : public UObject, public USingleton<UObjMgr>
{
GENERATED_BODY()

public:
UObjMgr();
virtual ~UObjMgr();
virtual void BeginDestroy() override;

public:
template<typename TRetType>
TRetType* GetObj(UClass* _cls); //根据模板获取对象

void Recycle(UObject* _obj);
auto& GetObjMap() { return mObjMap; }

public:
//蓝图对象类设置
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<AMyChar> mCharCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<AMyBullet> mBulletCls;

//--------- pk Begin -----
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UFightData> mFightDataCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UPkProcess> mPkProcessCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UPkMsg> mPkMsgCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UParam> mPkParamCls;
//--------- pk End -----

//--------- filter Begin -----
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UCircleFilter> mCircleFltCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<ULockFilter> mLockFltCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<URectFilter> mRectFltCls;
//--------- filter End -----


//--------- skill Begin -----
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UCoolDown> mCoolDownCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<USkillFunction> mSkillFuncCls;
//--------- skill End -----

//--------- buff Begin -----
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UAppendBuff> mAppBuffCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UCommonBuff> mComBuffCls;
//--------- buff End -----

//--------- function Begin -----
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UAddBuff> mAddBuffCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UAttack> mAttackCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<UAttackPhy> mAttackPhyCls;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UObjMgr")
TSubclassOf<USuckup> mSuckupCls;
//--------- function End -----

private:
TMap<FString, TArray<UObject*>> mObjMap; //对象回收池
};

#define GetObjMgr() UObjMgr::GetInstance()

(ps:一系列的TSubclassOf是为了实现蓝图对象,如果某些类派生了某些蓝图类,在初始化时指定该蓝图类,即可new出蓝图实例对象)

ObjMgr.cpp

UObjMgr::UObjMgr() : Super()
{
//default cpp class
mFightDataCls = UFightData::StaticClass();
mPkProcessCls = UPkProcess::StaticClass();
mPkMsgCls = UPkMsg::StaticClass();
mPkParamCls = UParam::StaticClass();

mCircleFltCls = UCircleFilter::StaticClass();
mLockFltCls = ULockFilter::StaticClass();
mRectFltCls = URectFilter::StaticClass();

mCoolDownCls = UCoolDown::StaticClass();
mSkillFuncCls = USkillFunction::StaticClass();

mAppBuffCls = UAppendBuff::StaticClass();
mComBuffCls = UCommonBuff::StaticClass();

mAddBuffCls = UAddBuff::StaticClass();
mAttackCls = UAttack::StaticClass();
mAttackPhyCls = UAttackPhy::StaticClass();
mSuckupCls = USuckup::StaticClass();
}

UObjMgr::~UObjMgr()
{
UE_LOG(ObjLogger, Warning, TEXT("--- UObjMgr::~UObjMgr"));
}

void UObjMgr::BeginDestroy()
{
for (auto Iter = mObjMap.CreateConstIterator(); Iter; ++Iter)
{
for (UObject* obj : Iter->Value)
{
obj->RemoveFromRoot();
obj->ConditionalBeginDestroy();
}
}
mObjMap.Empty();

UE_LOG(ObjLogger, Warning, TEXT("--- UObjMgr::BeginDestroy"));
Super::BeginDestroy();
}

//获取回收池中的对象,不够了则new出来
template<typename TRetType>
TRetType* UObjMgr::GetObj(UClass* _cls)
{
TArray<UObject*>* findObjVec = mObjMap.Find(_cls->GetName());
if (findObjVec != nullptr)
{
if (findObjVec->Num() > 0)
{
UObject* obj = findObjVec->Pop();
return Cast<TRetType>(obj);
}
}

TRetType* ret = NewObject<TRetType>(TRetType::StaticClass());
UObject* obj = (UObject*)ret;
obj->AddToRoot();
return ret;
}

//对象回收逻辑
void UObjMgr::Recycle(UObject* _obj)
{
FString clsName = _obj->GetClass()->GetName();
TArray<UObject*>* objVec = mObjMap.Find(clsName);
if (objVec != nullptr)
{
objVec->Push(_obj);
}
else
{
TArray<UObject*> tmp;
tmp.Add(_obj);
mObjMap.Add(clsName, tmp);
}
}

(ps:在这基础上可以继续扩展,使用一些算法定时清除对象,LRU神马的) 

3、继承接口,使用回收

FightData.h

#include "FightData.generated.h"

UCLASS()
class UFightData : public UObject, public IObjInterface
{
GENERATED_BODY()

public:
UFightData();
virtual ~UFightData();
virtual void BeginDestroy() override;
virtual void Reset() override;
virtual void Recycle() override;

UFightData* Clone();
void Copy(UFightData* _fightData);


float GetAttackPhy() const { return mAttackPhy; }
float GetLv() const { return mLv; }

public:
//原始属性
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UCharData")
float mAttackPhy; //物理攻击

public:
//成长相关
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UCharData")
int mLv; //等级

public:
};

FightData.cpp

#include "../../Object/ObjMgr.h"

UFightData::UFightData() : Super(), IObjInterface()
{
IObjInterface::SetObj(this); //设置宿主为自身
}

UFightData::~UFightData()
{
UE_LOG(SkillLogger, Warning, TEXT("--- UFightData::~UFightData"));
}

void UFightData::BeginDestroy()
{
UE_LOG(SkillLogger, Warning, TEXT("--- UFightData::BeginDestroy"));
Super::BeginDestroy();
}

void UFightData::Reset()
{
mAttackPhy = 0.f;
mLv = 1;
}

void UFightData::Recycle()
{
IObjInterface::Recycle();
}

UFightData* UFightData::Clone()
{ //从回收池中拿对象
UFightData* data = GetObjMgr()->GetObj<UFightData>(GetObjMgr()->mFightDataCls);
data->Copy(this);
return data;
}

void UFightData::Copy(UFightData* _fightData)
{
this->mAttackPhy = _fightData->mAttackPhy;
this->mLv = _fightData->mLv;
}


用接口实现Broadcast,适用于多个类继承统一接口,处理不同实例对象
class IBehavInterface
{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintNativeEvent)
void OnInputTap(const FVector& _pos);
};

必须用 UFUNCTION宏 声明为 BlueprintNativeEvent,所有继承这个接口的类都必须实现OnInputTap()方法


.h

class AMyChar : public ACharacter, public IBehavInterface
{
GENERATED_BODY()
public:
//重写接口方法,注意_Implementation
virtual void OnInputTap_Implementation(const FVector& _pos) override;
};

.cpp

void AMyChar::OnInputTap_Implementation(const FVector& _pos)
{
UE_LOG(SkillLogger, Warning, TEXT("--- AMyChar::OnInputTap_Implementation, targetId:%d, pos:%f,%f,%f"), GetUuid(), _pos.X, _pos.Y, _pos.Z);
}

调用接口
AMyChar* tarChar = Cast<AMyChar>(HitActor);
//调用前一定要检查一下该类是否实现了这个接口
if ( tarChar && tarChar->GetClass()->ImplementsInterface(UBehavInterface::StaticClass()) )
{
//第一个参数目的对象,第二个参数才是接口方法的参数
IBehavInterface::Execute_OnInputTap(tarChar, WorldPosition);
}
(ps: 一定要先检查是否实现了接口)
结果:


**小坑

1、不能直接调 BlueprintNativeEvent 声明的方法
UFUNCTION(BlueprintNativeEvent)
void OnInputTap(const FVector& _pos);

如:

xxx->OnInputTap(xx);

这种方法必须用这种方式调用

IBehavInterface::Execute_OnInputTap(tarChar, WorldPosition);



接口中的方法暴露给蓝图使用

必须声明为为 CannotImplementInterfaceInBlueprint,且不能用 BlueprintNativeEvent 声明的方法,
被声明为  BlueprintCallable  的方法必须是  virtual  方法
UINTERFACE(meta = (CannotImplementInterfaceInBlueprint))
class UBTNodeInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};

class IBTNodeInterface
{
GENERATED_IINTERFACE_BODY()
public:
IBTNodeInterface();

UFUNCTION(BlueprintCallable, Category = "IBTNodeInterface")
virtual int32 GetCharUUid();
};
a
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蝶泳奈何桥.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值