CoopGame02-武器1
type: Post
status: Published
date: 2022/10/02
slug: CoopGame02
summary: UE4 C++多人游戏入门
category: Unreal
导入资产
- 下载源文件,密码:zmingu
- 导入CoopGame\Content\Weapons文件夹到项目
Content
目录
创建武器
创建武器类
创建武器C++类
SWeapon
,继承Actor
的。/*SWeapon.h*/ //武器的骨骼网格体 UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Weapon") class USkeletalMeshComponent* SKMeshComp;
/*SWeapon.cpp*/ ASWeapon::ASWeapon() { SKMeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SKMeshComp")); RootComponent = SKMeshComp; }
创建继承
SWeapon
武器类的蓝图类BP_SWeapon
,并选择设置武器的骨骼网格体SK_Rifle.
为角色生成武器
在角色骨骼的
hand_r
右键添加名为WeaponSocket
武器的骨骼插槽。在
SCharacter
编写代码将武器生成到玩家手上的名为WeaponSocket
的插槽上。/*SCharacter.h*/ //当前武器 UPROPERTY(BlueprintReadOnly) class ASWeapon* CurrentWeapon; //需要生成的武器类 UPROPERTY(EditDefaultsOnly, Category = "Player") TSubclassOf<ASWeapon> StarterWeaponClass; //武器插槽名 UPROPERTY(VisibleDefaultsOnly, Category = "Player") FName WeaponAttachSocketName;
/*SCharacter.cpp*/ /*引入武器类*/ #include "SWeapon.h" /*在ASCharacter()构造函数中添加*/ //玩家骨骼上的武器插槽名 WeaponAttachSocketName = "WeaponSocket"; /*在BeginPlay()函数中添加*/ /* * 生成默认的武器。 */ //设置生成参数。 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
的类默认值为BP_SWeapon
调整武器位置
武器开火
在武器类
SWeapon
中编写开火函数/*SWeapon.h*/ //开火函数 UFUNCTION(BlueprintCallable,Category="Weapon") void Fire();
/*SWeapon.cpp*/ /*引入绘制调试射线助手类*/ include "DrawDebugHelpers.h" /*定义Fire()函数*/ void ASWeapon::Fire() { AActor* WeaponOwner= GetOwner(); if (WeaponOwner) { /* * 弹道的起点和终点 */ FVector EyeLocation; FRotator EyeRotator; //弹道起点 = 玩家摄像头位置 Cast<APawn>(Owner)->GetActorEyesViewPoint(EyeLocation,EyeRotator); //弹道终点 = 起点位置 + (方向 * 距离) FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000); /* *打击和碰撞 */ //打击结果(里面能存储射线打击到的一些信息) FHitResult Hit; //查询参数 FCollisionQueryParams QueryParams; //查询参数设置忽略武器自身和拥有武器的玩家 QueryParams.AddIgnoredActor(this); QueryParams.AddIgnoredActor(WeaponOwner); //查询参数启用复合追踪 QueryParams.bTraceComplex = true; //判断是否弹道射线打到东西,单射线查询通道(打击结果,射线开始位置,射线结束位置,碰撞通道,查询参数) bool bHit = GetWorld()->LineTraceSingleByChannel(Hit,EyeLocation,TraceEnd,ECC_Visibility,QueryParams); //如果射线打到东西 if (bHit) { //处理击中事件,待编写 } //把射线检测绘制出来 DrawDebugLine(GetWorld(),EyeLocation,TraceEnd,FColor::Red,false,1,0,1); } }
在角色蓝图
BP_SCharacter
使用鼠标左键事件调用武器的开火函数,此时开火可见从玩家身上摄像机发出的射线。(右键搜索CurrentWeapon
变量,从该变量调用Fire()函数)
使开火产生伤害
/*SWeapon.h*/
//伤害类型
UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category="Weapon")
TSubclassOf<UDamageType> DamageType;
/*SWeapon.cpp*/
/*补充射线击中需要处理的事情*/
//如果射线打到东西
if (bHit)
{
//应用点状伤害(被伤害的Actor,要应用的基础伤害,受击方向,描述命中的碰撞或跟踪结果,照成伤害的控制器(例如射击武器的玩家的控制器),实际造成伤害的Actor,伤害类型)
UGameplayStatics::ApplyPointDamage(Hit.GetActor(),20,EyeRotator.Vector(),Hit,WeaponOwner->GetInstigatorController(),this,DamageType);
}
这里调一下角色身上的弹簧臂的位置,让待会更好观察并测试代码结果.
在角色蓝图类
BP_SCharacter
,添加事件点状伤害
并绘制调试球体,将网格体碰撞打开,- 在场景中拖入
BP_SCharacter
测试射击结果。
- 在场景中拖入
开火特效
枪口特效和击中特效
导入武器特效资产,目录
WeaponEffects
,并编写SWeapon
武器类。/*SWeapon.h*/ //枪骨骼上的枪口骨骼名 UPROPERTY(VisibleDefaultsOnly,BlueprintReadOnly,Category="Weapon") FName MuzzleSocketName; //枪口特效 UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category="Weapon") class UParticleSystem* MuzzleEffect; //击中特效 UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category="Weapon") class UParticleSystem* ImpactEffect;
/*SWeapon.cpp*/ /*引入特效相关头文件*/ #include "Kismet/GameplayStatics.h" /*ASWeapon()构造函数设置枪口骨骼的插槽名*/ MuzzleSocketName = "MuzzleSocket"; /*Fire()函数的if(WeaponOwner)判断中添加*/ if (MuzzleEffect) { //生成特效并附加到组件上的某个骨骼上,参数为(粒子特效,要依附的组件,生成的命名点) UGameplayStatics::SpawnEmitterAttached(MuzzleEffect,SKMeshComp,MuzzleSocketName); } if (ImpactEffect) { //在生成特效在某个位置,参数为(生成的世界,粒子特效,世界位置,世界旋转)——SpawnEmitterAtLocation有三个重载。 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),ImpactEffect,Hit.ImpactPoint,Hit.ImpactPoint.Rotation()); }
BP_SWeapon
蓝图类设置特效的默认值如下,并测试。攻击地板,可以看到已经有了枪口特效和击中特效,其中我们会发现奇怪的问题,射线检测是从角色上发射出来的,这明显是不对,需要修改成从摄像机(也就是我们作为玩家看的方向)发射,在后面编写弹道特效的同时会进行修改.
弹道特效
先设置弹道特效粒子
P_SmokeTrail
的参数名为Target(光束粒子发射器)添加弹道特效
/*SWeapon.h*/ //弹道特效 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") UParticleSystem* TracerEffect; //弹道特效参数名 UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon") FName TracerTargetName;
/*SWeapon.cpp*/ /*引入粒子组件*/ #include "Particles/ParticleSystemComponent.h" /*ASWeapon()构造函数设置枪口骨骼的插槽名*/ TracerTargetName= "Target"; /*Fire()函数的if(WeaponOwner)判断中添加*/ //获得枪口插槽位置。 FVector MuzzleSocketLocation = SKMeshComp->GetSocketLocation(MuzzleSocketName); //枪口生成特效并拿到特效组件实例。 UParticleSystemComponent* TracerComp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),TracerEffect,MuzzleSocketLocation); if (TracerComp) { //在此粒子组件上设置命名矢量实例参数。 TracerComp->SetVectorParameter(TracerTargetName,TraceEnd); }
为武器BP_SWeapon蓝图类设置上弹道特效默认值.
现在来改变一下射线发射的初始位置.
可以看到我们调用的
GetActorEyesViewPoint()
获取的位置是在角色上方加上BaseEyeHeight
的值的位置,我们要修改成玩家摄像机位置.在角色类
SCharacter
中重写GetPawnViewLocation()
函数/*SCharacter.h*/ virtual FVector GetPawnViewLocation() const override;
/*SCharacter.cpp*/ FVector ASCharacter::GetPawnViewLocation() const { if (CameraComp) return CameraComp->GetComponentLocation(); return Super::GetPawnViewLocation(); }
注释掉之前的调试射线
/*SWeapon.cpp*/ //把射线检测绘制出来 //DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);
武器准星
- 新建UI目录,新建控件蓝图,命名
WBP_Crosshair
. 拖入image图片,锚点设置为中心,其他设置如下.
在角色蓝图
BP_SCharacter
中的BeginPlayer
事件编写逻辑,将控件添加到视口
运行效果
挑战:榴弹发射器
- 创建继承SWeapon的C++类
SProjectileWeapon,
重写Fire()函数 将
SWeapon
的Fire()函数修改为虚函数./*SWeapon.h*/ UFUNCTION(BlueprintCallable,Category="Weapon") virtual void Fire();
SProjectileWeapon
类中重写Fire()
函数,声明子弹类./*SProjectileWeapon.h*/ protected: virtual void Fire() override; UPROPERTY(EditDefaultsOnly,Category="ProjectileWeapon") TSubclassOf<AActor> ProjectileClass;//生成的子弹类
/*SProjectileWeapon.cpp*/ void ASProjectileWeapon::Fire() { Super::Fire(); AActor* WeaponOwner = GetOwner(); if (WeaponOwner) { FVector EyeLocation; FRotator EyeRotator; WeaponOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator); //获取枪口位置 FVector MuzzleLocation = SKMeshComp->GetSocketLocation(MuzzleSocketName); //生成参数 FActorSpawnParameters SpawnParams; SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; if (ProjectileClass) { GetWorld()->SpawnActor<AActor>(ProjectileClass, MuzzleLocation, EyeRotator, SpawnParams); } } }
- 创建蓝图类
BP_GrenadeLauncher
,继承SProjectileWeapon
类,设置该蓝图类的网格体为Launcher
- 重命名
Launcher
骨骼网格体的骨骼Launcher_Skeleton
中的插槽名MuzzleFlashSocket
改为MuzzleSocket
创建子弹类蓝图
BP_GrenadeProjectile
继承Actor类,并添加发射物移动组件ProjectileMovement
,设置初始和最大速度为2000,勾选应反弹在
BP_GrenadeLauncher
榴弹发射器类中中设置发射物类为BP_GrenadeProjectile
在
BP_SCharacter
角色类中的类默认值中设置要生成的武器为榴弹发射器类BP_GrenadeLauncher
测试结果