实现武器开火动画声音特效
本文是根据B站up主TurBo强的系列视频的个人学习记录,存在部分残缺和不足,请见谅
添加武器开火动画
首先在客户端武器类中添加以下声明
//声明动画蒙太奇
UPROPERTY(EditAnywhere,BlueprintReadWrite)
UAnimMontage* ClientArmsFireAnimMontage;
//将其公开给蓝图事件图表中,由蓝图编写
UFUNCTION(BlueprintImplementableEvent, Category = "FPGunAnimation")
void PlayShootAnimation();
PlayShootAnimation()蓝图中如下
玩家类中添加以下声明,用于绑定开火输入事件
//声明手臂的动画蓝图指针
UAnimInstance* ClientArmsAnimBP;
void InputFirePressed();
void InputFireReleased();
//实现客户端武器开火逻辑
UFUNCTION(Client, Reliable)
void ClientFire();
void ClientFire_Implementation();
//实现总开火逻辑
void FireWeaponPrimary();
void StopFirePrimary();
InputComponent->BindAction(TEXT("Fire"), IE_Pressed, this, &AFPSTeachBaseCharacter::FireWeaponPrimary);
InputComponent->BindAction(TEXT("Fire"), IE_Released, this, &AFPSTeachBaseCharacter::StopFirePrimary);
void AFPSTeachBaseCharacter::InputFirePressed()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
FireWeaponPrimary();
}
}
}
void AFPSTeachBaseCharacter::InputFireReleased()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
StopFirePrimary();
}
}
}
void AFPSTeachBaseCharacter::FireWeaponPrimary()
{
/*客户端逻辑*/
//播放枪体动画
ClientFire_Implementation();
}
//获取当前武器的指针,调用当前武器的动画
void AFPSTeachBaseCharacter::ClientFire_Implementation()
{
AWeaponBaseClient* CurrentClientWeapon = GetCurrentClientFPArmsWeaponActor();
if (CurrentClientWeapon) {
CurrentClientWeapon->PlayShootAnimation();
}
//手臂播放动画蒙太奇
UAnimMontage* ClientArmsFireMontage = CurrentClientWeapon->ClientArmsFireAnimMontage;
ClientArmsAnimBP->Montage_SetPlayRate(ClientArmsFireMontage, 1);
ClientArmsAnimBP->Montage_Play(ClientArmsFireMontage);
}
//获取当前武器的类型,返回该类型武器的指针
AWeaponBaseClient* AFPSTeachBaseCharacter::GetCurrentClientFPArmsWeaponActor()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
return ClientPrimaryWeapon;
}
}
return nullptr;
}
新建一个动画蒙太奇并添加插槽
手臂动画蓝图如下,使用动画蒙太奇是为了使用其插槽,它优先级更高,在触发该事件后优先播放该动画,结束后又回到其他动画,方便混合
添加开火音效和特效
在客户端武器类中添加如下,将相应素材拖入
//声明开火声音
UPROPERTY(EditAnywhere)
USoundBase* FireSound;
//声明武器粒子特效
UPROPERTY(EditAnywhere)
UParticleSystem* MuzzleMesh;
void DisplayWeaponEffect();
//播放枪设射击效果
void AWeaponBaseClient::DisplayWeaponEffect()
{
//播放枪口粒子特效
UGameplayStatics::SpawnEmitterAttached(MuzzleMesh, WeaponMesh, TEXT("Fire_FX_Slot"), FVector::ZeroVector, FRotator::ZeroRotator, FVector::OneVector, EAttachLocation::KeepRelativeOffset, true, EPSCPoolMethod::None, true);
//播放武器声音
UGameplayStatics::PlaySound2D(GetWorld(),FireSound);
}
玩家类中ClientFire_Implementation()方法修改如下
void AFPSTeachBaseCharacter::ClientFire_Implementation()
{
//获取当前武器的指针
AWeaponBaseClient* CurrentClientWeapon = GetCurrentClientFPArmsWeaponActor();
if (CurrentClientWeapon) {
//调用当前武器的动画
CurrentClientWeapon->PlayShootAnimation();
//手臂播放动画蒙太奇
UAnimMontage* ClientArmsFireMontage = CurrentClientWeapon->ClientArmsFireAnimMontage;
ClientArmsAnimBP->Montage_SetPlayRate(ClientArmsFireMontage, 1);
ClientArmsAnimBP->Montage_Play(ClientArmsFireMontage);
//播放武器音效
CurrentClientWeapon->DisplayWeaponEffect();
}
}
添加开火时屏幕抖动
创建一个matineecamerashakebase类蓝图,如下编辑
新建一个playercontroller类,命名为MutliFPSPlayerController
public:
void PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake);
void AMutliFPSPlayerController::PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake)
{
//实现镜头抖动方法
ClientPlayCameraShake(CameraShake, 1, ECameraShakePlaySpace::CameraLocal, FRotator::ZeroRotator);;
}
客户端武器类中添加如下,将创建好的镜头抖动类蓝图拖入其中
//声明镜头抖动类型
UPROPERTY(EditAnywhere)
TSubclassOf<UCameraShakeBase> CameraShakeClass;
在玩家类中引用
//声明玩家控制类,在beginplay中拿到,从而不让在每次调用中获取
UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
AMutliFPSPlayerController* FPSPlayerController;
void AFPSTeachBaseCharacter::BeginPlay()
{
Super::BeginPlay();
StartWithKingOfWeapon();
ClientArmsAnimBP = FPArmsMesh->GetAnimInstance();
//获取playercontroller类并强制转化为AMutliFPSPlayerController类
FPSPlayerController = Cast<AMutliFPSPlayerController>(GetController());
}
void AFPSTeachBaseCharacter::ClientFire_Implementation()
{
//获取当前武器的指针
AWeaponBaseClient* CurrentClientWeapon = GetCurrentClientFPArmsWeaponActor();
if (CurrentClientWeapon) {
//调用当前武器的动画
CurrentClientWeapon->PlayShootAnimation();
//手臂播放动画蒙太奇
UAnimMontage* ClientArmsFireMontage = CurrentClientWeapon->ClientArmsFireAnimMontage;
ClientArmsAnimBP->Montage_SetPlayRate(ClientArmsFireMontage, 1);
ClientArmsAnimBP->Montage_Play(ClientArmsFireMontage);
//播放武器音效
CurrentClientWeapon->DisplayWeaponEffect();
//播放镜头抖动
FPSPlayerController->PlayerCameraShake(CurrentClientWeapon->CameraShakeClass);
}
}
所有类的全部代码展示
FPSTeachBaseCharacter类
//只编译一次,其他文件调用时不会再次编译
#pragma once
#include "CoreMinimal.h"
#include "WeaponBaseServer.h"
#include "MutliFPSPlayerController.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "FPSTeachBaseCharacter.generated.h"
UCLASS()
class FPS_API AFPSTeachBaseCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AFPSTeachBaseCharacter();
private:
#pragma region Component
//UPROPERTY目的是为了在蓝图中可读可写,但在C++中以private形式保护起来不被访问
UPROPERTY(Category = Character, visibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
//声明一个摄像机组件
UCameraComponent* PlayerCamera;
UPROPERTY(Category = Character, visibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
//声明一个手臂网格体
USkeletalMeshComponent* FPArmsMesh;
//声明手臂的动画蓝图指针
UAnimInstance* ClientArmsAnimBP;
//声明玩家控制类,在beginplay中拿到,从而不让在每次调用中获取
UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
AMutliFPSPlayerController* FPSPlayerController;
#pragma endregion
protected:
virtual void BeginPlay() override;
#pragma region InputEvent
void MoveRight(float AxisValue);
void MoveForward(float AxisValue);
void JumpAction();
void StopJumpAction();
void InputFirePressed();
void InputFireReleased();
void LowSpeedWalkAction();
void NormalSpeedWalkAction();
#pragma endregion
#pragma region Weapon
public:
//声明服务器客户端武器指针
//class 必须带,C++中两个类不能相互包含头文件,只能一个有对方的include,另一个在引用时加上class
void EquipPrimary(class AWeaponBaseServer* WeaponBaseServer);
private:
//公开给蓝图,声明当前武器类型
UPROPERTY(EditAnywhere,meta = (AllowPrivateAccess = "true"))
EWeaponType ActiveWeapon;
UPROPERTY(meta = (AllowPrivateAccess = "true"))
class AWeaponBaseServer* ServerPrimaryWeapon;
UPROPERTY(meta = (AllowPrivateAccess = "true"))
class AWeaponBaseClient* ClientPrimaryWeapon;
void StartWithKingOfWeapon();
void PurchaseWeapon(EWeaponType WeaponType);
AWeaponBaseClient* GetCurrentClientFPArmsWeaponActor();
#pragma endregion
private:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
#pragma region Fire
public:
//实现总开火逻辑
void FireWeaponPrimary();
void StopFirePrimary();
#pragma endregion
public:
#pragma region NetWork
//实现静步的网络同步
UFUNCTION(Server, Reliable, WithValidation)
void ServerLowSpeedWalkAction();
void ServerLowSpeedWalkAction_Implementation();
bool ServerLowSpeedWalkAction_Validate();
UFUNCTION(Server, Reliable, WithValidation)
void ServerNormalSpeedWalkAction();
void ServerNormalSpeedWalkAction_Implementation();
bool ServerNormalSpeedWalkAction_Validate();
//实现客户端武器装备
UFUNCTION(Client, Reliable)
void ClientEquipFPArmsPrimary();
void ClientEquipFPArmsPrimary_Implementation();
//实现客户端武器开火逻辑
UFUNCTION(Client, Reliable)
void ClientFire();
void ClientFire_Implementation();
#pragma endregion
};
#include "FPSTeachBaseCharacter.h"
AFPSTeachBaseCharacter::AFPSTeachBaseCharacter()
{
PrimaryActorTick.bCanEverTick = true;
#pragma region Component
//生成一个摄像机组件,并放置于根节点,由于PlayerCamera为指针类型,需要if防止出错
PlayerCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("PlayerCamera"));
if (PlayerCamera) {
PlayerCamera->SetupAttachment(RootComponent);
//设置摄像机上下旋转
PlayerCamera->bUsePawnControlRotation = true;
}
//生成一个手臂网格体,并放置于PlayerCamera节点之下,将属性仅自己可见设为启用
FPArmsMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FPArmsMesh"));
if (FPArmsMesh) {
FPArmsMesh->SetupAttachment(PlayerCamera);
FPArmsMesh->SetOnlyOwnerSee(true);
}
//将自身网格体设为自身不可见,设置碰撞类型
GetMesh()->SetOwnerNoSee(true);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
GetMesh()->SetCollisionObjectType(ECC_Pawn);
#pragma endregion
}
void AFPSTeachBaseCharacter::BeginPlay()
{
Super::BeginPlay();
StartWithKingOfWeapon();
ClientArmsAnimBP = FPArmsMesh->GetAnimInstance();
//获取playercontroller类并强制转化为AMutliFPSPlayerController类
FPSPlayerController = Cast<AMutliFPSPlayerController>(GetController());
}
void AFPSTeachBaseCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AFPSTeachBaseCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
InputComponent->BindAction(TEXT("Jump"), IE_Pressed, this, &AFPSTeachBaseCharacter::JumpAction);
InputComponent->BindAction(TEXT("Jump"), IE_Released, this, &AFPSTeachBaseCharacter::StopJumpAction);
InputComponent->BindAction(TEXT("LowSpeedWalk"), IE_Pressed, this, &AFPSTeachBaseCharacter::LowSpeedWalkAction);
InputComponent->BindAction(TEXT("LowSpeedWalk"), IE_Released, this, &AFPSTeachBaseCharacter::NormalSpeedWalkAction);
InputComponent->BindAction(TEXT("Fire"), IE_Pressed, this, &AFPSTeachBaseCharacter::FireWeaponPrimary);
InputComponent->BindAction(TEXT("Fire"), IE_Released, this, &AFPSTeachBaseCharacter::StopFirePrimary);
InputComponent->BindAxis(TEXT("MoveRight"), this, &AFPSTeachBaseCharacter::MoveRight);
InputComponent->BindAxis(TEXT("MoveForward"), this, &AFPSTeachBaseCharacter::MoveForward);
InputComponent->BindAxis(TEXT("Turn"), this, &AFPSTeachBaseCharacter::AddControllerYawInput);
InputComponent->BindAxis(TEXT("LookUp"), this, &AFPSTeachBaseCharacter::AddControllerPitchInput);
}
#pragma region Network
void AFPSTeachBaseCharacter::ServerLowSpeedWalkAction_Implementation()
{
GetCharacterMovement()->MaxWalkSpeed = 300;
}
bool AFPSTeachBaseCharacter::ServerLowSpeedWalkAction_Validate()
{
return true;
}
void AFPSTeachBaseCharacter::ServerNormalSpeedWalkAction_Implementation()
{
GetCharacterMovement()->MaxWalkSpeed = 600;
}
bool AFPSTeachBaseCharacter::ServerNormalSpeedWalkAction_Validate()
{
return true;
}
//客户端接收服务器端信息,在客户端生成第一人称手臂上的武器
void AFPSTeachBaseCharacter::ClientEquipFPArmsPrimary_Implementation()
{
//判断服务器端武器是否生成
if (ServerPrimaryWeapon) {
//判断客户端武器是否已经存在
if (ClientPrimaryWeapon) {
}
else {
//动态生成客户端武器对象
FActorSpawnParameters sapwnInfo;
sapwnInfo.Owner = this;
sapwnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ClientPrimaryWeapon = GetWorld()->SpawnActor<AWeaponBaseClient>(ServerPrimaryWeapon->ClientWeaponBaseBPClass, GetActorTransform(), sapwnInfo);
//将武器放置在第一人称手臂上
ClientPrimaryWeapon->K2_AttachToComponent(FPArmsMesh, TEXT("WeaponSocket"), EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, true);
}
}
}
void AFPSTeachBaseCharacter::ClientFire_Implementation()
{
//获取当前武器的指针
AWeaponBaseClient* CurrentClientWeapon = GetCurrentClientFPArmsWeaponActor();
if (CurrentClientWeapon) {
//调用当前武器的动画
CurrentClientWeapon->PlayShootAnimation();
//手臂播放动画蒙太奇
UAnimMontage* ClientArmsFireMontage = CurrentClientWeapon->ClientArmsFireAnimMontage;
ClientArmsAnimBP->Montage_SetPlayRate(ClientArmsFireMontage, 1);
ClientArmsAnimBP->Montage_Play(ClientArmsFireMontage);
//播放武器音效
CurrentClientWeapon->DisplayWeaponEffect();
//播放镜头抖动
FPSPlayerController->PlayerCameraShake(CurrentClientWeapon->CameraShakeClass);
}
}
#pragma endregion
#pragma region Action
void AFPSTeachBaseCharacter::MoveRight(float AxisValue)
{
AddMovementInput(GetActorRightVector(), AxisValue,false);
}
void AFPSTeachBaseCharacter::MoveForward(float AxisValue)
{
AddMovementInput(GetActorForwardVector(), AxisValue, false);
}
void AFPSTeachBaseCharacter::JumpAction()
{
Jump();
}
void AFPSTeachBaseCharacter::StopJumpAction()
{
StopJumping();
}
void AFPSTeachBaseCharacter::InputFirePressed()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
FireWeaponPrimary();
}
}
}
void AFPSTeachBaseCharacter::InputFireReleased()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
StopFirePrimary();
}
}
}
void AFPSTeachBaseCharacter::LowSpeedWalkAction()
{
ServerLowSpeedWalkAction();//将服务器端移速修改,实现网络同步
GetCharacterMovement()->MaxWalkSpeed = 300;//此处修改的为客户端端移速
}
void AFPSTeachBaseCharacter::NormalSpeedWalkAction()
{
ServerNormalSpeedWalkAction();
GetCharacterMovement()->MaxWalkSpeed = 600;
}
#pragma endregion
#pragma region Weapon
void AFPSTeachBaseCharacter::EquipPrimary(class AWeaponBaseServer* WeaponBaseServer)
{
//判断是否已经有武器
if (ServerPrimaryWeapon) {
}
else {
//将武器放置在第三人称人物上
ServerPrimaryWeapon = WeaponBaseServer;
ServerPrimaryWeapon->SetOwner(this);
ServerPrimaryWeapon->K2_AttachToComponent(Mesh, TEXT("Weapon_Rifle"), EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, true);
//通知客户端执行
ClientEquipFPArmsPrimary_Implementation();
}
}
void AFPSTeachBaseCharacter::StartWithKingOfWeapon()
{
//判断当前代码是否有主控权,本例即判断是否在服务器上执行
if (HasAuthority()) {
PurchaseWeapon(EWeaponType::Ak47);
}
}
//在世界中动态生成武器,调用装备武器逻辑将武器装备在人物身上
void AFPSTeachBaseCharacter::PurchaseWeapon(EWeaponType WeaponType)
{
FActorSpawnParameters sapwnInfo;
sapwnInfo.Owner = this;
sapwnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
switch (WeaponType)
{
case EWeaponType::Ak47:
{
//动态生成AK47并装备
UClass* BlueprintVar = StaticLoadClass(AWeaponBaseServer::StaticClass(), nullptr, TEXT("Blueprint'/Game/Blueprint/ServerBP_AK47.ServerBP_AK47_C'"));
AWeaponBaseServer* ServerWeapon = GetWorld()->SpawnActor<AWeaponBaseServer>(BlueprintVar, GetActorTransform(), sapwnInfo);
ServerWeapon->EquipWeapon();
EquipPrimary(ServerWeapon);
}
break;
default:
{
}
}
}
//获取当前武器的类型,返回该类型武器的指针
AWeaponBaseClient* AFPSTeachBaseCharacter::GetCurrentClientFPArmsWeaponActor()
{
switch (ActiveWeapon)
{
case EWeaponType::Ak47:
{
return ClientPrimaryWeapon;
}
}
return nullptr;
}
#pragma endregion
#pragma region Fire
void AFPSTeachBaseCharacter::FireWeaponPrimary()
{
/*客户端逻辑*/
//播放动画
ClientFire_Implementation();
}
void AFPSTeachBaseCharacter::StopFirePrimary()
{
}
#pragma endregion
WeaponBaseClient类
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include <Kismet/GameplayStatics.h>
#include "WeaponBaseClient.generated.h"
UCLASS()
class FPS_API AWeaponBaseClient : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AWeaponBaseClient();
//声明网格体
UPROPERTY(EditAnywhere,BlueprintReadWrite)
USkeletalMeshComponent* WeaponMesh;
//声明动画蒙太奇
UPROPERTY(EditAnywhere,BlueprintReadWrite)
UAnimMontage* ClientArmsFireAnimMontage;
//声明开火声音
UPROPERTY(EditAnywhere)
USoundBase* FireSound;
//声明武器粒子特效
UPROPERTY(EditAnywhere)
UParticleSystem* MuzzleMesh;
//声明镜头抖动类型
UPROPERTY(EditAnywhere)
TSubclassOf<UCameraShakeBase> CameraShakeClass;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//将其公开给蓝图事件图表中,由蓝图编写
UFUNCTION(BlueprintImplementableEvent, Category = "FPGunAnimation")
void PlayShootAnimation();
void DisplayWeaponEffect();
};
#include "WeaponBaseClient.h"
// Sets default values
AWeaponBaseClient::AWeaponBaseClient()
{
// 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;
//将网格体作为根组件且仅拥有者可见
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
RootComponent = WeaponMesh;
WeaponMesh->SetOnlyOwnerSee(true);
}
// Called when the game starts or when spawned
void AWeaponBaseClient::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AWeaponBaseClient::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
//播放枪射击效果
void AWeaponBaseClient::DisplayWeaponEffect()
{
//播放枪口粒子特效
UGameplayStatics::SpawnEmitterAttached(MuzzleMesh, WeaponMesh, TEXT("Fire_FX_Slot"), FVector::ZeroVector, FRotator::ZeroRotator, FVector::OneVector, EAttachLocation::KeepRelativeOffset, true, EPSCPoolMethod::None, true);
//播放武器声音
UGameplayStatics::PlaySound2D(GetWorld(),FireSound);
}
WeaponBaseServer类
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "WeaponBaseClient.h"
#include "Components/SphereComponent.h"
#include "WeaponBaseServer.generated.h"
//枚举一些武器
UENUM()
enum class EWeaponType :uint8
{
Ak47 UMETA(DisplayName = "AK47"),
DesertEagle UMETA(DisplayNmae = "DesertEagle")
};
UCLASS()
class FPS_API AWeaponBaseServer : public AActor
{
GENERATED_BODY()
public:
AWeaponBaseServer();
//声明一个武器类型,表示武器类型
UPROPERTY(EditAnywhere)
EWeaponType KindOfWeapon;
//声明网格体
UPROPERTY(EditAnywhere)
USkeletalMeshComponent* WeaponMesh;
//声明圆形碰撞体,用于碰撞检测
UPROPERTY(EditAnywhere)
USphereComponent* SphereCollision;
//声明客户端武器蓝图类,用于动态生成第一人称武器对象
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<AWeaponBaseClient> ClientWeaponBaseBPClass;
//碰撞触发事件
UFUNCTION()
void OnOtherBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//装备武器时改变部分设置
UFUNCTION()
void EquipWeapon();
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "WeaponBaseServer.h"
#include <FPSTeachBaseCharacter.h>
// Sets default values
AWeaponBaseServer::AWeaponBaseServer()
{
PrimaryActorTick.bCanEverTick = true;
//创建网格体并将其设置为根组件,将碰撞体设置为子组件
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
RootComponent = WeaponMesh;
SphereCollision = CreateDefaultSubobject<USphereComponent>(TEXT("SphereCollision"));
SphereCollision->SetupAttachment(RootComponent);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
WeaponMesh->SetCollisionObjectType(ECC_WorldStatic);
SphereCollision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
SphereCollision->SetCollisionObjectType(ECC_WorldDynamic);
//设置仅拥有者不可见,启用重力,模拟物理
WeaponMesh->SetOwnerNoSee(true);
WeaponMesh->SetEnableGravity(true);
WeaponMesh->SetSimulatePhysics(true);
SphereCollision->OnComponentBeginOverlap.AddDynamic(this,&AWeaponBaseServer::OnOtherBeginOverlap);
//允许当前Actor可以被服务器复制
SetReplicates(true);
}
//武器被人物碰撞时完成捡起逻辑
void AWeaponBaseServer::OnOtherBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//检测碰撞的武器是否为玩家,如果是则这个强制转换成功,FPSCharacter不为空
AFPSTeachBaseCharacter* FPSCharacter = Cast<AFPSTeachBaseCharacter>(OtherActor);
if (FPSCharacter) {
EquipWeapon();
FPSCharacter->EquipPrimary(this);
}
}
//武器被人物碰撞捡起时取消碰撞和模拟物理和重力
void AWeaponBaseServer::EquipWeapon()
{
WeaponMesh->SetEnableGravity(false);
WeaponMesh->SetSimulatePhysics(false);
SphereCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
// Called when the game starts or when spawned
void AWeaponBaseServer::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AWeaponBaseServer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
MutliFPSPlayerController类
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MutliFPSPlayerController.generated.h"
/**
*
*/
UCLASS()
class FPS_API AMutliFPSPlayerController : public APlayerController
{
GENERATED_BODY()
public:
//声明一个镜头抖动函数
void PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MutliFPSPlayerController.h"
void AMutliFPSPlayerController::PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake)
{
//实现镜头抖动方法
ClientPlayCameraShake(CameraShake, 1, ECameraShakePlaySpace::CameraLocal, FRotator::ZeroRotator);;
}
MutliFPSPlayerController类
```c
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MutliFPSPlayerController.generated.h"
/**
*
*/
UCLASS()
class FPS_API AMutliFPSPlayerController : public APlayerController
{
GENERATED_BODY()
public:
//声明一个镜头抖动函数
void PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MutliFPSPlayerController.h"
void AMutliFPSPlayerController::PlayerCameraShake(TSubclassOf<UCameraShakeBase> CameraShake)
{
//实现镜头抖动方法
ClientPlayCameraShake(CameraShake, 1, ECameraShakePlaySpace::CameraLocal, FRotator::ZeroRotator);;
}