RPC同步销毁对象(已修改)

// YanWei.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AuraProjectile.generated.h"

class UNiagaraSystem;
class UProjectileMovementComponent;
class USphereComponent;


UCLASS()
class AURA_API AAuraProjectile : public AActor
{
	GENERATED_BODY()
	
public:	
	AAuraProjectile();

	//设置为公共public  因为之后可能会用它改变projectile的参数
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<UProjectileMovementComponent> ProjectileMovement;
	
protected:
	virtual void BeginPlay() override;
	virtual void Destroyed() override;
	
	/*// 声明一个 Server RPC,用于在服务器上销毁对象
	UFUNCTION(Server, Reliable, WithValidation)
	void ServerDestroyProjectile();*/

	//TODO:: Projectile Overlap
	UFUNCTION()
	void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp,int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
	
private:
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<USphereComponent> Sphere;

	UPROPERTY(EditAnywhere)
	TObjectPtr<UNiagaraSystem> ImpactEffect;
	UPROPERTY(EditAnywhere)
	TObjectPtr<USoundBase> ImpactSound;
	bool bHit = false; //用于判断当前火球是否和其它物体产生了碰撞

};
// YanWei.


#include "Actor/AuraProjectile.h"

#include "NiagaraFunctionLibrary.h"
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"

AAuraProjectile::AAuraProjectile()
{
	PrimaryActorTick.bCanEverTick = false;
	bReplicates = true; //此类在服务器运行,然后复制到每个客户端
	
	Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
	SetRootComponent(Sphere);
	Sphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly); //设置其只用作查询使用
	Sphere->SetCollisionResponseToChannels(ECR_Ignore); //设置其忽略所有碰撞检测
	Sphere->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Overlap); //设置其与世界动态物体产生重叠事件
	Sphere->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Overlap); //设置其与世界静态物体产生重叠事件
	Sphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); //设置其与Pawn类型物体产生重叠事件
	
	//创建发射组件
	ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>("ProjectileMovement");
	ProjectileMovement->InitialSpeed = 550.f; //设置初始速度
	ProjectileMovement->MaxSpeed = 550.f; //设置最大速度
	ProjectileMovement->ProjectileGravityScale = 0.f; //设置重力影响因子,0为不受影响
	
}

void AAuraProjectile::BeginPlay()
{
	Super::BeginPlay();
	Sphere->OnComponentBeginOverlap.AddDynamic(this,&AAuraProjectile::OnSphereOverlap);
	
}

void AAuraProjectile::Destroyed()
{
	//如果没有权威性且未触发重叠事件时, 在销毁之前播放击中特效
	if (!bHit && !HasAuthority())
	{
		UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(),FRotator::ZeroRotator);
		UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation());
	}
	Super::Destroyed(); // 调用父类的销毁逻辑
	
}
/*
void AAuraProjectile::ServerDestroyProjectile_Implementation()
{
	// 确保在服务器上销毁
	Destroy();
}

bool AAuraProjectile::ServerDestroyProjectile_Validate()
{
	// 可以在这里添加验证逻辑,检查销毁请求是否合理
	return true;
}*/


void AAuraProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
                                      UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 播放 Sound 和 Niagara 特效
	UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(),FRotator::ZeroRotator);
	UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation());

	//如果拥有权威性,在触发重叠后,销毁它,如果没有,将bHit设置为true,代表它已经触发了重叠事件,并且已经播放了几种特效,
	//但是没有对火球的控制权,无法自身直接销毁。 需添加销毁函数
	if (HasAuthority())
	{
		//拥有权限时销毁(服务器端)
		Destroy(); // 服务器端控制,直接销毁
	}else
	{
		//无权威时销毁(客户端)
		bHit = true;  // 客户端设置 bHit 为 true,等待服务器处理
		
		//ServerDestroyProjectile();// 客户端请求服务器
	}
	
}

AActor::Destroyed() 是 Unreal Engine 中 AActor 类的一个成员函数,用于在对象销毁时执行一些清理和回调操作。这个函数主要用于处理对象销毁前的一些必要步骤。接下来,我会详细解析它的工作流程,并说明如何通过 RPC 来同步销毁对象。

AActor::Destroyed() 详细解析

void AActor::Destroyed()
{
    RouteEndPlay(EEndPlayReason::Destroyed);  // 通知游戏框架该 Actor 正在销毁
    ReceiveDestroyed();  // 调用接收销毁事件的虚拟函数
    OnDestroyed.Broadcast(this);  // 广播 OnDestroyed 委托
}
1. RouteEndPlay(EEndPlayReason::Destroyed)
  • 该函数用于通知游戏框架对象即将销毁,并开始执行销毁过程。
  • EEndPlayReason::Destroyed 是枚举值,表示该对象是由于销毁事件而结束生命周期。它会触发 AActor::EndPlay 函数中的相关清理工作,例如注销事件、移除对象等。
2. ReceiveDestroyed()
  • 这是一个虚拟函数,可以在子类中重写。Destroyed() 会在销毁时调用它,允许子类在销毁前进行一些自定义的清理工作。
  • 如果你需要在销毁对象时做一些额外处理(例如,释放资源、停止计时器等),你可以在子类中重写这个函数。
  • 示例:
    void AMyActor::ReceiveDestroyed()
    {
        Super::ReceiveDestroyed();
        // 在这里添加销毁前的清理逻辑,比如关闭文件句柄或清理自定义资源
    }
    
3. OnDestroyed.Broadcast(this)
  • 这是一个委托(Delegate),用于在对象销毁时广播通知,其他订阅该事件的对象可以做出相应的处理。
  • 你可以订阅 OnDestroyed 委托,以便在对象销毁时触发某些操作,例如更新 UI 或执行某些动画。
  • 示例:
    MyActor->OnDestroyed.AddDynamic(this, &AMyGameMode::OnActorDestroyed);
    
    然后你可以在 AMyGameMode 类中定义处理销毁的函数:
    void AMyGameMode::OnActorDestroyed(AActor* DestroyedActor)
    {
        // 处理销毁的 Actor
        UE_LOG(LogTemp, Warning, TEXT("Actor destroyed: %s"), *DestroyedActor->GetName());
    }
    

通过 RPC 同步销毁

如果你希望通过 RPC 来同步销毁对象,可以结合 Destroyed() 方法和 RPC 来确保对象在服务器和所有客户端上都能正确销毁。

假设你希望通过 RPC 从客户端向服务器请求销毁一个 Actor,可以按照以下步骤操作。

定义服务器端 RPC 方法

你需要定义一个服务器端的 RPC 方法,来在服务器上销毁对象。

UFUNCTION(Server, Reliable, WithValidation)
void ServerDestroy();
实现 RPC
void AMyActor::ServerDestroy_Implementation()
{
    Destroy(); // 销毁对象
}

bool AMyActor::ServerDestroy_Validate()
{
    return true; // 可选验证函数,检查客户端是否有权限进行销毁
}
客户端调用 RPC

当客户端需要销毁一个对象时,调用该 RPC 方法:

MyActor->ServerDestroy();  // 客户端请求服务器销毁对象

通过这种方式,客户端通过 RPC 向服务器请求销毁对象,服务器接收到请求后执行 AActor::Destroyed(),触发销毁相关的清理和委托操作。这样可以保证销毁操作在服务器和客户端同步进行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值