一、目标
当人物模型和武器模型重叠时显示小窗口,按E键时拾取武器,当拾取到武器时窗口不可见,当人物靠近其他人物时(其他客户端/服务器)窗口同样不可见,在具有Authority权限的PC上同理
二、实现过程
1.创建一个武器的类命名为Weapon,在头文件中定义一个骨骼网格类(USkeletalMeshComponent)的指针,声明一个球形组件类(USphereComponent)的指针,创建一个枚举类型,设置对应的枚举属性
xxx.h
// 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;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
private:
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties") // 设置在任何地方都可以看见,类别设置为武器属性
USkeletalMeshComponent* WeapomMesh; /* 骨骼网格 */
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
class USphereComponent* AreaSphere; /* 球形组件 判断人物模型和武器模型是否重叠 */
UPROPERTY(VisibleAnywhere)
EWeaponState WeaponState;
};
xxx.cpp : 在cpp文件中将骨骼网格指针和球形指针初始化并对碰撞设置,在beginplay函数中设置当前是否在服务器上,如果在设置碰撞参数
// 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);
}
// 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);
}
}
// Called every frame
void AWeapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
2.创建对应的武器类的蓝图
3.在蓝图中添加武器,双击打开蓝图类,点击左侧栏中的Weapon Mesh,在右侧栏的细节中找到网格体,在网格体资产中选择武器资产,选择后可能不像下图所示,通过调整武器资产的位置找到合适的放置位置,调整位置在中间界面的上方的按钮处
4.点击左侧栏的Area Sphere 在右侧栏中将球体半径放大到覆盖整个武器资产
5.编译保存后拖拽蓝图到界面中放置武器