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

EQS

EQS Testing Pawn

能够设置所需要查看的EQS生成点和效果,对于调试来说非常便利,且仅需拖动即可刷新

Generator

可以通过设置Projection Data将某些生成点映射到附近的NavMesh上

Path Exist Test

可以判断生成点是否有路径可以到达Context,开销大,需谨慎考虑

Game Mode

定义了玩家的类和其Controller的类

UCurveFloat

可以通过此类在蓝图中配置曲线

Tips

  • GetAllActorsOfClass函数性能开销很大,将遍历场景中所有的Actor

  • 使用TActorIterator遍历场景中的Actor效率高于GetAllActorsOfClass

for(TActorIterator<T> It(GetWorld()); It; ++It)
{
	//...
}
  • C++实现GameMode继承 GameModeBase

项目代码

GitHub: https://github.com/yufeige4/ActionRoguelike

  • 实现在玩家周围根据条件刷怪的逻辑

EQS判断与玩家距离是否够大和是否存在路径能够到达玩家

  • GameMode调用

// GGameModeBase.h
// ...
UCLASS()
class ACTIONROGUELIKE_API AGGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

public:
	AGGameModeBase();

	virtual void StartPlay() override;

protected:

	UPROPERTY(VisibleAnywhere, Category = "Components")
	UGSpawnControlComponent* SpawnControlComp;
};
// GGameModeBase.cpp
// ...
AGGameModeBase::AGGameModeBase()
{
	SpawnControlComp = CreateDefaultSubobject<UGSpawnControlComponent>("SpawnControlComp");
}

void AGGameModeBase::StartPlay()
{
	Super::StartPlay();
	SpawnControlComp->SpawnObjects();
}
  • 通过组件实现,并挂在GM下 (个人实现方法)

// GSpawnControlComponent.h
// ...
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ACTIONROGUELIKE_API UGSpawnControlComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UGSpawnControlComponent();

protected:

	UPROPERTY(EditDefaultsOnly, Category = "AI")
	int32 SpawnNumLimit;
	
	UPROPERTY(EditDefaultsOnly, Category = "AI")
	float SpawnInterval;

	UPROPERTY(EditDefaultsOnly, Category = "AI")
	TSubclassOf<AActor> SpawnClass;

	UPROPERTY(EditDefaultsOnly, Category = "AI")
	UEnvQuery* EnvQueryTemplate;

	FTimerHandle TimerHandle_SpawnReset;
	
public:
	UFUNCTION(BlueprintCallable, Category = "AI")
	void SpawnObjects();

	UFUNCTION(BlueprintCallable, Category = "AI")
	void StopSpawning();

protected:
	UFUNCTION()
	void SpawnReset_TimeElapsed();

	UFUNCTION()
	void OnQueryFinished(UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus);

};
// GSpawnControlComponent.cpp
// ...
UGSpawnControlComponent::UGSpawnControlComponent()
{
	SpawnInterval = 5.0;
	SpawnNumLimit = 3;
}

void UGSpawnControlComponent::SpawnReset_TimeElapsed()
{
	int32 CurrNumCount = 0;
	for(TActorIterator<AGAICharacter> It(GetWorld()); It; ++It)
	{
		AGAICharacter* AICharacter = *It;
		if(AICharacter)
		{
			auto AttributeComp = Cast<UGAttributeComponent>(AICharacter->GetComponentByClass(UGAttributeComponent::StaticClass()));
			if(AttributeComp && AttributeComp->IsAlive())
			{
				++CurrNumCount;
			}
		}
	}
	int32 NumLimit = SpawnNumLimit;
	if(DifficultyCurve)
	{
		DifficultyCurve->GetFloatValue(GetWorld()->TimeSeconds);
	}
	if(CurrNumCount>=NumLimit)
	{
		return;
	}
	if(ensureAlwaysMsgf(EnvQueryTemplate,TEXT("EnvQueryTemplate need to be select!!!")))
	{
		auto EQSInstance = UEnvQueryManager::RunEQSQuery(GetWorld(),EnvQueryTemplate,GetOwner(),EEnvQueryRunMode::RandomBest5Pct,nullptr);
		if(EQSInstance)
		{
			EQSInstance->GetOnQueryFinishedEvent().AddDynamic(this,&UGSpawnControlComponent::OnQueryFinished);
		}
	}
}

void UGSpawnControlComponent::SpawnObjects()
{
	GetWorld()->GetTimerManager().SetTimer(TimerHandle_SpawnReset,this,&UGSpawnControlComponent::SpawnReset_TimeElapsed,SpawnInterval,true);
}

void UGSpawnControlComponent::StopSpawning()
{
	GetWorld()->GetTimerManager().ClearTimer(TimerHandle_SpawnReset);
}

void UGSpawnControlComponent::OnQueryFinished(UEnvQueryInstanceBlueprintWrapper* QueryInstance,
                                              EEnvQueryStatus::Type QueryStatus)
{
	if(QueryStatus!=EEnvQueryStatus::Success)
	{
		UE_LOG(LogTemp,Warning,TEXT("Spawn Object EQS Failed!"));
		return;
	}
	
	TArray<FVector> Locations = QueryInstance->GetResultsAsLocations();
	if(Locations.Num()>0)
	{
		FActorSpawnParameters SpawnParams;
		SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
		if(ensureAlwaysMsgf(SpawnClass,TEXT("SpawnClass need to be select!!!")))
		{
			GetWorld()->SpawnActor<AActor>(SpawnClass,Locations[0],FRotator::ZeroRotator,SpawnParams);
		}
	}
}
  • 实现怪物低血量逃跑脱战补血功能 - Assignment 4

  • Service - 检测低血量

  • EQS - 找到距离怪物最近的躲藏点

  • Task - 到达隐藏点补满HP

  • 触发间隔为60秒

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值