一、目标拿取地上的武器
1.创建武器组件的类,父类时ActorComponent
2.打开项目设置->找到输入->在操作映射中添加一个按键(我添加了E键)
3.在人物类中定义一个武器组件的指针并在构造中初始化,将指针设置为可复制(只有这个组件可以这样设置),在定义一个和操作映射绑定的回调函数,重写访问战斗组件的函数
//头文件中
//定义装备武器的回调函数
void EquipButtonPressed();
//变量
UPROPERTY(VisibleAnywhere)
class UCombatComponent* Combat;
/** 可以访问战斗组件,它将到这个时候构建 */
virtual void PostInitializeComponents() override;
//构造函数中
/** 战斗组件 */
Combat = CreateDefaultSubobject<UCombatComponent>(TEXT("CombatComponent"));
/** SetIsReplicated将组件设置为复制组件 */
Combat->SetIsReplicated(true);
/** 战斗组件 */
//绑定
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
void ABlasterCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (Combat)
{
Combat->Character = this;
}
}
4.在武器组件类中需要一个人物的指针知道是哪个角色,需要一个武器的指针装备看哪个武器武器组件代码如下,setWeaponState在后面说明了在哪设置
xxx.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CombatComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BLASTER_API UCombatComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UCombatComponent();
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
friend class ABlasterCharacter;
/** 装备武器函数 */
void EquipWeapon(class AWeapon* WeaponToEquip);
protected:
// Called when the game starts
virtual void BeginPlay() override;
private:
class ABlasterCharacter* Character;
AWeapon* EquippedWeapon;
public:
};
xxx.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "CombatComponent.h"
#include "Components/SphereComponent.h"
#include "Blaster/Weapon/Weapon.h"
#include "Blaster/Character/BlasterCharacter.h"
#include "Engine/SkeletalMeshSocket.h"
// Sets default values for this component's properties
UCombatComponent::UCombatComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = false;
// ...
}
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
/** Character类指针在ABlasterCharacter::PostInitializeComponents()获得 */
if (Character == nullptr || WeaponToEquip == nullptr)
return;
/** 设置武器状态 */
EquippedWeapon = WeaponToEquip;
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
/** 获得在骨骼网格体中设置的插座,通过获得mesh去获得 */
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
/** 武器和角色不同武器没有所有者,需要在某个角色拾取到武器时将所有者设置 */
/** 设置武器的所有者是角色 */
EquippedWeapon->SetOwner(Character);
EquippedWeapon->ShowPickupWidget(false);
EquippedWeapon->GetAreaSphere()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
// Called when the game starts
void UCombatComponent::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
5.实现装备函数(EquipWeapon)前需要在人物骨骼蓝图类中在骨骼网络创建新的插座
1.双击打开角色骨骼蓝图(一般放在Mesh文件夹中)
2.找到对应的骨骼单机右键选择添加插槽
3.将插槽重命名
4.选择装备的武器查看外观右键节点->添加预览资产->选择资产
5.查看动画将武器武器位置调整上方是参考的动画,下方是打开的骨骼蓝图
6.设置武器的状态
//武器类H
void SetWeaponState(EWeaponState state);
FORCEINLINE USphereComponent* GetAreaSphere() const { return AreaSphere; };
//武器CPP
void AWeapon::SetWeaponState(EWeaponState state)
{
WeaponState = state;
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
二、 实现RPC函数
在人物的C++类中定义如下函数在CPP中实现函数名_Implementation的版本主要功能是告诉服务器装备了武器
//H
/* 定义RPC函数使用UFUNCTION红定义服务端可靠的RPC函数,声明的RPC函数不用实现
需要实现函数名_Implementation的函数*/
UFUNCTION(Server,Reliable)
void ServerEquipButtonPressed();
//CPP
void ABlasterCharacter::ServerEquipButtonPressed_Implementation()
{
if (Combat)
{
Combat->EquipWeapon(OverLappingWeapon);
}
}
在人物C++类中绑定的按键的回调函数中实现,EquipButtonPressed在beginplay函数中进行了对应的操作映射
void ABlasterCharacter::EquipButtonPressed()
{
//if (Combat && HasAuthority())
//{
// Combat->EquipWeapon(OverLappingWeapon);
//}
if (Combat)
{
if (HasAuthority())
{
Combat->EquipWeapon(OverLappingWeapon);
}
else
{
ServerEquipButtonPressed();
}
}
}
在武器类中定义武器状态的回调函数,当装备武器后不会在对碰撞进行判断。
//H
UPROPERTY(ReplicatedUsing = OnRep_WeaponState, VisibleAnywhere, Category = "Weapon Properties")
EWeaponState WeaponState;
UFUNCTION()
void OnRep_WeaponState();
//CPP
void AWeapon::OnRep_WeaponState()
{
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
现在我只判断了装备武器的状态,当人物装备武器后移动到其他客户端的人物时其他客户端不会有碰撞判断
//H
void SetWeaponState(EWeaponState state);
FORCEINLINE USphereComponent* GetAreaSphere() const { return AreaSphere; };
//CPP
void AWeapon::SetWeaponState(EWeaponState state)
{
WeaponState = state;
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
三、装备武器、人物、武器组件、武器类的完整C++代码
人物C++头文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BlasterCharacter.generated.h"
UCLASS()
class BLASTER_API ABlasterCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ABlasterCharacter();
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
/** 要标记要复制的内容,我们使用 UPROPERTY 中的 Replicated 说明符。
在将某个内容标记为 Replicated 之后,我们必须定义一个名为 GetLifetimeReplicatedProps 的新函数 */
/** 返回用于网络复制的属性,这需要被所有具有本机复制属性的 actor 类覆盖 */
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
/** 可以访问战斗组件,它将到这个时候构建 */
virtual void PostInitializeComponents() override;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
/* 人物移动函数 */
void MoveForward(float Value);
void MoveRight(float Value);
void Turn(float Value);
void LookUp(float Value);
void EquipButtonPressed();
private:
/** 弹簧臂组件类声明 属性设置为在任何地方可视 类别是摄像机 */
UPROPERTY(VisibleAnywhere, Category = Camera)
class USpringArmComponent* CameraBoom;
/** 摄像机类声明 属性设置为在任何地方可视 类别是摄像机 */
UPROPERTY(VisibleAnywhere, Category = Camera)
class UCameraComponent* FollowCamera;
UPROPERTY(EditAnywhere,BlueprintReadOnly,meta = (AllowPrivateAccess = "true"))
class UWidgetComponent* OverheadWidget;
/** 属性设置为变量可重复 */
//UPROPERTY(Replicated)
/** 使用复制指定复制函数,通知OnRep_OverLappingWeapon调用 */
UPROPERTY(ReplicatedUsing = OnRep_OverLappingWeapon)
class AWeapon* OverLappingWeapon;
UFUNCTION()
void OnRep_OverLappingWeapon(AWeapon* LastWeapon);
UPROPERTY(VisibleAnywhere)
class UCombatComponent* Combat;
/* 定义RPC函数使用UFUNCTION红定义服务端可靠的RPC函数,声明的RPC函数不用实现
需要实现函数名_Implementation的函数*/
UFUNCTION(Server,Reliable)
void ServerEquipButtonPressed();
public:
//FORCEINLINE void SetOverlappingWeapon(AWeapon* Weapon) { OverLappingWeapon = Weapon; };
void SetOverlappingWeapon(AWeapon* Weapon);
};
人物C++源文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "BlasterCharacter.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/WidgetComponent.h"
#include "Net/UnrealNetwork.h"
#include "Blaster/Weapon/Weapon.h"
#include "Blaster/BlasterComponents/CombatComponent.h"
// Sets default values
ABlasterCharacter::ABlasterCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));/** 创建类 */
CameraBoom->SetupAttachment(GetMesh());/** SetupAttachment()将弹簧臂固定在网格上 GetMesh()获得角色的网格(胶囊体) */
CameraBoom->TargetArmLength = 600.f;/** 设置臂长 */
CameraBoom->bUsePawnControlRotation = true;/** 是否控制旋转 */
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
/** 设置附件 将摄像机连接到弹簧臂上,通过USpringArmComponent的指针和USpringArmComponent的名字USpringArmComponent::SocketName*/
FollowCamera->SetupAttachment(CameraBoom,USpringArmComponent::SocketName);
/** 跟随摄像头无需使用旋转 旋转在CameraBoom CameraBoom是FollowCamera的组件 */
FollowCamera->bUsePawnControlRotation = false;
bUseControllerRotationYaw = false; /** 不希望角色和控制器一起旋转 */
GetCharacterMovement()->bOrientRotationToMovement = true; /** 使角色按照原有的方向运动 */
OverheadWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("OverheadWidget"));
OverheadWidget->SetupAttachment(RootComponent);
/** 战斗组件 */
Combat = CreateDefaultSubobject<UCombatComponent>(TEXT("CombatComponent"));
/** SetIsReplicated将组件设置为复制组件 */
Combat->SetIsReplicated(true);
/** 战斗组件 */
}
// Called every frame
void ABlasterCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//if (OverLappingWeapon)
//{
// OverLappingWeapon->ShowPickupWidget(true);
//}
}
// Called to bind functionality to input
void ABlasterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
/* 绑定动作映射 */
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);/* 具有一个输入的事件IE_Pressed */
PlayerInputComponent->BindAction("Equip", IE_Pressed, this, &ABlasterCharacter::EquipButtonPressed);
/* 绑定轴映射 */
PlayerInputComponent->BindAxis("MoveForward",this,&ABlasterCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ABlasterCharacter::MoveRight);
PlayerInputComponent->BindAxis("Turn", this, &ABlasterCharacter::Turn);
PlayerInputComponent->BindAxis("LookUp", this, &ABlasterCharacter::LookUp);
}
void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
/** 指定了具有复制变量的类 和 复制的变量是哪个 */
DOREPLIFETIME_CONDITION(ABlasterCharacter, OverLappingWeapon, COND_OwnerOnly);
}
void ABlasterCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (Combat)
{
Combat->Character = this;
}
}
// Called when the game starts or when spawned
void ABlasterCharacter::BeginPlay()
{
Super::BeginPlay();
}
void ABlasterCharacter::MoveForward(float Value)
{
/* Controller理解成一个人物的控制器 */
if (Controller != nullptr && Value != 0.f)
{
/* 获得旋转方向 */
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
/* 从旋转方向创建旋转矩阵FRotationMatrix(YawRotation) 称其为单位轴GetUnitAxis(EAxis::X),返回一个F向量 */
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X));
/*沿给定世界方向向量(通常归一化)添加运动输入,按 'ScaleValue' 缩放。
如果 ScaleValue < 0,则移动方向相反。Base Pawn 类不会自动应用移动,
在 Tick 事件中,这取决于用户是否这样做。Character 和 DefaultPawn 等子类会自动处理此输入并移动*/
AddMovementInput(Direction, Value);
}
}
void ABlasterCharacter::MoveRight(float Value)
{
if (Controller != nullptr && Value != 0.f)
{
const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y));
/*沿给定世界方向向量(通常归一化)添加运动输入,按 'ScaleValue' 缩放。
如果 ScaleValue < 0,则移动方向相反。Base Pawn 类不会自动应用移动,
在 Tick 事件中,这取决于用户是否这样做。Character 和 DefaultPawn 等子类会自动处理此输入并移动*/
AddMovementInput(Direction, Value);
}
}
void ABlasterCharacter::Turn(float Value)
{
/*如果是本地 PlayerController,
则将输入(影响 Yaw)添加到控制器的 ControlRotation。
此值乘以 PlayerController 的 InputYawScale 值。*/
AddControllerYawInput(Value);
}
void ABlasterCharacter::LookUp(float Value)
{
/*如果它是本地 PlayerController,
则将输入(影响 Pitch)添加到控制器的 ControlRotation。
此值乘以 PlayerController 的 InputPitchScale 值*/
AddControllerPitchInput(Value);
}
void ABlasterCharacter::EquipButtonPressed()
{
//if (Combat && HasAuthority())
//{
// Combat->EquipWeapon(OverLappingWeapon);
//}
if (Combat)
{
if (HasAuthority())
{
Combat->EquipWeapon(OverLappingWeapon);
}
else
{
ServerEquipButtonPressed();
}
}
}
void ABlasterCharacter::OnRep_OverLappingWeapon(AWeapon* LastWeapon)
{
if (OverLappingWeapon)
{
OverLappingWeapon->ShowPickupWidget(true);
}
if (LastWeapon)
{
LastWeapon->ShowPickupWidget(false);
}
}
void ABlasterCharacter::ServerEquipButtonPressed_Implementation()
{
if (Combat)
{
Combat->EquipWeapon(OverLappingWeapon);
}
}
void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
{
if (OverLappingWeapon)
{
OverLappingWeapon->ShowPickupWidget(false);
}
OverLappingWeapon = Weapon;
if (IsLocallyControlled())
{
if (OverLappingWeapon)
{
OverLappingWeapon->ShowPickupWidget(true);
}
}
}
武器C++类头文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapon.generated.h"
// 一个枚举类 作为蓝图的类型
UENUM(BlueprintType) /* 可以将此枚举用作蓝图中的一种类型 */
enum class EWeaponState : uint8
{
EWS_Initial UMETA(DisplayName = "Initial State"),
EWS_Equipped UMETA(DisplayName = "Equipped"),
EWS_Dropped UMETA(DisplayName = "Dropped"),
EWS_MAX UMETA(DisplayName = "DefaultMAX")
};
UCLASS()
class BLASTER_API AWeapon : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AWeapon();
// Called every frame
virtual void Tick(float DeltaTime) override;
/** 要标记要复制的内容,我们使用 UPROPERTY 中的 Replicated 说明符。
在将某个内容标记为 Replicated 之后,我们必须定义一个名为 GetLifetimeReplicatedProps 的新函数 */
/** 返回用于网络复制的属性,这需要被所有具有本机复制属性的 actor 类覆盖 */
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
/** 设置何时显示提示框 是否角色和武器重叠 */
void ShowPickupWidget(bool bShowWidget);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UFUNCTION()
virtual void OnSphereOverlap(
UPrimitiveComponent* OverlappedComponent,// UPrimitiveComponent重叠组件类
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult //碰撞检测结果
);
/** 重叠结束 */
UFUNCTION()
virtual void OnSphereEndOverlap(
UPrimitiveComponent* OverlappedComponent,// UPrimitiveComponent重叠组件类
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex
);
public:
private:
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties") // 设置在任何地方都可以看见,类别设置为武器属性
USkeletalMeshComponent* WeapomMesh; /* 骨骼网格 */
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
class USphereComponent* AreaSphere; /* 球形组件 判断人物模型和武器模型是否重叠 */
UPROPERTY(ReplicatedUsing = OnRep_WeaponState, VisibleAnywhere, Category = "Weapon Properties")
EWeaponState WeaponState;
UFUNCTION()
void OnRep_WeaponState();
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
class UWidgetComponent* PickWidget; /* 界面组件 */
public:
void SetWeaponState(EWeaponState state);
FORCEINLINE USphereComponent* GetAreaSphere() const { return AreaSphere; };
};
武器C++类源文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "Weapon.h"
#include "Components/SphereComponent.h"
#include "Components/WidgetComponent.h"
#include "Net/UnrealNetwork.h"
#include "Blaster/Character/BlasterCharacter.h"
// Sets default values
AWeapon::AWeapon()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
bReplicates = true; //将执行组件复制到远程计算机 //由于想要将武器在服务器上判断是否碰撞,需要将武器作为一个actor复制到服务器上
WeapomMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh")); //创建骨骼网格提成员,名字是WeaponMesh
//WeapomMesh->SetupAttachment(RootComponent); //一个组件附加到另一个组件上
SetRootComponent(WeapomMesh);//设置根组件
// 当拿起武器时设置为完全阻止SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block)
// 当丢掉武器时设置为设置为忽略,即没有碰撞SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore)
// 当武器在地上时设置无碰撞SetCollisionEnabled(ECollisionEnabled::NoCollision)
WeapomMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block); //将碰撞响应设置为完全阻止
WeapomMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);//当放下武器时将任务设置为忽略,即没有碰撞
WeapomMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);//设置无碰撞
// 想在服务器上检测当前碰撞区域是否和角色重叠
// 将碰撞区域设置为SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore)不要碰撞
// 设置为在所有机上都是无碰撞SetCollisionEnabled(ECollisionEnabled::NoCollision);
// 在服务器上设置为启用碰撞 不在构造函数中设置,在游戏开始时BeginPlay()设置
AreaSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AreaSphere"));
AreaSphere->SetupAttachment(RootComponent);
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
PickWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("PickUpWidget"));
PickWidget->SetupAttachment(RootComponent);
}
void AWeapon::ShowPickupWidget(bool bShowWidget)
{
if (PickWidget)
{
PickWidget->SetVisibility(bShowWidget);
}
}
// Called when the game starts or when spawned
void AWeapon::BeginPlay()
{
Super::BeginPlay();
// (GetLocalRole() == ENetRole::ROLE_Authority) == HasAuthority() 作用相同
// GetLocalRole() 获得本地角色 ENetRole::ROLE_Authority 是否具有角色权威
if ( HasAuthority() )
{
//如果当前是在服务器上,将碰撞设置为物理碰撞
AreaSphere->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
//设置当前的碰撞是胶囊碰撞ECC_Pawn,并将碰撞设置为重叠ECR_Overlap
AreaSphere->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn,ECollisionResponse::ECR_Overlap);
// 绑定一个重叠区域处理函数
AreaSphere->OnComponentBeginOverlap.AddDynamic(this,&AWeapon::OnSphereOverlap);
AreaSphere->OnComponentEndOverlap.AddDynamic(this, &AWeapon::OnSphereEndOverlap);
}
if (PickWidget)
{
PickWidget->SetVisibility(false);
}
}
void AWeapon::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(OtherActor);
if (BlasterCharacter /* && PickWidget */ )
{
//PickWidget->SetVisibility(true);
BlasterCharacter->SetOverlappingWeapon(this);
}
}
void AWeapon::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(OtherActor);
if (BlasterCharacter /* && PickWidget */)
{
//PickWidget->SetVisibility(true);
BlasterCharacter->SetOverlappingWeapon(nullptr);
}
}
void AWeapon::OnRep_WeaponState()
{
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
void AWeapon::SetWeaponState(EWeaponState state)
{
WeaponState = state;
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
// Called every frame
void AWeapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
/* DOREPLIFETIME复制属性的宏 */
DOREPLIFETIME(AWeapon, WeaponState);
}
武器组件C++类头文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CombatComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BLASTER_API UCombatComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UCombatComponent();
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
friend class ABlasterCharacter;
/** 装备武器函数 */
void EquipWeapon(class AWeapon* WeaponToEquip);
protected:
// Called when the game starts
virtual void BeginPlay() override;
private:
class ABlasterCharacter* Character;
AWeapon* EquippedWeapon;
public:
};
武器组件C++类源文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "CombatComponent.h"
#include "Components/SphereComponent.h"
#include "Blaster/Weapon/Weapon.h"
#include "Blaster/Character/BlasterCharacter.h"
#include "Engine/SkeletalMeshSocket.h"
// Sets default values for this component's properties
UCombatComponent::UCombatComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = false;
// ...
}
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
/** Character类指针在ABlasterCharacter::PostInitializeComponents()获得 */
if (Character == nullptr || WeaponToEquip == nullptr)
return;
/** 设置武器状态 */
EquippedWeapon = WeaponToEquip;
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
/** 获得在骨骼网格体中设置的插座,通过获得mesh去获得 */
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(EquippedWeapon, Character->GetMesh());
}
/** 武器和角色不同武器没有所有者,需要在某个角色拾取到武器时将所有者设置 */
/** 设置武器的所有者是角色 */
EquippedWeapon->SetOwner(Character);
EquippedWeapon->ShowPickupWidget(false);
EquippedWeapon->GetAreaSphere()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
// Called when the game starts
void UCombatComponent::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}