筆者最近正在從頭開始搭建一個(gè)多人射擊游戲拉盾,用于熟悉UE4 DS的方方面面桨菜,以及設(shè)計(jì)/性能優(yōu)化等方面的課題,做些零碎的筆記
3.關(guān)于網(wǎng)絡(luò)同步中捉偏,Character的Rotation同步倒得。
在搭建游戲過程中,筆者發(fā)現(xiàn)直接設(shè)置Character的Rotation夭禽,并不能同步到服務(wù)器及其他客戶端霞掺,所以趴一趴UE4對(duì)位置同步中Rotation的處理。
這里給各位的童鞋推薦大佬博客 https://blog.csdn.net/u012999985/article/details/78669947讹躯,對(duì)移動(dòng)同步方向?qū)懙暮茉敿?xì)菩彬,所以我這里只對(duì) Rotation 的問題進(jìn)說明缠劝。
首先找到服務(wù)器同步的移動(dòng)數(shù)據(jù)ReplicatedMovement,ReplicatedUsing類型的同步變量:
在服務(wù)器進(jìn)行Actor同步的時(shí)候骗灶,會(huì)采集Movement信息惨恭,進(jìn)行Movement同步,從代碼中發(fā)現(xiàn)耙旦,同步的Rotation直接使用的RootComponent的Rotation脱羡,下面繼續(xù)從客戶端發(fā)送移動(dòng)請(qǐng)求尋找來源。
首先找到客戶端發(fā)給服務(wù)器的同步請(qǐng)求servemove:
void UCharacterMovementComponent::ServerMove(float TimeStamp, FVector_NetQuantize10 InAccel,
FVector_NetQuantize100 ClientLoc, uint8 CompressedMoveFlags, uint8 ClientRoll, uint32 View,
UPrimitiveComponent* ClientMovementBase, FName ClientBaseBoneName, uint8 ClientMovementMode)
{
if (MovementBaseUtility::IsDynamicBase(ClientMovementBase))
{
CharacterOwner->ServerMove(TimeStamp, InAccel, ClientLoc, CompressedMoveFlags, ClientRoll, View, ClientMovementBase, ClientBaseBoneName, ClientMovementMode);
}
else
{
CharacterOwner->ServerMoveNoBase(TimeStamp, InAccel, ClientLoc, CompressedMoveFlags, ClientRoll, View, ClientMovementMode);
}
}
發(fā)現(xiàn) Rotation 相關(guān)數(shù)據(jù)來自參數(shù) uint32 View免都,向上追溯參數(shù)來源锉罐,可以看出其實(shí)客戶端發(fā)給服務(wù)器的Rotation只是ControlRotation。
void UCharacterMovementComponent::CallServerMove
(
const class FSavedMove_Character* NewMove,
const class FSavedMove_Character* OldMove
)
{
check(NewMove != nullptr);
// Compress rotation down to 5 bytes
const uint32 ClientYawPitchINT = PackYawAndPitchTo32(NewMove->SavedControlRotation.Yaw, NewMove->SavedControlRotation.Pitch);
const uint8 ClientRollBYTE = FRotator::CompressAxisToByte(NewMove->SavedControlRotation.Roll);
...
在服務(wù)器調(diào)用RPC處理客戶端移動(dòng)請(qǐng)求時(shí)調(diào)用UpdateRotation绕娘,在UpdateRotation中直接設(shè)置了Actor的Rotation為ControlRotation(當(dāng)然會(huì)考慮bUseControllerRotationPitch/bUseControllerRotationYaw/bUseControllerRotationRoll)的設(shè)置脓规,所以說了一大堆,就是DS同步以ControlRotation為基礎(chǔ)险领。
void UCharacterMovementComponent::ServerMove_Implementation(
float TimeStamp,
FVector_NetQuantize10 InAccel,
FVector_NetQuantize100 ClientLoc,
uint8 MoveFlags,
uint8 ClientRoll,
uint32 View,
UPrimitiveComponent* ClientMovementBase,
FName ClientBaseBoneName,
uint8 ClientMovementMode)
{
...
// Perform actual movement
if ((MyWorld->GetWorldSettings()->Pauser == NULL) && (DeltaTime > 0.f))
{
if (PC)
{
PC->UpdateRotation(DeltaTime);
}
MoveAutonomous(TimeStamp, DeltaTime, MoveFlags, Accel);
}
...
}
void APlayerController::UpdateRotation( float DeltaTime )
{
// Calculate Delta to be applied on ViewRotation
FRotator DeltaRot(RotationInput);
FRotator ViewRotation = GetControlRotation();
if (PlayerCameraManager)
{
PlayerCameraManager->ProcessViewRotation(DeltaTime, ViewRotation, DeltaRot);
}
AActor* ViewTarget = GetViewTarget();
if (!PlayerCameraManager || !ViewTarget || !ViewTarget->HasActiveCameraComponent() || ViewTarget->HasActivePawnControlCameraComponent())
{
if (IsLocalPlayerController() && GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed())
{
auto XRCamera = GEngine->XRSystem->GetXRCamera();
if (XRCamera.IsValid())
{
XRCamera->ApplyHMDRotation(this, ViewRotation);
}
}
}
SetControlRotation(ViewRotation);
APawn* const P = GetPawnOrSpectator();
if (P)
{
P->FaceRotation(ViewRotation, DeltaTime);
}
}
void APawn::FaceRotation(FRotator NewControlRotation, float DeltaTime)
{
// Only if we actually are going to use any component of rotation.
if (bUseControllerRotationPitch || bUseControllerRotationYaw || bUseControllerRotationRoll)
{
const FRotator CurrentRotation = GetActorRotation();
if (!bUseControllerRotationPitch)
{
NewControlRotation.Pitch = CurrentRotation.Pitch;
}
if (!bUseControllerRotationYaw)
{
NewControlRotation.Yaw = CurrentRotation.Yaw;
}
if (!bUseControllerRotationRoll)
{
NewControlRotation.Roll = CurrentRotation.Roll;
}
#if ENABLE_NAN_DIAGNOSTIC
if (NewControlRotation.ContainsNaN())
{
logOrEnsureNanError(TEXT("APawn::FaceRotation about to apply NaN-containing rotation to actor! New:(%s), Current:(%s)"), *NewControlRotation.ToString(), *CurrentRotation.ToString());
}
#endif
SetActorRotation(NewControlRotation);
}
}
對(duì)于這種情況侨舆,可以有幾種方法同步ActorRotation:
1.如果對(duì)Controller Rotation沒有特殊限制,可以設(shè)置 bUseControllerRotationYaw = true舷暮,在需要修改轉(zhuǎn)向時(shí)直接SetControlRotation 即可态罪;
2.不通過Controller的Rotation同步,設(shè)置bUseControllerRotationYaw = false下面,設(shè)置CharacterMovementCompoennt中的bOrientRotationToMovement = true复颈,這個(gè)變量的意思是在移動(dòng)時(shí)自動(dòng)轉(zhuǎn)向你移動(dòng)的方向,可以通過RotationRate控制轉(zhuǎn)向速度沥割;
3.添加自定義變量ActorYaw耗啦,在需要修改時(shí)給服務(wù)器發(fā)RPC。