关于CameraComponent/SpringArmCompo

2019-05-22  本文已影响0人  小小謨

笔者最近正在从头开始搭建一个多人射击游戏,用于熟悉UE4 DS的方方面面,以及设计/性能优化等方面的课题,做些零碎的笔记。

1.关于CameraComponent/SpringArmComponent的创建时机。

很多时候,在Character构造函数里创建静态Compoennt变成了习以为常,尤其官方示例也是这么实现(笔者之前测试用工程https://github.com/tomlooman/EpicSurvivalGameSeries/tree/Section-4也是在构造函数中实现,如图)。

image

但是,静态组件会在Actor生成时自动创建,那么思考下,在所有的客户端包括服务端,对所有的Character都创建SpringArmComponent和CameraComponent是否合理,也即是说,如果有100个人同时在游戏(假设均在你的同步范围内),那么你本地创建了100个无用的SpringArmComponent和CameraComponent(真可怕),所以考虑两个组件的创建时机(也可以指所有组件都应该考虑他的创建时机)变得很有必要。

然后思考,在其他非ROLE_AutonomousProxy客户端,肯定是不需要创建这两个组件,但是在服务器是否需要呢?我在上一篇CharacterMovement优化思路中简单提到一句 相关性剪裁,函数定义如下。

bool AActor::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const

其中变量 SrcLocation 是需要视点坐标的,如果服务器没有CameraComponent,SrcLocation是否准确?答案是没问题的,进一步查看SrcLocation的来源,如图,来自 FNetViewer,

image

查看 FNetViewer,发现 FNetViewer 为保存网络相关性检查使用的相关信息,其中 ViewLocation 即视点位置,进一步查询ViewLocation来源,如图所示,测试工程结果来自于CameraManager 中的CameraCachePrivate(当然,在其他情况下,也可能来自于其他数值,可自行查看FNetViewer::FNetViewer(UNetConnection* InConnection, float DeltaSeconds)构造函数)。

image image

继续查看CameraCachePrivate的来源,堆栈比较深,不一一截图,如图,最终来自ServerUpdateCamera_Implementation,这是客户端给服务器的同步请求,所以PlayerController会自动完成视点同步。

image image

罗里吧嗦扯了一大堆,就是一句话,服务器也不需要创建CameraComponent/SpringArmComponent(当然话不能说绝对,具体情况再分析)。笔者修改测试工程,如下所示,只在ROLE_AutonomousProxy创建CameraComponent/SpringArmComponent。


void ASCharacter::BeginPlay()
{
Super::BeginPlay();
  if (Role == ROLE_AutonomousProxy)
  {
    CameraBoomComp = NewObject<USpringArmComponent>(this,"CameraBoom");
    CameraBoomComp->RegisterComponent();
    CameraBoomComp->SocketOffset = FVector(0, 35, 0);
    CameraBoomComp->TargetOffset = FVector(0, 0, 55);
    CameraBoomComp->bUsePawnControlRotation = true;
    CameraBoomComp->AttachToComponent(GetRootComponent(),FAttachmentTransformRules::KeepRelativeTransform);
    CameraComp = NewObject<UCameraComponent>(this, "Camera");
    CameraComp->RegisterComponent();
    CameraComp->AttachToComponent(CameraBoomComp,FAttachmentTransformRules::KeepRelativeTransform);
  }
}

2.关于Pawn::SetupPlayerInputComponent 和 APlayerController::SetupInputComponent

其实如果使用UE4 DS,Pawn::SetupPlayerInputComponent 和 APlayerController::SetupInputComponent 都可以进行输入绑定,但是由于笔者之前用UE4和其他服务端做过MMO,遇到过小坑,特意在这里进行记录,加深理解。
先看Pawn::SetupPlayerInputComponent 的调用来源,在使用UE4 DS时,APawn::PawnClientRestart()中为Pawn创建InputComponent,再进行输入响应绑定,APawn::PawnClientRestart()只有ROLE_AutonomousProxy客户端来回收到启动通知。但在使用其他服务端时,由于没有权限初始化,会给所以玩家对象调用Pawn::SetupPlayerInputComponent,产生输入冲突,导致玩家输入对其他本地模拟玩家的行为产生影响。
再看APlayerController::SetupInputComponent,在Channel打开时进行输入绑定,此时可能玩家pawn并没有生成,如果在APlayerController::SetupInputComponent中绑定输入响应,需要对Pawn的状态进行判断。
另外,笔者以为,在客户端,APlayerController是唯一的,玩家Pawn可能存在很多个,把和Pawn无关的输入(如界面等输入相应)写在APlayerController中,和Pawn有关的输入写在Pawn中,比较清晰,也可以无脑全放在APlayerController中,将响应逻辑(如果需要)写在Pawn中。

上一篇下一篇

猜你喜欢

热点阅读