您的位置:首页 > 编程语言 > C语言/C++

【UE4】【C++】炮弹(子弹)使用方法(创建、作用力、范围伤害及接受伤害)

2018-03-14 14:37 1241 查看
创建:
首先,肯定需要一个C++类(Actor就可以)(我们就叫他Projectile--弹)
然后创建基于Projectile的蓝图类
一个炮弹需要什么:作为炮弹的物体、射出去的粒子效果、爆炸之后的粒子效果等等
h:#include "Components/StaticMeshComponent.h" //炮弹
#include "Particles/ParticleSystemComponent.h" //粒子效果
#include "GameFramework/ProjectileMovementComponent.h" //用于制作子弹炮弹的抛物线
UProjectileMovementComponent *ProjectileMovementComponent = nullptr;

UPROPERTY(VisibleAnywhere,Category="Components")
UStaticMeshComponent* CollisionMesh = nullptr;

UPROPERTY(VisibleAnywhere, Category = "Components")
UParticleSystemComponent* LaunchParticle = nullptr;	//烟雾 火

UPROPERTY(VisibleAnywhere, Category = "Components")
UParticleSystemComponent* ImpactParticle = nullptr; //撞击

void LaunchProjectile(float Speed);    //调用此函数时 设置速度 顺便让抛物线组件启用

UFUNCTION()    //撞击事件
void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

cpp:AProjectile::AProjectile()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(FName("ProjectileMovement")); //生成组件
ProjectileMovementComponent->bAutoActivate = false; //自动飞行调成false

//炮弹
CollisionMesh = CreateDefaultSubobject<UStaticMeshComponent>(FName("CollisionMesh"));    //创建CollisionMesh
SetRootComponent(CollisionMesh);//设置成根结点
CollisionMesh->SetNotifyRigidBodyCollision(true); //设置可以撞击到物体
CollisionMesh->SetVisibility(true); //设置可见

LaunchParticle = CreateDefaultSubobject<UParticleSystemComponent>(FName("LaunchParticle"));
LaunchParticle->AttachTo(RootComponent);//将粒子效果绑定在根结点上(即CollisionMesh)
LaunchParticle->SetAutoActivate(true); //不要创建好就启动

ImpactParticle = CreateDefaultSubobject<UParticleSystemComponent>(FName("ImpactParticle"));
ImpactParticle->AttachTo(RootComponent);
ImpactParticle->SetAutoActivate(false); //不要创建好就启动

}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
Super::BeginPlay();
CollisionMesh->OnComponentHit.AddDynamic(this, &AProjectile::OnHit); //将Projectile绑定在了物件上
}

// Called every frame
void AProjectile::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

void AProjectile::LaunchProjectile(float Speed) {    //此函数用于鼠标左键输入连着的Fire函数(详情请见之前的生成子弹文章)
ProjectileMovementComponent->SetVelocityInLocalSpace(FVector::ForwardVector*Speed); //设置速度,因为是矢量所以乘向前的向量
ProjectileMovementComponent->Activate(); //可以飞行了
}
//碰撞后发生的事件
void AProjectile::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) {
UE_LOG(LogTemp, Warning, TEXT("Hit"));    //撞击后给个提示
ImpactParticle->Activate(true);            //撞击后产生撞击后的粒子效果

CollisionMesh->SetNotifyRigidBodyCollision(false); //碰撞之后再也不发生碰撞事件
SetRootComponent(ImpactParticle);//删除了作为根结点的炮弹,所以要在删除前换一个根结点
CollisionMesh->DestroyComponent(); //不是DestroyActor,Component是单一一个

}之后在Projectile的蓝图中就可以看到



如果还有一个DefaultSceneRoot,只需保存重启之后便会消失

作用力:
在原有的Projectile的代码中添加
h:#include "PhysicsEngine/RadialForceComponent.h"
UPROPERTY(VisibleAnywhere, Category = "Components")
URadialForceComponent* ExplosionForce = nullptr;

cpp:
在AProjectile中写:ExplosionForce= CreateDefaultSubobject<URadialForceComponent>(FName("ExplosionForce"));
ExplosionForce->AttachTo(RootComponent);
ExplosionForce->SetAutoActivate(false);在OnHit中写:ExplosionForce->FireImpulse();    //撞击后便释放力编译后在蓝图中可见:


多了一个ExplosionForce

之后便可在Details中设置他的各种东西啦!!
伤害值: http://api.unrealengine.com/INT/API/Runtime/Engine/Kismet/UGameplayStatics/ApplyRadialDamage/index.html

UGameplayStatics::ApplyRadialDamage

Choose your OS:Syntaxstatic bool ApplyRadialDamage
(
    const UObject * WorldContextObject,
    float BaseDamage,
    const FVector & Origin,
    float DamageRadius,
    TSubclassOf < class UDamageType > DamageTypeClass,
    const TArray < AActor * > & IgnoreActors,
    AActor * DamageCauser,
    AController * InstigatedByController,
    bool bDoFullDamage,
    ECollisionChannel DamagePreventionChannel
)

下面这个是在Radial范围内随中心递减伤害的方法 http://api.unrealengine.com/INT/API/Runtime/Engine/Kismet/UGameplayStatics/ApplyRadialDamageWithFalloff/index.html

UGameplayStatics::ApplyRadialDamageWithFalloff

Choose your OS:Syntaxstatic bool ApplyRadialDamageWithFalloff
(
    const UObject * WorldContextObject,
    float BaseDamage,
    float MinimumDamage,
    const FVector & Origin,
    float DamageInnerRadius,        //在几米以内都是最大伤害
    float DamageOuterRadius,        //在几米之外都是最小伤害
    float DamageFalloff,            //从里到外递减多少
    TSubclassOf < class UDamageType > DamageTypeClass,
    const TArray < AActor * > & IgnoreActors,
    AActor * DamageCauser,
    AController * InstigatedByController,
    ECollisionChannel DamagePreventionChannel
)

Kismet/GameplayStatics.h

--------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------- http://api.unrealengine.com/INT/API/Runtime/Engine/GameFramework/AActor/TakeDamage/index.html

APawn::TakeDamage

Choose your OS:Override Hierarchy
AActor::TakeDamage()
APawn::TakeDamage()
Syntaxvirtual float TakeDamage
(
    float DamageAmount,
    struct FDamageEvent const & DamageEvent,
    AController * EventInstigator,
    AActor * DamageCauser
)
h.(Projectile):UPROPERTY(EditAnywhere, Category = "Setup")
float ProjectileDamage = 20.0f;
cpp(Projectile):UGameplayStatics::ApplyRadialDamage(
this,     
ProjectileDamage,     //炮弹伤害 自己定义的
GetActorLocation(),
ExplosionForce->Radius,     //爆炸范围作为伤害范围
UDamageType::StaticClass(),     //需引用Engine/World.h 用于放更详细的伤害信息(比如是什么伤害:火焰、魔法……)
TArray<AActor*>()        //传进一个Array数组不伤害(比如友军),没有友军传的是一个空数组
);这个时候Projectile就有伤害了 还要让被打的目标有生命值
被打的Actor(Tank):
h:(Tank)
重写virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;
private:
UPROPERTY(EditAnywhere,Category="Health")
int32 MaxHp = 100;	//最大血量

UPROPERTY(VisibleAnywhere,Category="Health")
int32 CurrentHp = MaxHp;	//现在血量默认最大
cpp:(Tank)float ATank::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) {
int32 DamagePoint = FPlatformMath::RoundToInt(DamageAmount); //将伤害(float)通过四舍五入转为int,强制转型会向下取整
int32 DamageToApply = FMath::Clamp<int>(DamagePoint, 0, CurrentHp); //防止把血打到负数
CurrentHp -= DamageToApply;
if (CurrentHp <= 0) {
//Tank Dead
UE_LOG(LogTemp, Warning, TEXT("Tank Dead,Tank Name:%s"), *GetName());
}
return DamageToApply;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息