UE C++中定义enum类
// 在任意.h文件中定义
UENUM(BlueprintType)
enum class EDemo : uint8
{
A UMETA(DisplayName = "A"),
B UMETA(DisplayName = "B"),
C UMETA(DisplayName = "C")
};
黑板中数据(注意C++中的枚举只能通过文本方式添加)!!!
UMG
NativeTick() - Tick函数
AddToViewport - C++中的该函数被调用后,随后会调用蓝图中UserWidget的Event Construct函数
Meta
BindWidget
声明该元数据需要在UMG蓝图中designer中被绑定,需要使用相同的变量名称
否则将会:
![](https://i-blog.csdnimg.cn/blog_migrate/b3a21e91101da909b5d170ae48098c6c.png)
Debug指令
对函数使用UFUNCTION(Exec)宏标记可以让函数能够在游戏中的Console调用
仅在如下几个地方中可以声明:
Player Controller
玩家操控的Character
Game Mode
Cheat Manager
Tips
使用UPROPERTY()将变量暴露在UE的反射系统中,即可利用引用计数,能够避免使用野指针
UMG Data Binding特别费性能,如非必须,尽量避免使用
GetTimeSeconds函数返回本地时间,多人游戏时无法返回正确的游戏时间
应使用GameState->GetServerWorldTimeSeconds
![](https://i-blog.csdnimg.cn/blog_migrate/ecfaa895564e3424644b360f4a4291b8.png)
由于需要支持多语言,所以一定要注意使用FText而不是FString
Ctrl+P - UE编辑器全局快捷搜东西
可以通过加锁的操作让Designer界面中的指定内容无法被选中
UE的BTService有大坑,按顺序生成死亡的怪物可能共用一个Service实例
需要手动在构造函数中声明bCreateNodeInstance = true才能阻止UE为了节省内存的复用
项目代码
GitHub: https://github.com/yufeige4/ActionRoguelike
使用代理重构了怪物脱战回血机制,解决了任务没执行完就开始移动的问题 // 参考源码BTTask_MoveTo结点
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnRecoverFinished);
UCLASS()
class ACTIONROGUELIKE_API UBTTask_RecoverHealth : public UBTTaskNode
{
GENERATED_BODY()
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
public:
UBTTask_RecoverHealth();
FOnRecoverFinished OnRecoverFinished;
protected:
EBTNodeResult::Type TaskState;
bool bStartTask;
UFUNCTION()
void FinishedRecover();
};
EBTNodeResult::Type UBTTask_RecoverHealth::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
if(!bStartTask)
{
auto AIC = Cast<AAIController>(OwnerComp.GetOwner());
if(AIC)
{
auto ControlledPawn = AIC->GetPawn();
if(ControlledPawn && ControlledPawn->Implements<UGAICharacterInterface>())
{
IGAICharacterInterface::Execute_Recover(ControlledPawn,this);
TaskState = EBTNodeResult::InProgress;
bStartTask = true;
}
}
}
return TaskState;
}
UBTTask_RecoverHealth::UBTTask_RecoverHealth()
{
bStartTask = false;
TaskState = EBTNodeResult::Succeeded;
OnRecoverFinished.AddDynamic(this,&UBTTask_RecoverHealth::FinishedRecover);
}
void UBTTask_RecoverHealth::FinishedRecover()
{
UE_LOG(LogTemp,Log,TEXT("Finish Recover!!!"));
bStartTask = false;
TaskState = EBTNodeResult::Succeeded;
}
修复Service检查怪物血量,多只怪物不重置CD问题 // 必须在构造函数中声明bCreateNodeInstance以阻止UE复用
跟踪窗口显示C++基类
UCLASS()
class ACTIONROGUELIKE_API UGUserWidget_World : public UUserWidget
{
GENERATED_BODY()
protected:
UPROPERTY(meta=(BindWidget))
USizeBox* ParentSizeBox;
UPROPERTY(EditAnywhere, Category = "UI")
FVector WorldDisplayOffset;
public:
UPROPERTY(BlueprintReadOnly, Category = "UI")
AActor* AttachedActor;
protected:
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
};
void UGUserWidget_World::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
Super::NativeTick(MyGeometry, InDeltaTime);
// 判断该Actor是否被回收或即将被回收
if(!IsValid(AttachedActor))
{
// 销毁自身实例
RemoveFromParent();
UE_LOG(LogTemp,Warning,TEXT("AttachedActor is destroyed, removing related UserWidget"));
return;
}
FVector2D ScreenPosition;
bool bProjectSuccess = UGameplayStatics::ProjectWorldToScreen(GetOwningPlayer(),AttachedActor->GetActorLocation() + WorldDisplayOffset,ScreenPosition);
if(bProjectSuccess)
{
float ViewportScale = UWidgetLayoutLibrary::GetViewportScale(this);
ScreenPosition /= ViewportScale;
if(ParentSizeBox)
{
ParentSizeBox->SetRenderTranslation(ScreenPosition);
}
}
}
创建玩家主UI界面
怪物血条UI,游戏积分UI,游戏全局信息UI
![](https://i-blog.csdnimg.cn/blog_migrate/13ff92693e6d2613dd8b599ad26adddf.png)
实现击杀全部怪物和回满玩家血量的作弊指令