实现武器开火动画声音特效

实现武器开火动画声音特效

本文是根据B站up主TurBo强的系列视频的个人学习记录,存在部分残缺和不足,请见谅

添加武器开火动画

首先在客户端武器类中添加以下声明

//声明动画蒙太奇
	UPROPERTY(EditAnywhere,BlueprintReadWrite)
		UAnimMontage* ClientArmsFireAnimMontage;
//将其公开给蓝图事件图表中,由蓝图编写
	UFUNCTION(BlueprintImplementableEvent, Category = "FPGunAnimation")
		void PlayShootAnimation();

PlayShootAnimation()蓝图中如下

image-20230920113928408

玩家类中添加以下声明,用于绑定开火输入事件


//声明手臂的动画蓝图指针
	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;
}

新建一个动画蒙太奇并添加插槽

image-20230920115821409

手臂动画蓝图如下,使用动画蒙太奇是为了使用其插槽,它优先级更高,在触发该事件后优先播放该动画,结束后又回到其他动画,方便混合

image-20230920120043039

添加开火音效和特效

在客户端武器类中添加如下,将相应素材拖入

//声明开火声音
	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类蓝图,如下编辑

image-20230920153704683

新建一个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);;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值