UE5学习笔记9-创建一个小窗口提示人物是否和武器重叠

news2024/11/15 16:45:06

一、目标

        创建一个UsrWidget去显示如果人物和武器重叠显示窗口,如果人物和武器不重叠将窗口隐藏

二、创建窗口并显示

        1.创建一个窗口蓝图类,命名为PickUpWidget,这个蓝图类不需要C++类,在对应文件夹中单机右键选择用户界面的控件蓝图

        2.在界面蓝图类中添加一个text控件,将字体设置为front,居中显示,可以在右侧栏找到对应设置,将控件命名为PickUpText

         3.在之前创建的武器的C++类中绑定text控件 ,在头文件中声明一个界面组件的指针在cpp文件中的构造函数中初始化这个指针

// 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;

	/** 设置何时显示提示框 是否角色和武器重叠 */
	void ShowPickupWidget(bool bShowWidget);
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, Category = "Weapon Properties")
	EWeaponState WeaponState;

	UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
	class UWidgetComponent* PickWidget; /* 界面组件 */
};
// 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);
	}
}

// Called every frame
void AWeapon::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

         4.编译代码,打开武器的蓝图类可以在左侧栏看见刚添加的组件,选中当前组件在右侧谢绝栏中的用户界面下拉框中将空间改成屏幕,将空间类选择成刚才创建的pickupwidget的蓝图类的名字,将以所需大小绘制勾选,最后将提示框放到你想放到的位置上,如图。

        5.显示完成可以运行查看,若没有按照正确的位置显示请查看武器类的构造函数中这两行代码是否有设置跟组件,请将武器的骨骼设置为跟组件将另一行代码注释或删除

        WeapomMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh")); //创建骨骼网格提成员,名字是WeaponMesh
    //WeapomMesh->SetupAttachment(RootComponent); //一个组件附加到另一个组件上
    SetRootComponent(WeapomMesh);//设置根组件 

三、创建一个重叠部分判断的功能

        1.在头文件中添加一个函数用来判断是否发生重叠

// 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;

	/** 设置何时显示提示框 是否角色和武器重叠 */
	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	//碰撞检测结果
	);

public:


private:
	UPROPERTY(VisibleAnywhere, Category = "Weapon Properties") // 设置在任何地方都可以看见,类别设置为武器属性
	USkeletalMeshComponent* WeapomMesh;	/* 骨骼网格 */
	UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
	class USphereComponent* AreaSphere; /* 球形组件 判断人物模型和武器模型是否重叠 */

	UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
	EWeaponState WeaponState;

	UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
	class UWidgetComponent* PickWidget; /* 界面组件 */
};
// 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);
    }
    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);
	}
}


// Called every frame
void AWeapon::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

四、当前效果

        在服务器上发生重叠可以看见提示,在客户端中看不见,当客户端发生重叠时客户端看不见提示在服务器上可以看见

五、创建一个当结束重叠时将提示款设置不可见

        一点说明:定义一个函数OnSphereEndOverlap代表结束重叠将会去实现的功能,在beginplay函数中通过之前定义的class USphereComponent* AreaSphere;指针调用OnComponentBeginOverlap 去绑定重叠开始的函数,调用OnComponentEndOverlap去绑定重叠结束的函数,参数可以在OnComponentBeginOverlap/OnComponentEndOverlap通过F12转到定义去查看。

        定义中FComponentBeginOverlapSignature OnComponentBeginOverlap;对FComponentBeginOverlapSignature转定义DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( FComponentBeginOverlapSignature, UPrimitiveComponent, OnComponentBeginOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult);可以看见是一个宏函数有10个参数(为啥我有7个现在我也没整明白,视频中是这么写的,之后在研究)

        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;
    /** 要标记要复制的内容,我们使用 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
	);

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);
};

        xxx.cpp

// 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);

}

        六、当前的问题

        可能会有测试游戏时在服务器上人物与武器重叠时会有提示框不会在客户端显示,重新测试当客户端与武器重叠时当前客户端和服务器上都会有提示,这是因为在重叠时武器的状态会改变,之前在人物的C++类中定义的武器的变量存在服务器一份客户端一份,客户端的武器变量改变时服务器也会发生改变,可以在人物C++中加判断

        七、人物C++类代码

        1.说明

        在头文件中添加了武器类的指针和当状态改变时的回调函数同时重写GetLifetimeReplicatedProps函数指定复制变量的类和复制的变量,同时设置了指定的条件

        2.ReplicatedUsing = OnReq_XX:作用是绑定了OnReq_XX回调函数,在当前变量改变时调用,也说明当前变量是一个可复制的变量

        3.DOREPLIFETIME_CONDITION的作用是:/** 指定了具有复制变量的类 和 复制的变量是哪个 , 复制的条件是什么  */DOREPLIFETIME_CONDITION(ABlasterCharacter, OverLappingWeapon, COND_OwnerOnly);若是DOREPLIFETIME宏则只有(ABlasterCharacter, OverLappingWeapon)两个参数可能会在客户端与武器重叠时,服务器上也会有相同的显示

/** 要标记要复制的内容,我们使用 UPROPERTY 中的 Replicated 说明符。 
在将某个内容标记为 Replicated 之后,我们必须定义一个名为 GetLifetimeReplicatedProps 的新函数 */
/** 返回用于网络复制的属性,这需要被所有具有本机复制属性的 actor 类覆盖 */
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

/** 属性设置为变量可重复 */
//UPROPERTY(Replicated)
/** 使用复制指定复制函数,通知OnRep_OverLappingWeapon调用 */
UPROPERTY(ReplicatedUsing = OnRep_OverLappingWeapon)
class AWeapon* OverLappingWeapon;

UFUNCTION()
void OnRep_OverLappingWeapon(AWeapon* LastWeapon);
void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	/** 指定了具有复制变量的类 和 复制的变量是哪个  */
	DOREPLIFETIME_CONDITION(ABlasterCharacter, OverLappingWeapon, COND_OwnerOnly);
}

void ABlasterCharacter::OnRep_OverLappingWeapon(AWeapon* LastWeapon)
{
	if (OverLappingWeapon)
	{
		OverLappingWeapon->ShowPickupWidget(true);
	}

	if (LastWeapon)
	{
		LastWeapon->ShowPickupWidget(false);
	}
}

 

        xxx.h 

// 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;

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);

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);

public:	
	//FORCEINLINE void SetOverlappingWeapon(AWeapon* Weapon) { OverLappingWeapon = Weapon; };
	void SetOverlappingWeapon(AWeapon* Weapon);
};

        xxx.cpp

// 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);
}

// 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->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);
}

// 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::OnRep_OverLappingWeapon(AWeapon* LastWeapon)
{
	if (OverLappingWeapon)
	{
		OverLappingWeapon->ShowPickupWidget(true);
	}

	if (LastWeapon)
	{
		LastWeapon->ShowPickupWidget(false);
	}
}

void ABlasterCharacter::SetOverlappingWeapon(AWeapon* Weapon)
{
	if (OverLappingWeapon)
	{
		OverLappingWeapon->ShowPickupWidget(false);
	}
	OverLappingWeapon = Weapon;

	if (IsLocallyControlled())
	{
		if (OverLappingWeapon)
		{
			OverLappingWeapon->ShowPickupWidget(true);
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2041912.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

torch分布式训练DataParallel和DistributedDataParallel

Pytorch 分布式训练主要有两种方式&#xff1a; torch.nn.DataParallel > 简称 DP torch.nn.parallel.DistributedDataParallel > 简称DDP 其中 DP 只用于单机多卡&#xff0c;DDP 可以用于单机多卡也可用于多机多卡&#xff0c;后者现在也是Pytorch训练的主流用法&…

维基知识库系统Wiki.js本地Linux环境部署并配置公网地址远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

所生成项目的处理器架构“MSIL”与引用“***”的处理器架构“x86”不匹配。

在c#工程里新建了一个类库&#xff0c;编译的场合出现以下警告&#xff1a;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(2401,5): warning MSB3270: 所生成项目的处理器架构“MSIL”与引用“…

单链表leetcode刷题/下(C语言版)

目录 题目1&#xff1a;返回倒数第k个结点 题目2&#xff1a;回文链表 题目3&#xff1a;相交链表 题目1&#xff1a;返回倒数第k个结点 如图&#xff0c;该题使用到了快慢指针的思想。先定义两个指针&#xff0c;同时指向链表的首元结点&#xff0c;然后让fast指针向前先走…

秋招突击——8/15——知识补充——Socket通信

文章目录 引言正文基于TCP协议的Socket通信基于UDP协议的Socket通信服务端如何接收更多项目多进程多线程IO多路复用select轮询IO多路复用epoll事件通知 使用Socket实现同一个机器上的多线程通信服务端创建对应socket监听端口客户端发起对应的连接请求 总结 引言 上次面试腾讯的…

Qt篇——:-1: error: collect2.exe: error: ld returned 1 exit status错误

错误如图所示&#xff1a; 出现这个错误的时候我们点击下面的 [4 编译输出]&#xff0c;可以看到具体的编译报错信息&#xff0c;找到对应的错误进行解决即可。 这里举个例子&#xff0c;比如最常见的一种错误原因是&#xff1a;multiple definition of ......。这代表着你重复…

视频号小店升级微信小店,视频号直播电商将迎来新变化!

8月12日&#xff0c;腾讯发布《视频号小店升级为微信小店的公告》-意见征集通知&#xff0c;及其相关规则通知。 ▲ 图片来源&#xff1a;腾讯公告 公告称&#xff1a;腾讯计划自08月25日起&#xff0c;正式支持商家将视频号小店升级成微信小店。 微信小店将进一步简化商家入驻…

C++语言基础|循环结构

C语言基础|循环结构 循环1. for语句2. while循环3. do…while语句 循环 在程序中&#xff0c;常常需要重复地执行某些操作。C提供了3种循环语句&#xff1a;for语句、while语句和do-while语句。在循环语句中&#xff0c;重复执行的操作叫做循环体。循环体可以是单条语句、块语…

一把手在精益生产的实施中扮演着怎样的角色?

在探讨一把手在精益生产实施中的角色时&#xff0c;我们不得不深入剖析精益生产的核心要义及其在现代企业管理中的重要性。精益生产作为一种以提高效率、降低成本、增加价值为目标的生产管理方式&#xff0c;其核心理念包括价值导向、流动制造、消除浪费、持续改进等。在这个过…

ubuntu服务器部署的mysql本地连不上的问题

试过了网上的所有方法,都连不上,可以执行: SELECT user, host, plugin FROM mysql.user WHERE user root; 查一下:plungin这个连接插件是不是auth_socket, auth_socket是只能本地连接的插件,需要修改: ALTER USER root% IDENTIFIED WITH mysql_native_password BY your_pass…

攀登SEO巅峰:代理技术如何成为网站排名提升的秘密武器

在当今这个数字化时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已成为企业和电商从业者在网站获取自然流量、提升品牌知名度和促进业务增长的关键策略之一。然而&#xff0c;随着搜索引擎算法的不断升级和市场竞争的日益激烈&#xff0c;传统的SEO手段已难以满足现…

【数据结构】二叉树(二)遍历

上篇已经了解对二叉树有了大概了解&#xff0c;本篇学习二叉树的前序、中序、后序及层序遍历的递归与非递归共7种遍历方法&#xff0c;快收藏吧~ 目录 1、前序遍历 递归方式&#xff1a; 迭代方式&#xff1a; 2、中序遍历 递归方式&#xff1a; 迭代方式&#xff1a; …

数字医学影像系统PACS源码,三甲以下医院都能满足,C#语言开发,C/S架构系统成熟稳定,支持二次开发项目使用。

数字医学影像系统&#xff08;RIS/PACS&#xff09;源码&#xff0c;三甲以下的医院都能满足。开发技术&#xff1a;C/S架构&#xff0c;C#开发语言&#xff0c;数据库服务器采用Oracle数据库。 PACS系统模块组成 &#xff1a; 工作站&#xff1a; 分诊工作站、超声工作站、放…

二叉树详解(1)

文章目录 目录1. 树的概念及结构1.1 树的相关概念1.2 树的表示1.3 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2. 二叉树的概念及结构2.1 概念2.2 特殊的二叉树2.3 二叉树的存储结构 3. 二叉树的顺序结构及实现3.1 二叉树的顺序结构3.2 堆的概念及结构…

监控电脑屏幕被拍照的原理是什么?如此有趣的电脑防偷窥知识,你一学就会!

“防身立志言为本&#xff0c;修业安命行为先”。在数字化时代&#xff0c;保护个人隐私与信息安全已成为我们不可忽视的重要课题。 当我们坐在电脑前工作、学习或娱乐时&#xff0c;是否曾想过&#xff0c;屏幕上的内容也可能成为他人窥探的目标&#xff1f; 今天&#xff0c…

【NI-DAQmx入门】基于TSN的以太网NI CompactDAQ机箱(9185/9189)

软件兼容性&#xff1a; WIN10 64bit&#xff1a; LabVIEW 2019 32bit NI-DAQmx 19.6 NI-Sync 19.5&#xff08;TSN&#xff09; WIN11 64bit&#xff1a; LabVIEW 2022Q3 32bit NI-DAQmx 2022Q3 32bit NI-TimeSync 2022 Q4&#xff08;TSN&#xff09; 如果要启用TSN&…

力扣 | 递增子序列 | 动态规划 | 最长递增子序列、最长递增子序列的个数、及其变式

文章目录 一、300. 最长递增子序列二、673. 最长递增子序列的个数三、变式1、646. 最长数对链2、1218. 最长定差子序列3、1027. 最长等差数列4、354. 俄罗斯套娃信封问题5、1964. 找出到每个位置为止最长的有效障碍赛跑路线 四、2024复旦计科夏令营机试 最长递增子序列&#xf…

Docker容器逃逸

Docker容器逃逸 Privileged 特权模式容器逃逸 | T Wiki (teamssix.com)https://wiki.teamssix.com/cloudnative/docker/docker-privileged-escape.html 1、云原生-Docker 安全-容器逃逸&特权模式 2、云原生-Docker 安全-容器逃逸&挂载 Procfs 3、云原生-Docker 安…

Linux云计算 |【第二阶段】OPERATION-DAY3

主要内容&#xff1a; Nginx调度器&#xff08;7层代理服务器Http、Nginx&#xff0c;4层代理服务器SSH&#xff09;、配置upstream服务器集群池属性&#xff0c;HTTP错误代码&#xff0c;Nginx优化&#xff08;自定义404错误代码、状态页面显示、ab压力测试、客户端开启缓存、…

在HMI项目中,传感器扮演的角色是啥?一文告诉你。

说到HMI项目&#xff0c;就绕不开物联网&#xff0c;说到物联网就不得不说传感器&#xff0c;本文大千UI工场带你详细了解传感器的价值。 一、传感器的价值 在HMI&#xff08;Human-Machine Interface&#xff09;项目中&#xff0c;传感器扮演着收集和监测实时数据的角色。传…