《UE5_C++多人TPS完整教程》學習筆記50 ——《P51 多人游戲中的俯仰角(Pitch in Multiplayer)》


本文為B站系列教學視頻 《UE5_C++多人TPS完整教程》 —— 《P51 多人游戲中的俯仰角(Pitch in Multiplayer)》 的學習筆記,該系列教學視頻為計算機工程師、程序員、游戲開發者、作家(Engineer, Programmer, Game Developer, Author) Stephen Ulibarri 發布在 Udemy 上的課程 《Unreal Engine 5 C++ Multiplayer Shooter》 的中文字幕翻譯版,UP主(也是譯者)為 游戲引擎能吃么。
在這里插入圖片描述


文章目錄

  • P51 多人游戲中的俯仰角(Pitch in Multiplayer)
  • 51.1 旋轉體的同步機制
  • 51.2 映射 AO_Pitch 區間
  • 51.3 Summary


P51 多人游戲中的俯仰角(Pitch in Multiplayer)

本節課我們將對瞄準偏移俯仰角變量 “AO_Pitch” 進行網絡同步,以解決上節課中服務器和客戶端人物角色瞄準偏移動畫不同步的問題。
在這里插入圖片描述


51.1 旋轉體的同步機制

  1. 打開 Visual Studio,在 “BlasterCharacter.cpp” 中的 “AimOffset()” 函數中添加調試代碼,將客戶端上服務器所控制的人物角色的瞄準偏移俯仰角 “Pitch” 打印到消息日志中。

    /*** BlasterCharacter.cpp ***/...// 瞄準偏移
    void ABlasterCharacter::AimOffset(float DeltaTime)
    {if (Combat && Combat->EquippedWeapon == nullptr) return;FVector Velocity = GetVelocity();												// 獲取人物角色速度向量Velocity.Z = 0.f;																// 不關心 Z 軸速度,設置為 0float Speed = Velocity.Size();													// 獲取人物角色速度向量的模(大小)bool bIsInAir = GetCharacterMovement()->IsFalling();							// 判斷人物角色是否掉落從而判斷人物角色是否在空中if (Speed == 0.f && !bIsInAir) {												// 當人物角色靜止站立且不跳躍時FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);	// 獲取人物角色當前瞄準旋轉FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation);	// 標準化獲取 CurrentAimRotation 和 StartingAimRotation 的差量AO_Yaw = DeltaAimRotation.Yaw;												// 獲取人物角色瞄準偏航角bUseControllerRotationYaw = false;											// 禁用控制器旋轉偏航}if (Speed > 0.f || bIsInAir) {													// 當奔跑或跳躍時StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);			// 改變奔跑或跳躍狀態轉換為靜止站立狀態時的起始瞄準旋轉AO_Yaw = 0.f;																// 由于啟用了控制器旋轉偏航,人物角色朝向始終面向控制器當前朝向,因此設置 AO_Yaw 為 0 bUseControllerRotationYaw = true;											// 啟用控制器旋轉偏航}AO_Pitch = this->GetBaseAimRotation().Pitch;									// 獲取人物角色瞄準俯仰角/* P51 多人游戲中的俯仰角*/if (!HasAuthority() && !IsLocallyControlled()) {UE_LOG(LogTemp, Warning, TEXT("AO_Pitch: %f"), AO_Pitch);}/* P51 多人游戲中的俯仰角*/
    }...
    
  2. 編譯后進行測試。當我們控制服務器上的人物角色持續向下進行瞄準時,可以看到客戶端上打印出的 “AO_Pitch” 的值從大于 0 減小到 0,然后再跳躍到 360.0360.0 開始減小,所以客戶端上服務器控制的人物角色會向上進行瞄準。這便是問題所在,因為我們本來期望的是 “AO_Pitch” 的值在減小到 0 之后在負數的區間 [-90,0) 里面連續變化,這樣 “AO_Pitch” 的值就可以和我們瞄準偏移 “HipAimOffset” 和 “AimAimOffset”中的垂直軸 [-90,0) 區間對應上。
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述

  3. 出現這樣的測試結果與虛幻引擎對旋轉體 Yaw、Pitch 和 Roll 三個方向上的分量值進行網絡同步的機制有關。為了減小網絡同步的壓力,通常在發送方會將它們進行壓縮傳輸,在此過程中首先會將角度限定在 [0->360) 的浮點數區間,任何角度的負值都會變成正值,以便在壓縮時映射到 [0->65535) 的字節區間。而在接收方,解壓縮過程則相反,將角度從字節值重新映射到 [0->360) 的浮點值。

    PlayerInfo 高頻同步解決方案
    需求目的
    分析一個常見的需求: “在 1P 客戶端顯示 3P 的 Transform ”。
    顯然,在客戶端存在 3P 的 Pawn 時,可以直接取 PawnTransform;但出于性能考慮,會進行各種 AOI 機制,在較遠距離時客戶端會將 3P 的 Pawn 裁剪掉,只留下 PlayerState(或者某個不被剪裁的數據 Channel) 用于同步。
    一個直觀的想法是將 Transform 直接通過對應的 PlayerState 屬性同步給所有客戶端;但出于性能考慮,對于同步一般會開啟 PushModel;這種高頻字段會頻繁將 PlayerState 對應 ActorChannelMarkDirty,導致 PushModel 功能基本失效,頻繁進行同步的 Diff 等大開銷的操作;所以需要一個機制對這種情況進行優化。
    核心思路
    對于 DS,創建一個 Channel 專門用于同步 Player 的高頻變化信息,如 LocationRotation 等;
    對于同步的信息,進行適當的同步降頻(不需要每幀同步)、字節壓縮(舍棄部分精度,精確到 float 沒有意義);
    同時為了保證 Client 的信息相對正確(同步降頻會導致 Location 不連續),在 1P Client 進行信息的預測插值;


    —— 《[UE] PlayerInfo高頻同步解決方案》

  4. 具體可以參閱虛幻引擎的源碼,值得注意的是函數 “CompressAxisToShort()” 中在將角度從浮點數量化為字節值、四舍五入后使用了位運算 “& 0xFFFF,其作用主要在于只保留最后 16位,剔除 16 位前所有的二進制值,這樣返回值的類型就是 “uint16” 。

    /*** Rotator.h ***/...template<typename T>
    FORCEINLINE uint16 TRotator<T>::CompressAxisToShort( T Angle )
    {// map [0->360) to [0->65536) and mask off any windingreturn FMath::RoundToInt(Angle * (T)65536.f / (T)360.f) & 0xFFFF;
    }template<typename T>
    FORCEINLINE T TRotator<T>::DecompressAxisFromShort( uint16 Angle )
    {// map [0->65536) to [0->360)return (Angle * (T)360.f / (T)65536.f);
    }...
    

51.2 映射 AO_Pitch 區間

  1. 了解了虛幻引擎對旋轉體分量值進行網絡同步的機制,接下來我們只需將 “AO_Pitch” 的變化區間 [270, 360) 映射到 [-90, 0) 即可。在 “BlasterCharacter.cpp” 中的 “AimOffset()” 函數中定義兩個區間,然后調用 “FMath::GetMappedRangeValueClamped()” 進行區間映射即可。
    /*** BlasterCharacter.cpp ***/...// 瞄準偏移
    void ABlasterCharacter::AimOffset(float DeltaTime)
    {if (Combat && Combat->EquippedWeapon == nullptr) return;FVector Velocity = GetVelocity();												// 獲取人物角色速度向量Velocity.Z = 0.f;																// 不關心 Z 軸速度,設置為 0float Speed = Velocity.Size();													// 獲取人物角色速度向量的模(大小)bool bIsInAir = GetCharacterMovement()->IsFalling();							// 判斷人物角色是否掉落從而判斷人物角色是否在空中if (Speed == 0.f && !bIsInAir) {												// 當人物角色靜止站立且不跳躍時FRotator CurrentAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);	// 獲取人物角色當前瞄準旋轉FRotator DeltaAimRotation = UKismetMathLibrary::NormalizedDeltaRotator(CurrentAimRotation, StartingAimRotation);	// 標準化獲取 CurrentAimRotation 和 StartingAimRotation 的差量AO_Yaw = DeltaAimRotation.Yaw;												// 獲取人物角色瞄準偏航角bUseControllerRotationYaw = false;											// 禁用控制器旋轉偏航}if (Speed > 0.f || bIsInAir) {													// 當奔跑或跳躍時StartingAimRotation = FRotator(0.f, GetBaseAimRotation().Yaw, 0.f);			// 改變奔跑或跳躍狀態轉換為靜止站立狀態時的起始瞄準旋轉AO_Yaw = 0.f;																// 由于啟用了控制器旋轉偏航,人物角色朝向始終面向控制器當前朝向,因此設置 AO_Yaw 為 0 bUseControllerRotationYaw = true;											// 啟用控制器旋轉偏航}AO_Pitch = this->GetBaseAimRotation().Pitch;									// 獲取人物角色瞄準俯仰角/* P51 多人游戲中的俯仰角*/// if (!HasAuthority() && !IsLocallyControlled()) {//	 UE_LOG(LogTemp, Warning, TEXT("AO_Pitch: %f"), AO_Pitch);// }if (AO_Pitch > 90.f && !IsLocallyControlled()) {								// 對于其他機器上非本地控制的人物角色FVector2D InRange(270.f, 360.f);FVector2D OutRange(-90.f, 0.f);AO_Pitch = FMath::GetMappedRangeValueClamped(InRange, OutRange, AO_Pitch);	// 將區間 [270,360) 映射到 [-90,0)}/* P51 多人游戲中的俯仰角*/
    }...
    
  2. 編譯后進行測試,可以發現無論是 “HipAimOffset” 還是 “AimAimOffset” 的動畫都能在所有機器上正確同步。在這里插入圖片描述在這里插入圖片描述

51.3 Summary

本節課我們成功解決了多人游戲中瞄準偏移俯仰角(Pitch)的網絡同步問題。
在測試中我們發現,在客戶端上服務器所控制的人物角色持續向下瞄準時,“AO_Pitch” 的值會從 360 開始遞減而不是保持在 [-90,0) 的區間,導致瞄準方向相反。通過深入分析虛幻引擎的旋轉體同步機制,我們了解到虛幻引擎將 [0->360) 角度值映射到 [0->65536) 再進行壓縮傳輸進行網絡傳輸,這導致了負角度值被轉換為正角度值,從而造成客戶端與服務器上的瞄準動畫顯示不一致。
因此,我們在 “BlasterCharacter.cpp” 中的 “AimOffset()” 函數中通過調用 “FMath::GetMappedRangeValueClamped()” 函數,將 “AO_Pitch” 的 [270,360) 區間映射到 [-90,0) 的區間,確保所有機器上的人物角色瞄準偏移的動畫都能夠正確同步。
在這里插入圖片描述


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96061.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96061.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96061.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

樹莓派 Ubuntu 24.04 開機換源總結

1. 圖形界面 (桌面版) 如果你刷的是 Ubuntu Desktop 24.04&#xff1a;打開 Software & Updates&#xff08;軟件和更新&#xff09;。在 Ubuntu Software 標簽里找到 Download from 下拉菜單。默認只有 Main server 和 Server for China&#xff0c;如果想要更多選擇&…

工業顯示器在地鐵電力監控與運維中的應用

在地鐵電力監控與運維中&#xff0c;工業顯示器憑借其高可靠性、環境適應性和強大的功能集成&#xff0c;成為保障地鐵供電系統安全穩定運行的核心設備。以下從關鍵應用場景、技術優勢及實際案例三個維度展開分析&#xff1a;一、核心應用場景變配電室與環控電控室監控 工業顯示…

Docker 快速部署單節點 NiFi 1.27

Docker 快速部署單節點 NiFi 1.27 前言 Apache NiFi 是一款強大的數據集成工具&#xff0c;專注于數據的采集、處理和分發&#xff0c;具有可視化流程設計、強大的容錯能力等特點。通過 Docker 部署可以快速搭建環境&#xff0c;省去復雜的配置步驟。本文介紹如何使用官方鏡像…

php redis 中文API文檔手冊

php redis 中文API文檔手冊 Redis::__construct構造函數 $redis new Redis();connect, open 鏈接redis服務 參數 host: string&#xff0c;服務地址 port: int,端口號 timeout: float,鏈接時長 (可選, 默認為 0 &#xff0c;不限鏈接時間) 注: 在redis.conf中也有時間&#xf…

Windows環境下實現GitLab與Gitee倉庫代碼提交隔離

1. 背景 在開發工作中&#xff0c;我需要同時使用2個代碼托管平臺&#xff1a;公司統一使用的GitLab和個人學習用的 Gitee。我希望能夠在同一臺電腦上方便地管理和提交兩個平臺的代碼&#xff0c;實現賬號和提交內容的有效隔離。 前提條件&#xff1a; 已安裝Git Bash、Tort…

深度解析:抗輻射電源芯片 ASP4644S2B 在空間環境中的單粒子效應表現

摘要&#xff1a;隨著航天技術的飛速發展&#xff0c;空間電子設備面臨著日益復雜和嚴苛的輻射環境挑戰。單粒子效應&#xff08;SEE&#xff09;作為輻射環境對半導體器件影響的主要形式之一&#xff0c;極大地影響著航天電子系統的可靠性和穩定性。本文通過系統梳理國科安芯推…

【RabbitMQ】如何在 Ubuntu 安裝 RabbitMQ

1. 安裝部署 Erlang 環境 RabbitMQ 是一套開源的消息隊列服務軟件&#xff0c;基于 Erlang 語言編寫的&#xff0c;因此&#xff0c;在安裝 RabbitMQ 之前&#xff0c;我們需要先部署 Erlang 環境&#xff0c;再安裝 RabbitMQ 環境&#xff08;就像運行 Java 程序&#xff0c;…

vue集成高德地圖API工具類封裝

import axios, { AxiosInstance, AxiosResponse } from axios;// 高德地圖 API 響應基礎結構 interface AMapResponse {status: string;info: string;infocode: string; }// 逆地理編碼響應結構 interface RegeoResponse extends AMapResponse {regeocode: {formatted_address:…

手寫 Tomcat

文章目錄02 初出茅廬:構造一個極簡的 HttpServerRequestResponseHttpServer03 動態 Response : 按照規范構造返回流04 各司其職的 Server : 拆分響應模塊與處理模塊HttpConnectorHttpProcessor05 Server 性能提升: 設計多個 ProcessorHttpConnectorHttpProcessor06 規范化: 引入…

嵌入式ARM架構學習3——啟動代碼

一 匯編補充&#xff1a;area reset, code, readonlycode32entry;mov r0, #4 ; r0 4;mov r1, r0 ; r1 r0;mov r2, r1, lsl #1 ;r2 r1 << 1 乘2;mov r3, r1, lsr #1 ;r3 r1 >> 1 除2;mov r4, r1, ror #2;mov r0, #100 ;100是十進制 轉為16進制賦值給十進制;mov …

PNPM庫離線安裝方案

以下是幾種可行的方案&#xff0c;推薦優先使用方案一。 方案一&#xff1a;使用離線鏡像&#xff08;Offline Mirror&#xff09; - 最優雅、最PNPM的方式 這是 PNPM 官方推薦的處理離線環境的方式。它會在內網電腦上創建一個所有依賴包的壓縮文件&#xff08;tarball&#x…

[Wit]CnOCR模型訓練全流程簡化記錄(包括排除BUG)

stepfile:step 00 創建數據集 目錄結構 yourproject -data --myset ---images #存放訓練圖片 ---dev.tsv #測試標簽 tsv格式 圖片文件名\t內容 ---train.tsv #訓練標簽 tsv格式 圖片文件名\t內容 -train_config.json -train_config_gpu.json -fix_cnocr_encoding.py step 01 創…

Sklearn(機器學習)實戰:鳶尾花數據集處理技巧

1.數據集的使用&#xff1a;先使用load導入鳶尾花數據&#xff1a;from sklearn.datasets import load_iris然后定義一個函數來查看鳶尾花數據集&#xff1a;數據集的獲取&#xff1a;iris load_iris()print(鳶尾花的數據集&#xff1a;\n,iris)使用iris[DESCR]來查看數據及里…

【企業微信】接口報錯:javax.net.ssl.SSLHandshakeException

詳細報錯信息 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target原因 關于qyapi…

光子芯片驅動的胰腺癌早期檢測:基于光學子空間神經網絡的高效分割方法

光子芯片驅動的胰腺癌早期檢測:基于光學子空間神經網絡的高效分割方法 1 論文核心概念 本文提出了一種基于集成光子芯片的光學子空間神經網絡(Optical Subspace Neural Network, OSNN),用于胰腺癌的早期檢測與圖像分割。其核心思想是利用光子芯片的高并行性、低延遲和低能…

Scikit-learn Python機器學習 - 特征降維 壓縮數據 - 特征提取 - 主成分分析 (PCA)

鋒哥原創的Scikit-learn Python機器學習視頻教程&#xff1a; 2026版 Scikit-learn Python機器學習 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 課程介紹 本課程主要講解基于Scikit-learn的Python機器學習知識&#xff0c;包括機器學習概述&#xff0c;特征工程(數據…

【Python】pytorch安裝(使用conda)

# 創建 PyTorch 虛擬環境 conda create -n pytorch_env python3.10# 激活環境 conda activate pytorch_env# 安裝 PyTorch&#xff08;CPU版本&#xff09; conda install pytorch torchvision torchaudio cpuonly -c pytorch# 或者安裝 GPU 版本&#xff08;如果有NVIDIA顯卡&…

ThreeJS骨骼示例

<html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>骨骼動畫混合演示</title><style>body {margin: 0;padding: …

python + Flask模塊學習 1 基礎用法

目錄 Flask 的主要作用 常用擴展 Flask 基本用法 1. 安裝 Flask&#xff08;再安裝個postman用來調試測試API哈 2. 最小化應用示例 3. 運行應用 Flask 是一個輕量級的 Python Web 框架&#xff0c;它簡潔靈活&#xff0c;適合快速開發 Web 應用和 API。它被稱為 "微…

python數據可視化之Matplotlib(8)-Matplotlib樣式系統深度解析:從入門到企業級應用

作者&#xff1a;浪浪山齊天大圣 描述&#xff1a;深入探索Matplotlib樣式系統的核心機制&#xff0c;掌握從基礎樣式到企業級樣式管理的完整解決方案引言 在數據可視化的世界里&#xff0c;一個優秀的圖表不僅要準確傳達數據信息&#xff0c;更要具備專業的視覺效果。Matplotl…