Ue4C++编程------伤害与c++(一)

    前面文中讲述了如何创建一个血条,本文将讲述如何创造伤害,怎么收到伤害。这在游戏中是相当重要的,因为大部分游戏都是有伤害机制的,当然,我们不会对伤害的数值进行研究,只进行简单的处理。

    首先在武器actor中,在构造玩collision时,设置为不碰撞,因为我们是只需要在挥剑的时候开启碰撞,其它时候应该是取消碰撞的。如下所示:

WeaponCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);

    接着在我们的人物character中,在挥剑的时候,开启碰撞,并设置一个定时器,在播放完蒙太奇的时候,才允许碰撞,因此首先,我们创建一个bool变量,用来控制OnHit函数,如下所示:

bool bCanAttack;
void ActiveAttack();
void DeActiveAttack(); // 不激活武器
void AWeaponActor::ActiveAttack()
{
	bCanAttack = true;
	if (WeaponCollision != nullptr) // 激活碰撞
	{
		WeaponCollision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
	}
}

void AWeaponActor::DeActiveAttack() // 关闭碰撞
{
	bCanAttack = false;
	if (WeaponCollision != nullptr)
	{
		WeaponCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	}
}

    接着在我们的人物character中,当挥剑时激活武器。而在播放完蒙太奇后则不激活武器,如下所示:

void ABlogProjectCharacter::Attack()
{
	UHeroAnimInstance* AnimInstance = Cast<UHeroAnimInstance>(GetMesh()->GetAnimInstance());
	if (AnimInstance != nullptr)
	{
		if (!AnimInstance->Montage_IsPlaying(AttackMontage)) // 如果该蒙太奇动画未在播放,则进行播放
		{
			Weapon->ActiveAttack();
			float fDt = AnimInstance->Montage_Play(AttackMontage);
			FTimerHandle ActiveWeapon;
			GetWorld()->GetTimerManager().SetTimer(ActiveWeapon, [=]() {
				Weapon->DeActiveAttack();
			}, fDt, false);
		}
	}
}

    接着我们创建一个接口,该接口是为了在发生碰撞中,只有实现了该接口的actor,才是有效的碰撞,如下图所示:    

    在接口函数中,定义一个受到伤害的函数,如下所示:

class BLOGPROJECT_API IBeAttackInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	
	virtual void BeAttacked(float fDamage) = 0;
	
};

    显然,我们的AI需要继承这个接口,并实现这个纯虚函数。我们可以在这个函数中,对我们的生命值进行加减,从而更新我们的血量。但是,这里我介绍另一种方法。

    首先在AI类中,重写一个叫TakeDamage的方法。为什么使用这种方法呢,因为这个函数中有个伤害类型的字段,我们可以根据不同的伤害类型,来使我们的AI做出不同的表现,但这里我只是简单的更新我们的血量,只是说一个思路。如下所示:

virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
float AAIBlogCharacter::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	CurrentHealth -= Damage;
	if (CurrentHealth <= 0) // 受到足够的伤害了,销毁actor
	{
		Destroy();
	}

	return 0.0f;
}

注意,我们这个函数是虚函数,那应该怎么调用这个函数呢?其实是不用调用的,引擎已经帮我们做好了这些,只要我们调用applydamage,便会调用该回调函数,从而造成伤害。因此,在我们的武器类中,实现OnHIt函数,如下所示:

void AWeaponActor::OnHit(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	UE_LOG(LogTemp, Warning, TEXT("OnHit"));
	if (bCanAttack && OtherActor != this) // 在攻击有效时,造成伤害
	{
		IBeAttackInterface* AC = Cast<IBeAttackInterface>(OtherActor);
		if (AC != nullptr)
		{
			UGameplayStatics::ApplyDamage(OtherActor, 10.0f, nullptr, this, UDamageType::StaticClass()); // 造成10点伤害
		}
	}
}

    编译代码并测试成功,可以看到我们已经对AI造成了伤害。:

    




    

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的UE4 C++代码示例,用于触发门的开启事件: 首先,创建一个继承自Actor的蓝图类,将门模型拖放到该类中,并为门添加一个Box组件作为门的触发器。 在.h文件中添加以下代码: ```c++ #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "MyDoor.generated.h" UCLASS() class MYPROJECT_API AMyDoor : public AActor { GENERATED_BODY() public: AMyDoor(); protected: UPROPERTY(VisibleAnywhere, Category = "Components") class UStaticMeshComponent* DoorMesh; UPROPERTY(VisibleAnywhere, Category = "Components") class UBoxComponent* TriggerBox; UPROPERTY(EditAnywhere, Category = "Properties") float OpenAngle = 90.0f; UPROPERTY(EditAnywhere, Category = "Properties") float DoorCloseDelay = 2.0f; float LastDoorOpenTime; UPROPERTY(EditAnywhere, Category = "Properties") float DoorOpenSpeed = 0.8f; UPROPERTY(EditAnywhere, Category = "Properties") float DoorCloseSpeed = 2.0f; UFUNCTION() void OnDoorOverlapBegin(class AActor* OverlappedActor, class AActor* OtherActor); UFUNCTION() void OnDoorOverlapEnd(class AActor* OverlappedActor, class AActor* OtherActor); public: virtual void Tick(float DeltaTime) override; }; ``` 在.cpp文件中添加以下代码: ```c++ #include "MyDoor.h" #include "Components/StaticMeshComponent.h" #include "Components/BoxComponent.h" AMyDoor::AMyDoor() { PrimaryActorTick.bCanEverTick = true; DoorMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorMesh")); RootComponent = DoorMesh; TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox")); TriggerBox->SetupAttachment(RootComponent); TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AMyDoor::OnDoorOverlapBegin); TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AMyDoor::OnDoorOverlapEnd); LastDoorOpenTime = 0.0f; } void AMyDoor::Tick(float DeltaTime) { Super::Tick(DeltaTime); if (GetWorld()->TimeSeconds - LastDoorOpenTime > DoorCloseDelay) { float CurrentYaw = DoorMesh->GetComponentRotation().Yaw; float TargetYaw; if (CurrentYaw > 0) { TargetYaw = 0.0f; } else { TargetYaw = OpenAngle; } float NewYaw = FMath::FInterpTo(CurrentYaw, TargetYaw, DeltaTime, DoorCloseSpeed); DoorMesh->SetRelativeRotation(FRotator(0.0f, NewYaw, 0.0f)); } } void AMyDoor::OnDoorOverlapBegin(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor && OtherActor != this) { LastDoorOpenTime = GetWorld()->TimeSeconds; float CurrentYaw = DoorMesh->GetComponentRotation().Yaw; float NewYaw = FMath::FInterpTo(CurrentYaw, OpenAngle, GetWorld()->DeltaTimeSeconds, DoorOpenSpeed); DoorMesh->SetRelativeRotation(FRotator(0.0f, NewYaw, 0.0f)); } } void AMyDoor::OnDoorOverlapEnd(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor && OtherActor != this) { LastDoorOpenTime = GetWorld()->TimeSeconds; } } ``` 这个代码示例中,我们添加了一个门模型和一个Box组件用作门的触发器。在Box组件上注册了OnComponentBeginOverlap和OnComponentEndOverlap事件,当有物体进入或离开Box时,将触发相应的事件。在OnDoorOverlapBegin事件中,我们通过插值将门旋转到开启的角度,并在LastDoorOpenTime中存储当前时间。在Tick函数中,我们检查LastDoorOpenTime是否超过DoorCloseDelay,如果是,则插值将门旋转回关闭的角度。 最后,将蓝图类添加到场景中,运行游戏并测试门的开启和关闭事件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值