斯坦福CS193U-虚幻4C++课程学习笔记(13)

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中被绑定,需要使用相同的变量名称

否则将会:

Debug指令

对函数使用UFUNCTION(Exec)宏标记可以让函数能够在游戏中的Console调用

仅在如下几个地方中可以声明:

  • Player Controller

  • 玩家操控的Character

  • Game Mode

  • Cheat Manager

Tips

  • 使用UPROPERTY()将变量暴露在UE的反射系统中,即可利用引用计数,能够避免使用野指针

  • UMG Data Binding特别费性能,如非必须,尽量避免使用

  • GetTimeSeconds函数返回本地时间,多人游戏时无法返回正确的游戏时间

  • 应使用GameState->GetServerWorldTimeSeconds

  • 由于需要支持多语言,所以一定要注意使用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

  • 实现击杀全部怪物和回满玩家血量的作弊指令

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值