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

Brain Component

BehaviorTreeComponent的父类,可以通过调用StopLogic()函数停止行为树

Static Function

静态函数

Metadata Specifier

在声明类、接口、结构、枚举、枚举值、函数或属性时,你可以添加元数据指示器来控制它们如何与引擎和编辑器的各个方面互动

使用方式:

{UCLASS/UENUM/UINTERFACE/USTRUCT/UFUNCTION/UPROPERTY}(SpecifierX, meta=(MetaTag1="Value1", MetaTag2, ..), SpecifierY)

Tips

  • SceneComponent需要在创建时设置Attachment,因为他们有位置信息

项目代码

  • 实现怪物死亡逻辑

  • 实现受击索敌

  • 实现两个静态函数,获取属性组件和判断是否存活

  • 赋予怪物攻击随机性

  • 玩家死亡后怪物停止攻击

  • 怪物受击闪烁

// GAICharacter.cpp
// ...
void AGAICharacter::Die()
{
	// stop BT
	AAIController* AIC = Cast<AAIController>(GetController());
	if(AIC)
	{
		AIC->GetBrainComponent()->StopLogic("Killed");
	}
	// Ragdoll
	GetMesh()->SetAllBodiesSimulatePhysics(true);
	GetMesh()->SetCollisionProfileName("Ragdoll"); 
	Cast<UCapsuleComponent>(RootComponent)->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		
	// SetLifeSpan
	SetLifeSpan(10.0f);
}

void AGAICharacter::OnChangedHealth(AActor* InstigatorActor, UGAttributeComponent* OwningComp, float NewHealth,
	float Delta)
{
	if(Delta<0.0f)
	{
		DamagedFlash();
		// can be improve by filter out ally
		if(InstigatorActor!=this)
		{
			SetTargetActor(InstigatorActor);
		}
		if(NewHealth<=0)
		{
			Die();
		}
	}
}

void AGAICharacter::Attack_Implementation(AActor* TargetActor)
{
	IGAICharacterInterface::Attack_Implementation(TargetActor);

	FVector SpawnLocation = GetMesh()->GetSocketLocation("Muzzle_Front_XForward");
	FVector TargetLocation = TargetActor->GetActorLocation();
	FRotator SpawnRotation = FRotationMatrix::MakeFromX(TargetLocation-SpawnLocation).Rotator();
	// Give random offset to projectile to make game more fun
	SpawnRotation.Pitch += FMath::RandRange(0.0f,RandomAttackOffset);
	SpawnRotation.Yaw += FMath::RandRange(-RandomAttackOffset,RandomAttackOffset);
	
	auto RangeAttack_TimeElapsed = [=]()
	{
		SpawnProjectile(RangeAttackProjectile,SpawnLocation,SpawnRotation);
	};
	PlayAnimMontage(RangeAttackAnim);
	GetWorldTimerManager().SetTimer(TimerHandle_RangeAttack,RangeAttack_TimeElapsed,1,false,RangeAttackProjectileDelay);
}
// GAttributeComponent.h
// ...
public:
	UFUNCTION(BlueprintCallable, Category = "Attributes")
	bool ApplyHealthChange(AActor* Instigator, float Delta);

	UFUNCTION(BlueprintCallable, Category = "Attributes")
	static UGAttributeComponent* GetAttributeComponent(AActor* Actor);
	
	UFUNCTION(BlueprintCallable, Category = "Attributes", meta = (DisplayName = "IsAlive"))
	static bool IsActorAlive(AActor* Actor);
// GAttributeComponent.cpp
// ... 
bool UGAttributeComponent::ApplyHealthChange(AActor* Instigator, float Delta)
{
	float PreviousHealth = CurrHealth;
	CurrHealth = FMath::Clamp(CurrHealth+Delta,0.0f,MaxHealth);
	float AcutualDelta = CurrHealth - PreviousHealth;
	// 调用代理
	OnHealthChanged.Broadcast(Instigator,this,CurrHealth,AcutualDelta);
	
	return true;
}

UGAttributeComponent* UGAttributeComponent::GetAttributeComponent(AActor* Actor)
{
	if(Actor)
	{
		return Cast<UGAttributeComponent>(Actor->GetComponentByClass(UGAttributeComponent::StaticClass()));
	}
	return nullptr;
}

// return false if no AttributeComp or not alive
bool UGAttributeComponent::IsActorAlive(AActor* Actor)
{
	UGAttributeComponent* AttributeComp = GetAttributeComponent(Actor);
	return (AttributeComp && AttributeComp->IsAlive());
}
// BTTask_AttackTarget.cpp
// ...
EBTNodeResult::Type UBTTask_AttackTarget::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	AAIController* MyController = OwnerComp.GetAIOwner();
	UBlackboardComponent* MyBB = OwnerComp.GetBlackboardComponent();

	if(ensure(MyController)&ensure(MyBB))
	{
		APawn* MyPawn = MyController->GetPawn();
		if(MyPawn && MyPawn->Implements<UGAICharacterInterface>())
		{
			AActor* TargetActor = Cast<AActor>(MyBB->GetValueAsObject(Key_TargetActor.SelectedKeyName));
			if(TargetActor && UGAttributeComponent::IsActorAlive(TargetActor))
			{
				IGAICharacterInterface::Execute_Attack(MyPawn,TargetActor);
				return EBTNodeResult::Succeeded;
			}
		}
		
	}
	return EBTNodeResult::Failed;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值