UE4 设置weapon(C++)

引擎版本:UE 4.22 + VS 2019; 学习教程:Unreal Engine 4 Mastery - Create Multiplayer Games With Cpp

1、创建一个Actor类(SWeapon)作为武器,并添加USkeletalMeshComponent

    UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category=Components)
    class USkeletalMeshComponent* MeshComp;

ASWeapon::ASWeapon()
{
     // 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;
    MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp"));
    RootComponent = MeshComp;
}

2、基于SWeapon创建蓝图BP_SWeapon,导入Weapon资源包,设置Mesh

 3、设置BP_SCharacter在游戏开始时持有武器

(一)、BP_SCharacter蓝图中,Beginplay->Spawn Actor from class(class:BP_Sweapon,AlwaysSpawn,IgnoreCollision)->Attach To Component(snap to surface)

(二)、设置指定socket

 (三)、调整Socket,使得武器更好的贴合人物

4、添加Fire()方法,并用蓝图快速测试

(一)、射线检测,起点(位置,旋转)+终点,如果中途与物体发生碰撞,则记录HitResult

#include "DrawDebugHelpers.h"

void ASWeapon::Fire()
{
    AActor* MyOwner = GetOwner();
    if (MyOwner) {
        FVector EyeLocation;
        FRotator EyeRotation;
        MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
        FVector TraceEnd = EyeLocation + (EyeRotation.Vector() * 10000);
        FCollisionQueryParams QueryParams;
        QueryParams.AddIgnoredActor(MyOwner);
        QueryParams.AddIgnoredActor(this);
        QueryParams.bTraceComplex = true;
        FHitResult Hit;
        if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
        {
            //Do damage
        }
        DrawDebugLine(GetWorld(),EyeLocation,TraceEnd,FColor::White,false,1.0f,0,1.0f);
    } 

(二)、重写GetActorEyesViewPoint方法,使得射线检测的起点为相机所在位置

FVector ASCharacter::GetPawnViewLocation() const
{
    if (CameraComp) {
        return CameraComp->GetComponentLocation();
    }
    return Super::GetPawnViewLocation();
}

(三)、BP_SCharacter调用Fire

 5、应用Damage

(一)、完善Do Damage部分代码,其中DamageType的定义为TSubclassOf<UDamageType> DamageType;

        if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, ECC_Visibility, QueryParams))
        {
            //Do damage
            AActor* HitActor = Hit.GetActor();
            UGameplayStatics::ApplyPointDamage(HitActor,20.f, ShotDirection,Hit,MyOwner->GetInstigatorController(),this,DamageType);
        }

(二)、添加一个Target,设置好collision,添加Event PointDamage->DrawDebugSphere进行测试

6、SWeapon中添加子弹射击特效

(一)、射击时火焰效果,

        if (MuzzleEffect) {
            UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComp, MuzzleSocketName);     
        }

(二)、击中时效果

     if (ImpactEffect) {
      UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());
       }

(三)、头文件中添加

    UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Muzzle")
    FName MuzzleSocketName;    

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Muzzle")
    UParticleSystem* MuzzleEffect;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Muzzle")
    UParticleSystem* ImpactEffect;
 

(四)、最终BP_SWeapon蓝图中指定所需要的资源 

6、设置简单的准心 ,创建一个WidgetBP,在中心放置一张准心的图片(根据感觉调整UI的位置)

 7、创建一个榴弹发射器

(一)、基于SWeapon派生一个C++类(SProjectfileWeapon),重写Fire方法:

protected:
    virtual void Fire()override;
    UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category=Projectile)
    TSubclassOf<AActor>ProjectileClass;

Fire方法主要是根据枪口位置发射子弹

void ASProjectfileWeapon::Fire()
{
    AActor* MyOwner = GetOwner();
    if (MyOwner) {
        FVector EyeLocation;
        FRotator EyeRotation;
        MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
        FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName);

        FActorSpawnParameters SpawnParams;
        SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
        //在枪口发射子弹
        GetWorld()->SpawnActor<AActor>(ProjectileClass, MuzzleLocation,EyeRotation,SpawnParams);

    }
}
 

(二)、派生子类蓝图(BP_GrenaradeLaucher),在其中添加武器的Mesh

(三)、创建一个Actor(BP_GrenaradeProjectile),作为子弹;主要是为该Actor添加一个ProjectileMovementcomponent和一个sphere(或者是子弹的具体模型),注意设置collision和simulate physics

(四)、在BP_GrenaradeProjectile的event graph中应用伤害

主要逻辑是Beginplay->Delay(1)->Explode(customEvent)

explode->spawn Emitter at location(指定爆炸特效,位置等信息)->apply radius damage->draw debugsphere->Destory

最后的效果:

8、添加镜头拉近效果: (主要是通过Camera的FOV实现)

(一)、按键绑定

    PlayerInputComponent->BindAction("Zoom", IE_Pressed, this, &ASCharacter::BeginZoom);
    PlayerInputComponent->BindAction("Zoom", IE_Released, this, &ASCharacter::EndZoom);

void ASCharacter::BeginZoom()
{
    bWantsToZoom = true;
}

void ASCharacter::EndZoom()
{
    bWantsToZoom = false;
}

(二)、 具体的镜头拉近是在tick中进行,FMath::FInterpTo可以使得镜头平缓的拉近

void ASCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    float TargetFOV = bWantsToZoom ? ZoomedFOV : DefaultFOV;
    float CurrentFOV = FMath::FInterpTo(CameraComp->FieldOfView, TargetFOV, DeltaTime, ZoomInterSpeed);
    CameraComp->SetFieldOfView(CurrentFOV);
}

对应的头文件中添加内容如下:

 

    bool bWantsToZoom;

    UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category=player)
    float ZoomedFOV;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = player,meta=(ClampMin=0.0,ClampMax=100))
    float ZoomInterSpeed;

    float DefaultFOV;
    void BeginZoom();
    void EndZoom();

 9、重构代码:将之前蓝图中生成武器调用fire方法用C++实现

需要注意的是蓝图与C++的不同,Sweapon中的Fire方法之前是Protected,如果想在SCharater中声明一个CurrentWeapon,要想调用SWeapon的Fire方法,需要把它设置为Public。也就是说蓝图中如果想要使用protected访问权限需要在UPROPERTY中使用BlueprintProtected.

在SCharacter中添加:

    ASWeapon* CurrentWeapon;
    UPROPERTY(EditDefaultsOnly,Category=player)
    TSubclassOf<ASWeapon> StarterWeaponClass;
    UPROPERTY(VisibleDefaultsOnly, Category = player)
    FName WeaponAttachSocketName;
    void Fire();

对应的spawn出Weapon作为CurrentWeapon再吸附于指定位置

ASCharacter::ASCharacter()
{

。。。。。。。

    WeaponAttachSocketName = "WeaponSocket";
}
 

void ASCharacter::BeginPlay()
{
    Super::BeginPlay();
    DefaultFOV = CameraComp->FieldOfView;
    //spawns a default weapon
    FActorSpawnParameters SpawnParams;
    SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

    CurrentWeapon = GetWorld()->SpawnActor<ASWeapon>(StarterWeaponClass, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
    if (CurrentWeapon)
    {
        CurrentWeapon->SetOwner(this);
        CurrentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, WeaponAttachSocketName);
        }
}

这样暂时就可以通过指定StarterWeaponClass来指定武器了 

 10、为武器射击时添加镜头抖动效果:
(一)、C++中调用ClientPlayCameraShake

void ASWeapon::PlayFireEffect()
{
    if (MuzzleEffect) {
        UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComp, MuzzleSocketName);

    }
    APawn* MyOwner = Cast<APawn>(GetOwner());
    if (MyOwner)
    {
        APlayerController* PC = Cast<APlayerController>(MyOwner->GetController());
        if (PC) {
            PC->ClientPlayCameraShake(FireCamShake);
        }
    }
}

。。。。。。。。。。。。。。

UPROPERTY(EditDefaultsOnly,Category=Weapon)
 TSubclassOf<UCameraShake>FireCamShake;

 (二)、创建一个cameraShake蓝图(CamShake_RifileFire),进行对应的水平后座、垂直后座等参数的设置

11、优化与问题:

首先是榴弹发射器的子弹,添加Mesh与TraceEffect 

问题:(真实感)

1、关于子弹:Refile的伤害计算是用射线检测做的对应point damage(缺乏真实感),榴弹发射器发射真实的子弹对应不到准心。

2、关于动画:相机向上向下时,持枪的朝向也需要改变

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值