目录
枪口特效
(1)单发枪
在武器类中添加NiagaraSystem和NiagaraComponent组件两个变量,
class UNiagaraSystem; class UNiagaraComponent; //枪口特效 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") UNiagaraSystem* MuzzleFX; //返回枪口特效组件 UNiagaraComponent* SpawnMuzzleFX();
在Cpp中
UNiagaraFunctionLibrary::SpawnSystemAttached()
#include "NiagaraFunctionLibrary.h" #include "NiagaraComponent.h" UNiagaraComponent* ASTUBaseWeapon::SpawnMuzzleFX() { //在枪口生成特效 //WeaponMesh是武器骨骼网格体 return UNiagaraFunctionLibrary::SpawnSystemAttached ( MuzzleFX, WeaponMesh, "MuzzleFlashSocket", FVector::ZeroVector, FRotator::ZeroRotator, EAttachLocation::SnapToTarget, true ); }
(2)连发枪
在头文件中
class UNiagaraComponent; UPROPERTY() UNiagaraComponent* MuzzleFXComponent; void InitMuzzleFX(); void SetMuzzleFXVisibility(bool Visible);
在CPP中
SetPaused():停止
SetVisibility():可见
#include "NiagaraComponent.h" void ASTURifleWeapon::InitMuzzleFX() { //这个SpawnMuzzleFX在上面单发枪基类实现的 MuzzleFXComponent = SpawnMuzzleFX(); SetMuzzleFXVisibility(true); } void ASTURifleWeapon::SetMuzzleFXVisibility(bool Visible) { if (MuzzleFXComponent) { MuzzleFXComponent->SetPaused(!Visible); MuzzleFXComponent->SetVisibility(Visible, true); } }
然后在开枪时激活,停止时关闭
void ASTURifleWeapon::Fire() { InitMuzzleFX(); GetWorldTimerManager().SetTimer(FireTimerHandle, this, &ASTURifleWeapon::MakeShot, TimerBetweenShots, true); } void ASTURifleWeapon::StopFire() { GetWorldTimerManager().ClearTimer(FireTimerHandle); SetMuzzleFXVisibility(false); }
弹道特效
在武器头文件中
class UNiagaraComponent; class UNiagaraSystem; //弹道特效 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") UNiagaraSystem* TraceFX; //这个TraceTargetName 是Niagara特效中的变量名 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") FString TraceTargetName = "TraceTarget"; void SpawnTraceFX(const FVector& TraceStart, const FVector& TraceEnd);
在CPP中
其中的一些函数实现在C++学习(六)中可以找到
主要是将射线检测到的落点作为弹道特效的落点
UNiagaraFunctionLibrary::SpawnSystemAtLocation():生成特效
SetNiagaraVariableVec3():
#include "NiagaraComponent.h" #include "NiagaraFunctionLibrary.h" void ASTURifleWeapon::MakeShot() { if (!GetWorld() || IsAmmoEmpty()) { StopFire(); return; } FVector TraceStart, TraceEnd; if (!GetTraceData(TraceStart, TraceEnd)) { StopFire(); return; } //通过摄像机的旋转来检测 FHitResult HitResult; MakeHit(HitResult, TraceStart, TraceEnd); //弹道特效落点 FVector TraceFXEnd = TraceEnd; //有检测到 if (HitResult.bBlockingHit) { TraceFXEnd = HitResult.ImpactPoint; MakeDamage(HitResult); //击中特效 WeaponFXComponent->PlayImpactFX(HitResult); 绘制一条枪口到检测点的射线 绘制调试射线 参数:World,开始位置,结束位置,颜色,判断射线是否永久绘制(默认false),存在时间,绘制深度的顺序,粗细 //DrawDebugLine(GetWorld(), GetMuzzleWorldLocation(), HitResult.ImpactPoint, FColor::Red, false, 3.0f, 0, 3.0f); 绘制球形调试 //DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10.0f, 24, FColor::Red, false, 3.0f); } //else //{ // //绘制一条枪口到终点的射线 // //绘制调试射线 参数:World,开始位置,结束位置,颜色,判断射线是否永久绘制(默认false),存在时间,绘制深度的顺序,粗细 // DrawDebugLine(GetWorld(), GetMuzzleWorldLocation(), TraceEnd, FColor::Red, false, 3.0f, 0, 3.0f); //} //弹道特效 SpawnTraceFX(GetMuzzleWorldLocation(), TraceFXEnd); DecreaseAmmo(); } void ASTURifleWeapon::SpawnTraceFX(const FVector& TraceStart, const FVector& TraceEnd) { UNiagaraComponent* TraceFXComponent = UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), TraceFX, TraceStart); if (TraceFXComponent) { TraceFXComponent->SetNiagaraVariableVec3(TraceTargetName, TraceEnd); } }
击中特效
这里是用ActorComponent来专门处理击中特效逻辑的,然后在落点生成贴花
在组件类中创建两个结构体用于存储不同的击中特效,这里是通过材质来判断击中的物体
在头文件中:
class UMaterialInterface; class UNiagaraSystem; //贴花 USTRUCT(BlueprintType) struct FDecalData { GENERATED_USTRUCT_BODY() UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") UMaterialInterface* Material; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") FVector Size = FVector(10.0f); UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") float LifeTime = 5.0f; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") float FadeOutTime = 0.7f; }; //粒子特效 USTRUCT(BlueprintType) struct FImpactData { GENERATED_USTRUCT_BODY(); UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") UNiagaraSystem* NiagaraEffect; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") FDecalData DecalData; }; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") FImpactData DefaultImpactData; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "VFX") TMap<UPhysicalMaterial*, FImpactData> ImpactDataMap; void PlayImpactFX(const FHitResult& Hit);
在CPP中:
UNiagaraFunctionLibrary::SpawnSystemAtLocation:生成特效
UGameplayStatics::SpawnDecalAtLocation:生成贴花
SetFadeOut():贴花消失
#include "NiagaraFunctionLibrary.h" #include "PhysicalMaterials/PhysicalMaterial.h" #include "Kismet/GameplayStatics.h" #include "Components/DecalComponent.h" void USTUWeaponFXComponent::PlayImpactFX(const FHitResult& Hit) { FImpactData ImpactData = DefaultImpactData; //根据击中的不用材质 播放不同的特效 //如果是根据材质的话,被击中的碰撞体需要开启bReturnPhysicalMaterial为true if (Hit.PhysMaterial.IsValid()) { const UPhysicalMaterial* PhysMat = Hit.PhysMaterial.Get(); if (ImpactDataMap.Contains(PhysMat)) { ImpactData = ImpactDataMap[PhysMat]; } } //niagara UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), ImpactData.NiagaraEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation() ); //decal UDecalComponent* DecalComponent = UGameplayStatics::SpawnDecalAtLocation( GetWorld(), ImpactData.DecalData.Material, ImpactData.DecalData.Size, Hit.ImpactPoint, Hit.ImpactNormal.Rotation() ); if (DecalComponent) { DecalComponent->SetFadeOut(ImpactData.DecalData.LifeTime, ImpactData.DecalData.FadeOutTime); } }
这里使用到的材质 是在碰撞设置中重载的
然后在武器类中添加这个组件类,
class USTUWeaponFXComponent; //击中特效 UPROPERTY(VisibleAnywhere, Category = "VFX") USTUWeaponFXComponent* WeaponFXComponent;
在射击逻辑中调用组件的PlayImpactFX函数,将射线检测到的HitResult传递过去
void ASTURifleWeapon::MakeShot() { if (!GetWorld() || IsAmmoEmpty()) { StopFire(); return; } FVector TraceStart, TraceEnd; if (!GetTraceData(TraceStart, TraceEnd)) { StopFire(); return; } //通过摄像机的旋转来检测 FHitResult HitResult; MakeHit(HitResult, TraceStart, TraceEnd); //弹道特效落点 FVector TraceFXEnd = TraceEnd; //有检测到 if (HitResult.bBlockingHit) { TraceFXEnd = HitResult.ImpactPoint; MakeDamage(HitResult); //击中特效 WeaponFXComponent->PlayImpactFX(HitResult); 绘制一条枪口到检测点的射线 绘制调试射线 参数:World,开始位置,结束位置,颜色,判断射线是否永久绘制(默认false),存在时间,绘制深度的顺序,粗细 //DrawDebugLine(GetWorld(), GetMuzzleWorldLocation(), HitResult.ImpactPoint, FColor::Red, false, 3.0f, 0, 3.0f); 绘制球形调试 //DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10.0f, 24, FColor::Red, false, 3.0f); } //else //{ // //绘制一条枪口到终点的射线 // //绘制调试射线 参数:World,开始位置,结束位置,颜色,判断射线是否永久绘制(默认false),存在时间,绘制深度的顺序,粗细 // DrawDebugLine(GetWorld(), GetMuzzleWorldLocation(), TraceEnd, FColor::Red, false, 3.0f, 0, 3.0f); //} //弹道特效 SpawnTraceFX(GetMuzzleWorldLocation(), TraceFXEnd); DecreaseAmmo(); }
最终效果:
地上的弹孔就是用贴花做的
子弹特效
需要在构建文件中加入这两个模块