UE5 多人游戏 AnimNotify的潜在问题

未分类
2.2k 词

在开发一个多人联机TPS游戏时,出现了一个网络同步导致的AnimNotify重复触发的问题。

本游戏客户端换弹逻辑为:

  1. 按下R,触发换弹函数OnActionReload.
  2. OnActionReload调用战斗模块Combat中的Reload函数。
  3. Reload调用ServerReload,向服务器发出RPC请求。
  4. 服务器调用HandleReload,播放换弹Montage动画,更新CombatStateReloading
  5. 客户端接受CombatState的同步,执行HandleReload方法,播放换弹Montage动画。
  6. Montage动画播放至AnimNotify,提示上弹一颗,客户端、服务器执行ShotGunShellReload.
  7. ShotGunShellReload检查服务器权限,拒绝客户端更新子弹,允许服务器更新子弹。
  8. 后续换弹逻辑。

问题出现在 “Montage动画播放至AnimNotify,提示上弹一颗,客户端、服务器执行ShotGunShellReload” 这一步,由客户端触发的换弹时,服务器在一次换弹动画触发两次AnimNotify,导致每次换弹换上两颗。

解决思路:

通过Debug定位到AnimNotify多次触发上后,将原属于蓝图编程的AnimNotify触发行为交给CPP,并希望通过记录相应时间和堆栈,确定原因。

原蓝图逻辑:

Blueprint

创建UShotGunReloadAnimNotify类,继承自UAnimNotify.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "ShotGunReloadAnimNotify.generated.h"

/**
*
*/
UCLASS()
class SHOOTGAME_API UShotGunReloadAnimNotify : public UAnimNotify
{
GENERATED_BODY()
public:
virtual void Notify
(USkeletalMeshComponent* MeshComp,
UAnimSequenceBase* Animation,
const FAnimNotifyEventReference& EventReference)
override;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void UShotGunReloadAnimNotify::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,  const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation);

FString Timestamp = FDateTime::Now().ToString(TEXT("%H:%M:%S.%s"));
UE_LOG(LogTemp, Log, TEXT("[%s] AnimNotify Triggered"), *Timestamp);

FString Callstack = FFrame::GetScriptCallstack(true);
UE_LOG(LogTemp, Log, TEXT("Callstack:\n%s"), *Callstack);

if(MeshComp && MeshComp->GetOwner())
{
if(APlayerCharacter* PlayerCharacter =
Cast<APlayerCharacter>(MeshComp->GetOwner());
PlayerCharacter && PlayerCharacter->GetCombat())
{
PlayerCharacter->GetCombat()->ShotGunShellReload();
}
}
}

通过对比试验,确定额外触发的原因。

正常情况下服务器换弹触发一次,输出为:

1
2
LogTemp: [16:57:16.103] AnimNotify Triggered
LogTemp: Callstack:

异常情况下客户端换弹触发两次,输出为:

1
2
3
4
5
LogTemp: [17:21:57.748] AnimNotify Triggered
LogTemp: Callstack:
/Script/Engine.Character.ServerMovePacked
LogTemp: [17:21:57.784] AnimNotify Triggered
LogTemp: Callstack:

结果显示是/Script/Engine.Character.ServerMovePacked导致的额外触发。

后续:设置了计时器,避免多时间内快速触发。

留言