<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      mini: false, //迷你模式 autoplay: false, //自動播放 theme: '#FADFA3', //主題色 loop: 'all', //音頻循環播放, 可選值: 'all'全部循環, 'one'單曲循環, 'none'不循環 order: 'random', //音頻循環順序, 可選值: 'list'列表循環, 'random'隨機循環 preload: 'auto', //預加載,可選值: 'none', 'metadata', 'auto' volume: 0.7, //默認音量,請注意播放器會記憶用戶設置,用戶手動設置音量后默認音量即失效 mutex: true, //互斥,阻止多個播放器同時播放,當前播放器播放時暫停其他播放器 listFolded: false, //列表默認折疊 listMaxHeight: 90, //列表最大高度 lrcType: 3, //歌詞傳遞方式

      Multiplayer Shooting Game

      GASP+Lyra Animation

      視頻
      Project Mega Sample (5.5)
      Alternate Link

      新 多人游戲插件

      [/Script/Engine.GameEngine]
      	+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
       
      	[OnlineSubsystem]
      	DefaultPlatformService=Steam
       
      	[OnlineSubsystemSteam]
      	bEnabled=true
      	SteamDevAppId=480
          bInitServerOnClient=true
       
      	[/Script/OnlineSubsystemSteam.SteamNetDriver]
      	NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
      
      • Step3:配置一些屬性
        在Project中設置 Map 和 Game Instance Class:

        設置List Of Map:

        修改模板中的GameMode和PlayerController:

        將父類改為自己寫的C++類:


        按下面圖片更改Map的GameMode:

      攀爬系統

      下載地址+使用文檔:
      https://drive.google.com/file/d/1GQg4gi1L4m3DTJd-Bvo4qbmJ3E4y9qdo/view

      Replicate 和 RPC 和 OnRep

      在服務器執行:
      1.服務器執行函數 并 在函數中改變復制變量
      2.觸發各個客戶端的OnRep_函數
      3.讓所有客戶端正確表現服務器裝備行為

      在客戶端執行:
      1.客戶端A執行PRC發請求給服務器
      2.服務器執行函數 并 在函數中改變復制變量(收到這個更新后,所有客戶端(包含 A 自己)都會觸發 OnRep_函數)
      3.觸發各個客戶端的OnRep_函數(包含 A 自己)
      4.讓 所有客戶端 和 客戶端A 正確表現 客戶端A 的行為

      // 如果不希望客戶端A在 RepNotify 里做某些處理,可以在回調里加一個判斷:
      void UCombatComponent::OnRep_EquippedWeapon()
      {
          // 只讓遠端客戶端執行
          if (!ShootCharacter->IsLocallyControlled())
          {
      
          }
      }
      

      Launch game in settings

      添加多人游戲

      設置游戲人數:

      選擇網絡模式:

      Play As Listen Server:其中一臺有人游玩的機器充當服務器,需要圖形渲染
      Play As Client:指定一臺機器作為服務器,沒有人實際在這臺機器上游玩游戲,無需圖形渲染(大型多人游戲)

      配置Project連接到Steam

      啟用Steam插件:


      在DefaultEngine.ini中添加代碼:


      [/Script/Engine.GameEngine]
      	+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
       
      	[OnlineSubsystem]
      	DefaultPlatformService=Steam
       
      	[OnlineSubsystemSteam]
      	bEnabled=true
      	SteamDevAppId=480
          bInitServerOnClient=true
       
      	[/Script/OnlineSubsystemSteam.SteamNetDriver]
      	NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
      


      添加完成后關閉UE和VS并刪除指定文件重構代碼:


      獲取在線子系統(OnlineSubsystem)并打印該名稱“Steam”:

      遇到該錯誤需要重構代碼:

      在編輯器中運行時,連接到的是名為“null”的子系統,只有打包后的項目才能連接到Steam在線子系統
      選擇多人模式并Package項目才能生效:

      Create Game Session

      委托(delegate):可以綁定回調函數(CallbackFuction),當游戲中某個特定事件發生時調用該函數

      在線會話接口(Online Session Interface):使用委托來處理創建和加入游戲會話時需要的信息傳輸
      步驟:

      1.定義:
      會話接口(OnlineSessionInterface)、
      創建會話的函數(CreateGameSession( ))、
      委托變量(CreateSessionCompleteDelegate)、
      回調函數(OnCreateSessionComplete(FName SessionName,bool bWasSuccessful))



      2.綁定回調函數到委托變量上:OnCreateSessionComplete()

      3.將委托添加到會話接口(Session Interface)的委托列表(Delegate List)中,使得當會話接口被創建時調用委托的CallbackFunction
      4.會話接口(Session Interface)調用創建會話函數(CreateSession())來連接Steam并創建游戲會話

      5.當會話創建完成時,Steam將會把信息發送回來,回調函數(callbackFuction)被觸發,并通過該函數打印出調試信息以驗證會話已成功創建

      Find Game Session



      需要添加頭文件才能使用:SEARCE_PRESENCE



      Join Game Session

      創建一個大廳(Lobby Level):

      創建Join Session的委托和回調函數:

      初始化委托:

      添加SessionSetting的Set函數:


      Create Session時,改變服務器地圖:

      Find session的回調函數:

      Join session的回調函數:

      需要保證Steam在同一下載地區:

      Create a Plugin

      創建多人游戲插件:



      啟用在線子系統插件:

      添加在線子系統模塊名稱:

      Create our own subsystem

      GameInstance和GameInstanceSubsystem

      創建GameInstanceSubsystem:


      在子系統中
      1.添加公共函數以處理會話創建、查找、加入、銷毀和啟動等操作
      2.添加委托變量
      3.創建對應的回調函數
      4.創建委托句柄以存儲對每個委托的引用,用于從會話接口中移除不再需要的委托


      Create Widget

      創建C++Widget類:





      創建Widget藍圖類:



      初始化Menu類并添加按鈕回調函數:




      添加刪除Widget函數,并在NativeDestruct函數中調用:
      添加NumPublicConnections和MatchType:





      添加自定義委托

      創建委托和回調函數并將回調函數綁定到委托上:





      如果創建失敗,則清除委托并廣播自定義委托為false;如果成功,則在回調函數中清除委托并廣播自定義委托為true


      將HostButtonClicked函數中的ServerTravel函數放到自定義委托的回調函數中,若創建成功則前往大廳:

      添加更多委托和回調函數并進行綁定:



      完善FindSession和JoinSession函數:



      通過游戲模式跟蹤加入和退出的玩家

      創建GameModeBase C++類:






      創建GameMode 藍圖類:


      Path to lobby




      完善Destroy函數

      由于網絡傳輸需要時間,立即調用CreateSession函數時可能Session還未被銷毀
      在DestroySession函數中先銷毀session,若成功則調用CreateSession函數重新創建:



      Disable Menu button

      當創建時禁用按鈕,創建失敗時啟用按鈕:



      Steps to use plugin

      Plugins.zip
      鏈接: https://pan.baidu.com/s/13PgLgU_LrBP4z0X3XMbFCQ?pwd=nx32 提取碼: nx32
      將測試里的Plugin壓縮:

      解壓到桌面:

      直接拖到需要的Project中:


      啟用Steam插件:

      在DefaultEngine.ini中添加代碼:


      [/Script/Engine.GameEngine]
      	+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
       
      	[OnlineSubsystem]
      	DefaultPlatformService=Steam
       
      	[OnlineSubsystemSteam]
      	bEnabled=true
      	SteamDevAppId=480
          bInitServerOnClient=true
       
      	[/Script/OnlineSubsystemSteam.SteamNetDriver]
      	NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
      


      在DefaultGame.ini中添加代碼:

      [/Script/Engine.GameSession]
      MaxPlayer=100
      

      創建Lobby地圖并復制該路徑:

      打開Level Blueprint:

      創建Widget并調用Menu Setup函數:

      刪除這些文件以重構代碼:


      打包時在List of maps添加這兩個地圖:

      steam需要在同一地區才能聯機:

      Create a Character

      創建Character C++類:


      創建Character 藍圖類:

      添加彈簧臂組件相機組件并初始化:

      將彈簧臂組件附加到Mesh而不是Capsule上,確保蹲下改變膠囊尺寸時,不會影響彈簧臂高度

      Add Character Movement

      Pitch,Roll,Yaw:
      Pitch:俯仰
      Roll:滾轉
      Yaw:偏航

      將旋轉前的Rotation坐標與旋轉矩陣相乘即可求出旋轉后的Rotation坐標:




      Create Animation

      先創建AnimInstance C++類:

      創建并初始化1+3個變量:


      創建Animation 藍圖類:


      先創建一個State Machine:


      IdleWalkRun:

      IdleWalkRun -> JumpStart:

      JumpStart -> Falling:

      Falling -> JumpStop:

      JumpStop -> IdleWalkRun:


      使用鍵盤操縱角色移動方向而不是鼠標:

      From Lobby Map to Game Map

      為Lobby Map創建GameMode C++類:


      當進入Lobby的玩家數量達到2個時,無縫Travel到Game Map中:


      為Lobby Map創建GameMode 藍圖類:

      在藍圖中也需要設置為無縫Travel:

      將Lobby的GameMode設置為BP_LobbyGameMode:

      創建一個空白的Transition Map:

      設置Transition Map:

      NetWork Role

      網絡角色(Network Role)包括本地角色和遠程角色
      1.角色權威(Authority):存在于服務器上的角色,具有最高權限
      2.模擬代理(Simulated Proxy):存在于客戶端上且由服務器或另一個客戶端控制的角色
      3.自主代理(Autonomous Proxy):存在于客戶端上且由當前玩家控制的角色
      4.無角色(None):未定義角色的演員

      創建在角色頭頂顯示角色信息的Widget C++類:




      在Character中創建并初始化Widget:


      創建藍圖類:

      配置Character中的Overhead Widget并調用Show Player Met Role函數:

      Create a Weapon

      創建C++類:


      為武器類添加一個枚舉(Enum)來定義武器的狀態(初始狀態、裝備狀態、掉落狀態):




      創建藍圖類:

      Create PickUpWidget

      創建Widget藍圖類:


      設置Text:

      在ShootCharacter C++中添加UWidgetComponent變量并設置只有重疊時才顯示該Widget:
      OnComponentBeginOverlap:



      僅在服務器上生成重疊事件,即當服務器或客戶端與武器重疊時,都只有服務器顯示Widget:

      在ShootCharacter藍圖中配置Widget:


      Problem:服務器或客戶端與武器重疊時,都只有服務器顯示Widget

      Show PickUpWidget using Replication

      解決上述問題,確保誰與武器重疊,誰show widget:
      創建復制變量并綁定調用函數:

      創建配置函數并配置復制變量:


      創建調用函數:

      創建SetOverlappingWeapon函數:


      在Weapon的OnSphereOverlap函數中調用SetOverlappingWeapon函數:

      Hide PickUpWidget using Replication

      添加OnSphereEndOverlap函數,結束重疊時將OverlappingWeapon設置為NULL:



      處理客戶端的結束重疊事件:
      在處理客戶端的回調函數中添加變量LastWeapon,表示復制之前的Weapon的值
      因為當OverlappingWeapon為NULL時,無法調用ShowPickUpWidget函數


      處理服務器的結束重疊事件:

      Equip Weapon

      在骨骼上添加Socket:


      創建CombatComponent組件并在Character中初始化:




      在Character中初始化:





      綁定裝備武器的按鍵:




      目前之有服務器才能裝備武器

      Remote Procedure Call:遠程過程調用(RPC)

      在客戶端調用,在服務器執行:是客戶端也能Equip Weapon



      Problem:還需要隱藏Widget并禁用Overlap Event
      解決方法:
      雖然服務器和客戶端調用的都是EquipWeapon函數,但客戶端無法直接修改服務器狀態,需通過 RPC 或變量復制同步


      將WeaponState設置為復制變量:



      Set Equip Animation Pose

      先將EquippedWeapon設置為復制變量,確保當一個客戶端改變時,所有客戶端都能更新其值,從而確保所有客戶端都能看見Equip Animation Pose:


      在ShootCharacter中創建IsWeaponEquipped函數:


      在ShootAnimInstance中創建布爾類型變量bWeaponEquipped,并通過IsWeaponEquipped函數初始化其值:


      在Animation中創建Equipped的State Machine,并通過Weapon Equipped調用Blend Poses by bool來判斷是否裝備了武器:

      Add Crouch

      添加按鍵綁定:




      在C++中設置為可以下蹲:

      在動畫實例中創建并初始化bIsCrouch變量:


      添加Crouch節點:

      在藍圖中設置Crouch變量:

      Add Aim

      添加按鍵綁定:

      創建復制變量bAiming:用于服務器上Aim時,可以復制到所有客戶端,從而能在其他客戶端看見
      創建RPC函數:用于客戶端Aim時,調用服務器的Aim,從而復制到所有客戶端,從而能在其他客戶端看見



      綁定到函數:



      創建函數用于在AnimInstance中調用:


      在ShootAnimInstance中創建并初始化bAiming:


      添加瞄準動作:


      若沒有設置為復制變量,或沒有添加RPC函數,則會導致動作不同步的現象:

      正確現象:

      Blend Space Animation

      若缺少向左前、右前、左后、右后的動畫,可以通過調整其他動畫的旋轉來獲得
      創建8個方向的混和動畫:
      視頻


      設置Weight Speed防止移動抽搐:


      需要添加Module

      Shift加速

      添加按鍵綁定:


      在CombatComponent中添加 bShift復制變量 和 SetShift函數 以及 RPC函數 :



      在ShootCharacter中添加SetShift函數:

      設置Camera不阻擋角色視角

      設置AimOffset

      根據玩家鼠標移動調整角色的頭部和武器方向
      通過在Tick中調用AimOffset函數來實時獲取Yaw和Pitch的值:




      在ShootAnimInstance中創建并初始化Yaw和Pitch:


      在虛幻中創建AimOffset:

      將需要用到的動畫的Base Pose全部設置為Idle動畫:

      設置AimOffset:

      存儲Equipped:


      動畫混合:將Lower body的動畫設置為Equipped,將Upper body的動畫設置為頭部的移動:


      設置Hand IK

      確保左手在武器的合適位置
      在武器上分別添加Idle和Aim時的LeftHandSocket:


      在Weapon中添加獲取WeaponMesh的函數:

      在ShootCharacter中獲取EquippedWeapon:


      創建LeftHandTransform并初始化:


      設置FABRIK:




      實時調整Socket,確保左手在合適位置:

      Turn in place

      Turn Animations
      創建Meradata用于判斷是否處于該動畫狀態:


      Force Root Lock:




      創建站立和蹲下的Idle和Aim的State Machine:



      創建Turn Left和Turn right:

      混合動畫:



      Rotate Root Bone

      角色轉向時移動方向
      初始化Interp(插值變量)AO_Yaw:


      平滑轉動:


      設置網絡更新頻率




      [/Script/OnlineSubsystemUtils.IpNetDriver]
      NetServerMaxTickRate=120
      

      在不同地形設置不同的Meta Sounds

      創建Meta sounds:

      在設置中添加不同的材質名稱:

      創建不同的物理材質:


      將物理材質的Suface Type改為對應設置中的名稱:


      在藍圖中創建Anim Notify:




      在C++中創建Anim Notify:


      創建BP類:

      添加Sync Marker(同步標記):

      添加Anim Notify:


      在實際地圖中設置不同的物理材質:

      Projectile Weapon


      投射武器:
      1.生成彈丸:發射具體的彈藥。
      2.具有速度:彈丸有一定的運動速度。
      3.可能有/沒有重力:彈丸的運動可能受到重力影響,也可能不受影響。
      4.命中事件:形成特定的命中效果。
      5.追蹤粒子:通常在飛行過程中可見的軌跡。
      命中掃描武器:
      1.執行直線追蹤:通過射線檢測目標。
      2.瞬時命中:發射后立即造成傷害。
      3.光束粒子:通常以光束形式表現。
      創建一個Weapon子C++類:


      創建子彈的C++類:


      Fire Montage

      綁定Fire按鍵:

      設置Fire和Fire_Aim的Addictive Settings:

      創建Fire Montage動畫,并Add Slot:

      在Aim Offsets之前使用蒙太奇動畫:


      在CombatComponent中創建 FireButtonPressed函數 和 bFireButtonPressed變量:


      在ShootCharacter中綁定輸出,并創建PlayFireMontage函數和變量



      Fire Effects Animation

      創建Fire動畫函數并調用:



      設置Weapon動畫:

      添加Projectile Weapon藍圖:

      使用NetMulticast RPC

      使服務器和客戶端都能看見Fire:


      Component Tick Problem

      問題:Component的Tick函數失效
      原因:在編輯器打開的情況下創建一個組件并進行編譯,構造函數不會再次運行,因為它在你第一次打開編輯器時已經運行過了。
      由于構造函數沒有第二次運行,因此創建的默認對象和庫(包括靜態庫和動態鏈接庫)不會被更新,導致編輯器中沒有反映出任何更改。
      藍圖知道組件的存在,因為C++告訴它有這個組件,但除此之外,藍圖并不知道其他信息。
      通過更改組件的名稱并重新編譯,可以將更改推送到CDO和庫中,從而使更改在編輯器中反映出來**

      通過十字準星獲取Hit Target




      設置偏移量,確保準星在人物右上方:

      Spawn Projectile

      在槍口位置添加Socket:

      添加HitTarget變量并初始化:


      在ProjectileWeapon中重載Weapon的Fire函數并Spawn子彈:


      創建子彈的藍圖類:


      Set Projectile Movement Component

      設置子彈的運動組件:

      使子彈的旋轉跟隨其速度方向:

      設置子彈的速度:


      添加Tracer:


      設置子彈的Replicated屬性

      將Fire函數設置為僅在服務器執行:

      將子彈設置為可復制:當子彈被發射時,它的狀態(位置、速度、碰撞等)需要在所有客戶端上保持一致

      Replicate Hit Target



      FVector_NetQuantize:用于網絡傳輸向量數據的一種類型,旨在減少網絡帶寬的使用并提高性能
      通過在RPC中使用FVector_NetQuantize來復制Hit Target:

      添加子彈擊中音效和粒子




      生成彈殼

      在武器中添加彈殼的Socket:

      創建彈殼的C++類:


      創建彈殼的Mesh:


      在Weapon中Spawn彈殼:


      創建彈殼的藍圖類:

      為彈殼添加速度和音效

      修改彈殼的顏色:
      將父類混合材質的Emissive Color設置為變量:

      將子類混合材質復制一份單獨給彈殼使用:


      修改彈殼顏色:

      為彈殼添加速度和音效:

      添加十字準星

      PlayerController中有獲取HUD的函數,HUD中可以繪制HUD:

      創建Player Controller C++類:


      創建HUD C++類:


      創建Player Controller 藍圖類:


      創建HUD 藍圖類:


      在ShootingGameMode中配置PlayerController和HUD:

      在Weapon中設置準星:確保每個武器可以配置不同的準星樣式

      在 ShootHUD 中創建準星貼圖Struct并在 CombatComponent 組件中配置準星貼圖,在由 DrawHUD 根據配置每秒繪制各個方向的準星:


      先獲取PlayerController,再通過PlayerController來獲取HUD:

      先獲取到HUD,再通過HUD->SetHUDPackage()函數來配置從Weapon中獲取到的準星材質,最后每幀通過戰斗組件的TickComponent調用SetHUDCrosshairs:

      導入素材并在Weapon中配置:

      制作動態準星

      創建不同的準星擴散:

      根據角色狀態調整準星擴散值:


      再HUD中應用擴散值:


      設置射擊時擴散準星:


      修正槍口方向與準星方向一致

      在Combat的Tick函數中時刻獲取HitTarget:


      在ShootCharacter中添加獲取Target的函數:


      在AnimInstance中添加RightHandRotation用于在藍圖中調整:

      只允許當地角色調整槍口方向與準星方向一致:

      重構藍圖實例:

      在Transform_Hand中添加FRABRIC中的內容并添加修正右手的內容:
      只允許當地角色調整槍口方向與準星方向一致:


      刪除FABRIC的state machine,重新使用Aim Offset:


      通過調整RightHandSocket來確保兩線重合:

      設置相機FOV實現瞄準時視角縮放

      設置腰射瞄準時Camera Boon的Offset

      不需要調整Camera
      需要將Camera Boom的Location調整到對著角色的腦袋,并在C++中設置Camera Boom的Socket Offset:


      初始化Socket Offset:

      在Combat中定義Camera Boom的默認Offset和瞄準Offset:


      在Tick函數中時刻更新:

      使用插值函數VInterpTo來實現Camera Boom Offset的平滑移動:

      必須要保證Y軸和Z軸偏移量相同,否則瞄準時準星將偏移:

      效果:

      Change Crosshairs Color

      擴展準星開始位置修復準星Bug

      由于Trace Start從相機開始,所以當有物體在Camera和Character之間時,會導致準星錯誤的識別到后面的物體:



      修復:在Start基礎上加上 相機到角色的距離 和 額外的距離:

      設置近距離不穿模


      將Near Clip Plane降低為2并重啟UE:

      Add Hit Reactions

      設置蒙太奇動畫:





      Play Montage動畫:




      由于Projectile忽略了Pawn,但如果Block Pawn,則會導致子彈對Capsule有碰撞,需要的是對Mesh有碰撞

      需要自定義一個Object Type:SkeletalMesh:

      在藍圖中將Mesh的Object Type設置為自定義Type:

      在MP_Shoot中定義ECC_GameTraceChannel1為SkeletalMesh,便于使用:

      在C++中將Mesh的Object Type設置為自定義Type:

      在Projectile中設置子彈忽略自定義Channel:

      Automatic Fire

      在Weapon中添加 延遲 和 是否自動射擊 變量:

      添加計時器,防止頻繁射擊:

      設置平滑相機

      游戲框架




      Add Health

      由于Player State網絡更新較慢,所以在Character中更新Health:

      創建Widget C++類:


      創建Widget藍圖類:



      在ShootCharacter中初始化Health:


      在CharacterOverlay中初始化變量:

      在ShootHUD中Create Widget:

      Update Health

      HUD中能Create Widget,PlayerController能獲取HUD,在PlayerController中創建更新Health的函數,在Character中能獲取PlayerController并調用該函數:

      在PlayerController中創建更新Health的函數:


      在Character中獲取PlayerController并調用該函數:

      Damage

      創建Projectile的C++子類,用于實現不同Damage的邏輯:


      在Projectile的projected部分創建Damage變量:

      在子類中繼承父類的OnHit函數:

      調用ApplyDamage函數:

      在ShootCharacter中創建ReceiveDamage函數:

      綁定ReceivedDamage函數:

      利用復制變量來更新Health HUD:

      創建藍圖類:


      在步槍中將子彈改為BP_ProjectileBullet:

      Elimination

      創建ShootGameMode來處理淘汰邏輯:


      修改BP_ShootingGameMode的父類為ShootGameMode C++類:

      GameMode 的 PlayerEliminated 函數負責調用角色上的 Elim 函數:


      在ShootCharacter中創建淘汰動畫函數和RPC函數:


      創建是否淘汰變量:


      在Health為0時,調用GameMode的淘汰函數:

      在AnimInstance中創建淘汰變量:


      創建淘汰蒙太奇動畫:

      防止角色死亡后站起:

      在動畫藍圖中使用Slot:

      Respawn

      在GameMode中創建復活函數:


      在ShootCharacter中創建延遲計時器:


      確保角色總能Spawn成功:

      Disable Collision and Movement

      淘汰時禁用移動和射擊,并設置為NoCollision:

      Drop Weapon

      在Combat中創建EquippedWeapon的回調函數,確保在其改變時,調用該函數:


      在Weapon中添加丟棄武器函數:

      設置Weapon State,確保調用WeaponState的回調函數:

      配置丟棄武器時,武器的狀態:

      在淘汰函數中調用丟棄武器函數:

      修復復活后血條未初始化問題

      在Character中獲取Health和MaxHealth:

      在PlayerController中重載OnPossess方法:當控制器擁有一個新的Pawn時,會調用這個方法:

      在該函數中更新Health HUD:

      修復當Travel時,由于Health未初始化導致Travel失敗的問題

      Dissolve Material

      創建Material:


      創建Material Instance:

      Score

      在CharacterOverlay中添加Score:

      創建PlayerState C++類 用于記錄得分:


      在CharacterOverlay中創建Score Text:

      在PlayerController中設置HUD的Score Text:


      在PlayerState中存儲Score并調用Controller中的函數來顯示:


      在角色死亡時,為AttackCharacter調用PlayerState中的AddToScore函數:

      因為PlayerState無法在BeginPlay中初始化,所以創建PollInit函數初始化Score為0并在Tick中調用:




      創建PlayerState 藍圖類:

      在GameMode中配置PlayerState:

      Defeats

      在CharacterOverlay中添加Defeats:

      在CharacterOverlay中創建Defeats Text:

      在PlayerController中設置HUD的Defeats Text:


      在PlayerState中存儲復制變量Defeats并調用Controller中的函數來顯示:



      在角色死亡時,為AttackCharacter調用PlayerState中的AddToDefeats函數:

      因為PlayerState無法在BeginPlay中初始化,所以創建PollInit函數初始化Defeats為0并在Tick中調用:

      Weapon Ammo

      先在Character Overlay中創建Ammo Text:

      在Character Overlay中初始化Ammo Text:

      在Controller中創建配置HUD的函數:


      在Weapon中創建 使用Controller中函數 的函數 并 重載Owner的回調函數 用于新角色撿起武器時更新Ammo:

      創建Ammo,Ammo的回調函數,消耗一發子彈的函數,Mag Capacity(彈匣的容量):

      復制Ammo:


      在Fire函數中調用SpendRound函數,即消耗一發子彈:

      若存在武器,則丟棄原有武器,更新Server的彈藥:

      角色淘汰時,隱藏Ammo:

      初始化Ammo和Mag Capacity(彈匣的容量):

      當武器子彈為0時,不可射擊:


      Carried Ammo

      先在Character Overlay中創建CarriedAmmo Text:

      在Character Overlay中初始化CarriedAmmo Text:

      在Controller中創建配置HUD的函數:


      創建WeaponType的枚舉類型,從而根據不同類型的武器,來配置不同的攜帶子彈:


      在Weapon中創建WeaponType并在編輯器中配置:

      在Combat中創建Map來連接 武器類型 和 對應的攜帶子彈數量,使用StartingAmmo初始化不同武器的攜帶子彈數量,使用復制變量CarriedAmmo來配置當前武器的攜帶子彈數量:

      當前僅初始化了步槍的攜帶子彈數量:


      Reload

      創建換彈Input:

      創建CombatState枚舉類型:


      在Character中創建Play Montage動畫:

      將Combat設置為BlueprintReadOnly以便與在藍圖中獲?。?/strong>

      獲取CombatState:

      綁定Input:


      在AnimInstance藍圖中使用該函數:


      添加復制變量CombatState:


      在Server中Play Reload Montage并改變CombatState從而觸發復制函數,同步到客戶端:

      在AnimInstance中創建bool,是否使用左手的FABRIC,AimOffset和右手Transform:

      Reload時,不使用:

      創建蒙太奇動畫:

      將Slot設置為WeaponSlot:

      創建Reload Finished Notify:

      當到達該Notify時,調用函數結束Reload:

      將Transform Hands分為Right Hand 和 Both Hand:

      Transform Hands,若在Reload,則不使用FABRIC:

      Right Hand,若在Reload,則不使用Transform Bone:

      Both Hand:

      Aim Offsets,若在Reload,則不使用AimOffset:

      換彈中持續按開火鍵,結束后執行Fire:

      換彈時,不可以Fire:

      Update Ammo

      換彈時,計算子彈數量:

      在Weapon中創建添加子彈,獲取子彈和彈夾中子彈數量:



      獲取換彈的子彈數量,更新子彈:

      在完成換彈后更新子彈:

      Add Weapon Sounds

      在Weapon中添加Equip Weapon音效:

      在Combat的EquipWeapon函數中Play Sounds:

      在復制函數中Play Sounds:

      添加換彈音效:

      Auto Reload

      自動換彈:


      滿彈夾不換彈:

      Game Time

      添加比賽倒計時:





      在Overlay中創建Text:

      ServerRequestServerTime 和 ClientReportServerTime 函數一起工作,通過測量網絡往返時間來估算客戶端和服務器之間的時間差,并將這個時間差存儲在 ClientServerDelta 變量中。 GetServerTime 函數使用這個時間差來返回一個與服務器同步的時間

      ReceivedPlayer函數在玩家連接后立即啟動時間同步過程:
      CheckTimeSync函數在Tick中每隔TimeSyncFrequency秒更新一次時間:



      熱身時間

      GameMode是GameModeBase的子類,具有GameModeBase的屬性以及Match State:
      若要使用Match State,則需要使用GameMode類:

      Match States有自帶的變量和函數:

      可以在InProgress中創建自定義變量:

      等待階段->熱身時間->開始游戲:

      可以通過AGameMode查看自帶的變量和函數:

      創建熱身時間:

      設置bDelayedStart為true,確保不自動Start Match:
      剩余時間結束后調用Start Match函數來Spawn Character:

      熱身時間不顯示SlashOverlay

      GameMode中的OnMatchStateSet函數:當MatchState改變時調用對應的函數

      在ShootGameMode中重載該函數

      遍歷所有Controller,并調用Controller中的OnMatchStateSet函數以用于判斷是否顯示HUD:

      在Controller中添加OnMatchStateSet函數:

      添加復制變量MatchState:


      設置MatchState變量,若MatchState為InProgress,則顯示SlashOverlay:

      刪除BeginPlay中的AddCharacterOverlay函數,只有在InProgress時才顯示SlashOverlay:

      修復游戲開始時沒有初始化Overlay的Bug

      由于CharacterOverlay最后才初始化,所以無法在CharacterOverlay初始化之前設置HUD的值
      創建變量用于各種存儲HUD的值:

      若沒有初始化,則暫存各個HUD的變量值:

      如果CharacterOverlay沒有初始化,則在Tick中直到其初始化,設置CharacterOverlay中HUD的值:

      顯示熱身時間

      創建Announcement C++類:



      創建藍圖類:


      創建熱身時間變量:

      在ShootHUD中添加該類和變量以及函數,用于顯示Announcement Widget到屏幕上:


      在PlayerController的BeginPlay中調用HUD的函數添加熱身時間到屏幕:

      在PlayerController中的InProgress中隱藏熱身時間:

      更新熱身時間

      在GameMode中初始化需要的時間:

      在Controller中創建設置熱身時間HUD的函數:

      創建服務器和客戶端檢查MatchState的函數 和 用于存儲時間的變量:



      Cooldown Match State

      根據GameMode中的Match State添加自定義Match State:

      添加結算狀態的Match State并添加結算時間:

      初始化結算狀態,在Tick中若剩余時間為0則將MatchState設置為Cooldown:

      在Controller中設置Handle Cooldown的函數:

      在OnMatchStateSet中若MatchState為Cooldown,則進入該函數:

      更新Cooldown Time

      創建Announcement Text:


      在GameMode中獲取倒計時:

      設置Cooldown時的倒計時:

      設置Cooldown Time:


      若倒計時為負數,則不顯示倒計時Text:

      服務器直接從GameMode中獲取倒計時,否則會有延遲:

      添加Cooldown Text:

      Restart Game

      冷卻時間內,設置角色靜止且無法操作:
      添加復制變量bDisableGameMode:


      除了Turn和LookUp,禁用其他按鍵綁定:

      禁用AimOffset,并且將bUseControllerRotationYaw設置為false,TurningInPlace設置為NotTurning:

      在角色淘汰時,將bDisableGamePlay設置為True,并且若淘汰時正在Fire,則將FireButtonPressed設置為false:

      在冷卻時間內,將bDisableGamePlay設置為True,將FireButtonPressed設置為false,SetAiming為false:

      當冷卻時間結束時,調用自帶函數RestartGame來重啟游戲:

      Game State

      在Game State中存儲得分最高的玩家 并 在冷卻時間在屏幕上顯示最高得分玩家:
      創建GameState C++類:


      創建GameState 藍圖類:


      在GameMode中設置Gaem State Class:

      在GameState中創建最高得分玩家的數組 和 更新該數組的函數:


      在GameMode中的淘汰函數中添加 更新最高得分玩家的函數:

      在處理Cooldown函數中,根據最高得分玩家來設置Announcement中的Info Text:

      火箭筒

      創建Projectile的C++子類:

      創建炮彈:

      創建藍圖類炮彈:

      添加重載函數OnHit:

      在OnHit中執行范圍傷害:

      在WeaponType中添加火箭筒變量:

      在Combat中初始化攜帶的炮彈數量:


      設置火箭筒的換彈動畫:

      創建火箭筒武器的藍圖類:


      創建LeftHandSocket并調整:

      Rocket Trail

      修復火箭筒發射時炸到自己

      為火箭筒單獨創建一個子彈的Movement Component:


      重載處理碰撞邏輯的函數:

      當火箭筒遇到阻擋時,繼續前進:

      在Rocket中初始化RocketMovementComponent:


      若Hit的是自己,則return:

      將Weapon的Movement設置為復制的,防止武器位置不匹配:

      將Projectile中的MovementComponent移動到Protected中,并刪除其初始化,讓每個Projectile都有唯一的Movement組件:

      在ProjectileBullet中初始化Movement組件:

      修復火箭筒爆炸時TrailSmoke瞬間消失

      延遲銷毀炮彈:


      設置定時器后,立即銷毀Mesh,Box,停止TrailSmoke生成新的粒子但沒有消失,過3秒后,讓TrailSmoke消失:

      Hit Scan Weapon

      通過射線檢測實現:當玩家按下開火鍵時,子彈會瞬間命中目標,不需要模擬真實的彈道飛行時間
      創建Scan Weapon的C++類:


      創建Scan Weapon的藍圖類:

      創建子彈類:



      為武器的帶子創建物理模型,讓其飄動

      散彈槍和隨機散射

      添加ShotGunWeapon的C++類:


      添加ShotGunWeapon的藍圖類:

      在Weapon中創建設置散射的變量 和 獲取隨機散射角度的函數:


      在ProjectileWeapon中使用隨機彈道:

      在ShotGunWeapon中創建散彈槍碎片數量:

      使用for循環來Spawn多個Projectile:

      添加瞄準鏡

      在Animation中設置新的Aim Offset,之前的Aim Offset會導致開鏡后無法上下動:




      添加一個圓柱體到瞄準鏡里面,用做鏡片:

      將兩者合并為一個StaticMesh:

      創建瞄準鏡的準星Texture和Material:

      將準星材質應用到鏡頭的材質上,圖中是1,并記住鏡片材質的編號,圖中是2:

      為每個武器創建不同的Camera的Socket,Scope的Socket,以及SceneCapture2D的Socket:


      實現右擊開鏡的邏輯:
      在Weapon中添加開鏡時間,開鏡后移動的速度降低,添加武器的Camera:

      在Combat中添加是否開鏡的變量和函數:



      在Character中添加按鍵綁定并判斷是點擊還是長按:

      點按:Scoping+Aiming
      長按:Aiming

      若開鏡射擊,則必須射擊到瞄準鏡準星上
      若開鏡射擊,則將射擊點設置到SceneCapture2D上,并沿著瞄準鏡方向發射子彈:

      添加配件的C++類:

      添加Attachment的子類:Scope類,用作瞄準鏡

      創建用于鏡片的材質:

      將Texture的名字更改為ScopeTexture,下面會在C++中用到:

      將材質應用到BP_Scope上:

      設置Attachment基類:


      設置Scope子類:

      設置鏡片的材質:


      在Weapon中添加SceneCaptureComponent2D,用于決定瞄準鏡的觀察:

      初始化武器相機位置,即不裝備瞄準鏡時相機的位置:

      調用Attachment的多態函數EquipToWeapon,實際上調用的是Scope的重載函數:

      在ShootCharacter中創建OverlappingAttachment,用于顯示PickUpWidget:






      添加Zoom按鍵綁定,當開鏡時可以調整放大縮?。?/strong>


      榴彈炮

      創建炮彈類:

      允許炮彈彈跳:




      換彈動畫(Reload Animations)

      創建Mag_Hand Socket:

      創建Anim Notify:

      在Weapon中創建函數:




      在Combat中使用函數:



      添加彈夾和空彈夾:

      散彈槍換彈動畫(Shotgun Reload Animation)

      每一發進行換彈,并在換彈時可以射擊:

      創建ShotgunShellReload,在AnimNotify中使用:


      每次Update,子彈+1 -1,若子彈滿了或沒有備彈了,則在服務器JumpToEnd:

      若沒有備彈了,則在客戶端JumpToEnd:

      若子彈滿了,則在客戶端JumpToEnd:

      散彈槍在換彈時可以Fire


      在Montage中添加多個Shell和Loop和ShotGunEnd:
      將Shell的TickType設置為Branching Point,防止客戶端由于動畫中使用Blend per bone導致一個動畫使用兩次從而導致散彈槍在客戶端一次reload兩個子彈:

      發光輪廓

      創建Post Volume并設置為無限大:

      Material:https://github.com/DruidMech/MultiplayerCourseBlasterGame/tree/main/GameAssets/Materials
      設置Post Volume的Materials:

      在藍圖中設置Custom Depth:

      在C++中設置:
      將Custom Depth Stencil Pass設置為Enabled with Stencil:

      添加不同顏色:
      武器與角色重合時發光,裝備后不發光:






      使用數組修復PickupWidget和Equip Weapon




      問題:Montage動畫被打斷導致無法到達AnimNotify

      當為蒙太奇動畫創建AnimNotify時,由于蒙太奇動畫會被其他動畫打斷,所以AnimNotify可能永遠不會執行:
      為每個有AnimNotify的蒙太奇動畫創建 打斷/結束 事件:
      屏幕截圖 2025-07-13 182555
      屏幕截圖 2025-07-13 182615

      手榴彈

      ShootCharacter.h:

      創建擊中點Mesh和樣條線,以及裝備的手雷:


      ShootCharacter.cpp:

      初始化組件:

      裝備手雷函數:




      右鍵按下時切換手雷 低拋/高拋 瞄準:

      左鍵按下時手雷瞄準,R鍵按下時手雷拉環:

      死亡后清除軌跡和擊中點:

      Play手雷的蒙太奇動畫:

      Grenade.h:


      Grenade.cpp:

      倒計時結束后實行范圍傷害:


      CombatComponent.h:




      CombatComponent.cpp:









      設置Montage Animation:


      設置樣條線軌跡和擊中點:



      后坐力系統




      第一人稱Arm和Weapon









      High Ping Warning








      方法一:簡單快速:

      方法二:可以在打包后進行測試:
      屏幕截圖 2025-07-03 213827

      添加 Local Fire 減輕延遲影響



      Show PickupWidget Locally

      Client-Side Prediction

      Prediction For Ammo

      取消Ammo的復制屬性,并添加RPC和Sequence用于預測客戶端子彈消耗:


      Prediction For Aiming

      解決快速Aiming時由于Lag導致本地玩家的瞄準狀態被網絡復制的值覆蓋:


      Prediction For Reloading





      Server Side Rewind 服務器端倒帶

      添加延遲補償組件:
      屏幕截圖 2025-06-26 134025
      添加Box組件:
      屏幕截圖 2025-06-26 200108
      屏幕截圖 2025-06-26 200120
      讓角色禁止:
      屏幕截圖 2025-06-26 184634
      先隱藏所有Box組件:
      屏幕截圖 2025-06-26 184816
      為每個Box組件設置合適的位置與Extent而不是放大縮小:
      屏幕截圖 2025-06-26 200013
      完成后在游戲中展示所有Box:
      屏幕截圖 2025-06-28 164105
      查看蹲下等動作的Box是否合適:
      屏幕截圖 2025-06-28 164129
      創建Box的Struct以存儲信息,并創建每一幀的Struct用于記錄每一幀Box的位置:
      屏幕截圖 2025-06-28 173428
      設置LagCompensationComponent并初始化:
      屏幕截圖 2025-06-28 163027
      屏幕截圖 2025-06-28 163055
      屏幕截圖 2025-06-28 163109
      添加Name:Box的Map用于存儲Box:
      屏幕截圖 2025-06-28 174746
      將每個Box添加到Map中:
      屏幕截圖 2025-06-28 174849
      創建保存FramePackage和展示FramePackage的函數:
      屏幕截圖 2025-06-28 174953
      先創建BoxInformation獲取所有Box的信息,再將BoxInformation存儲到FramePackage中:
      屏幕截圖 2025-06-28 175517
      屏幕截圖 2025-06-28 173307
      創建雙向鏈表用于存儲FramePackage:
      屏幕截圖 2025-06-28 190757
      在Tick中在Head存儲每幀的FramePackage,若超過最大記錄時間,則在Tail刪除節點:
      屏幕截圖 2025-06-28 190934
      屏幕截圖 2025-06-28 190644
      Server Side Rewind,先創建一個Struct用于判斷是否擊中 并 判斷是否為HeadShot:
      屏幕截圖 2025-06-29 190638
      確定FrameToCheck:
      屏幕截圖 2025-06-29 190704
      通過插值函數來找到YoungerTime與OlderTime之間的HitTime的Package:
      屏幕截圖 2025-06-29 190720
      存取當前HitCharacter的Box位置,然后將HitCharacter的Box通過MoveBoxes函數移動到FrameToCheck的位置,射線判斷結束后還原Box的位置并將Box的Collision設置為NoCollision:
      屏幕截圖 2025-06-29 190803
      通過LineTranceSingleByChannel確定是否擊中了Box,需要先隱藏Mesh的Collision,顯示Box的Collision。先判斷是否為HeadShot,再判斷其他:
      屏幕截圖 2025-06-29 190732

      添加ServerScoreRequest函數:
      屏幕截圖 2025-07-03 212556
      若倒帶函數判斷擊中了,則ApplyDamage:
      屏幕截圖 2025-07-03 212626
      將Tick中的代碼整合到SaveFramePackage函數中:
      屏幕截圖 2025-07-03 212610
      創建客戶端到服務器傳輸數據的單程時間:
      屏幕截圖 2025-07-03 212726
      屏幕截圖 2025-07-03 212732
      創建是否使用倒帶變量:
      屏幕截圖 2025-07-03 212852
      在Fire函數中,若為服務器 并 不使用倒帶,則直接ApplyDamage;若不為服務器 并 使用倒帶,則調用ServerScoreRequest函數:
      屏幕截圖 2025-07-03 212829
      重構ServerSideRewind:
      屏幕截圖 2025-07-05 234540
      屏幕截圖 2025-07-05 234530

      如果ShotGun是HitScanWeapon,則對ShotGun進行如下Server Rewind:
      屏幕截圖 2025-07-05 234335
      屏幕截圖 2025-07-05 234352
      屏幕截圖 2025-07-05 234549
      屏幕截圖 2025-07-05 234559
      屏幕截圖 2025-07-05 234610
      屏幕截圖 2025-07-05 234636
      屏幕截圖 2025-07-05 234645

      更改HitBoxCollisionType的屬性

      屏幕截圖 2025-07-11 161504
      屏幕截圖 2025-07-11 161917
      屏幕截圖 2025-07-11 172453
      更改LagComponent中所有的ECC_Visibility為ECC_HitBox:
      屏幕截圖 2025-07-11 172534
      屏幕截圖 2025-07-11 172559

      在C++中實現在編輯器同步更改屬性

      屏幕截圖 2025-07-10 201825
      屏幕截圖 2025-07-10 201834
      屏幕截圖 2025-07-10 201854
      屏幕截圖 2025-07-10 201915

      為Projectile Weapon實現Server Side Rewind

      先復制ProjectileBullet為ServerSideRewind-ProjectileBullet:
      屏幕截圖 2025-07-11 110856
      然后取消它的復制屬性:
      屏幕截圖 2025-07-11 111028
      初始化變量:
      屏幕截圖 2025-07-11 155131
      預測子彈軌跡:
      屏幕截圖 2025-07-11 155429
      創建一個新的ProjectileClass:
      屏幕截圖 2025-07-11 155518
      重構整合成一個函數:
      屏幕截圖 2025-07-11 155541
      屏幕截圖 2025-07-12 140551

      武器啟用SSR:
      1.服務器邏輯:
      如果角色是服務器且由本地控制(如主機玩家),生成復制的子彈(同步到其他客戶端)。
      如果角色是服務器但不由本地控制(如其他玩家的角色),生成非復制的子彈(僅服務器可見)。

      2.客戶端邏輯:
      如果角色是客戶端且由本地控制,生成非復制的子彈并啟用SSR。
      如果角色是客戶端但不由本地控制,生成非復制的子彈但不啟用SSR。

      武器未啟用SSR:
      僅在服務器上生成投射物,客戶端不生成任何子彈(依賴服務器同步)
      Fire函數:
      屏幕截圖 2025-07-11 155712
      屏幕截圖 2025-07-12 140801
      ServerSideRewind函數:
      屏幕截圖 2025-07-12 135939
      ConfirmHit函數:
      屏幕截圖 2025-07-12 140054
      屏幕截圖 2025-07-12 140106
      ScoreRequest函數:
      屏幕截圖 2025-07-12 140119
      在子彈的OnHit函數中使用ScoreRequest函數:
      屏幕截圖 2025-07-12 140213

      為Projectile ShotGunWeapon實現Server Side Rewind

      屏幕截圖 2025-07-12 140958

      limit Server Side Rewind

      聲明委托:
      屏幕截圖 2025-07-12 193452
      屏幕截圖 2025-07-12 193500
      屏幕截圖 2025-07-12 193510
      若高于閾值,則Broadcast:
      屏幕截圖 2025-07-12 193542
      屏幕截圖 2025-07-12 193640
      屏幕截圖 2025-07-12 193704
      屏幕截圖 2025-07-12 193720
      在裝備武器時綁定委托并檢查Ping值:
      屏幕截圖 2025-07-12 194223

      切換武器動畫

      創建Montage動畫:
      屏幕截圖 2025-07-13 162517
      屏幕截圖 2025-07-13 162526
      該變量用于判斷切換動畫是否結束:
      屏幕截圖 2025-07-13 162535
      image
      屏幕截圖 2025-07-13 162614
      在藍圖AnimNotify中使用:
      屏幕截圖 2025-07-13 162637
      屏幕截圖 2025-07-13 162657
      屏幕截圖 2025-07-13 162739
      屏幕截圖 2025-07-13 162924
      在AnimInstance中,若切換武器,則不使用Fabric:
      屏幕截圖 2025-07-13 162949
      屏幕截圖 2025-07-13 163215
      屏幕截圖 2025-07-13 164009
      屏幕截圖 2025-07-13 163238

      修復Shogun的Bug

      屏幕截圖 2025-07-13 163024
      屏幕截圖 2025-07-13 163041
      屏幕截圖 2025-07-13 180054

      Cheating and Validation

      使用驗證程序來確保重要數據未被修改:
      屏幕截圖 2025-07-13 174248
      屏幕截圖 2025-07-13 174257
      屏幕截圖 2025-07-13 174318

      Elim Announcement

      創建藍圖類:
      image
      創建Widget:
      屏幕截圖 2025-07-14 180403
      屏幕截圖 2025-07-14 180413
      在ShootHUD中創建將ElimAnnouncement添加到ViewPort的函數:
      屏幕截圖 2025-07-14 180504
      屏幕截圖 2025-07-14 180547
      在PlayerController中實現服務器淘汰事件發送給所有客戶端,客戶端根據不同的淘汰場景在 HUD 上顯示相應的信息:
      屏幕截圖 2025-07-14 180617
      屏幕截圖 2025-07-14 180649
      在ShootGameMode的PlayerEliminated函數中循環每個控制器來調用函數:
      屏幕截圖 2025-07-14 180744

      實現動態消息

      創建漸變動畫:
      屏幕截圖 2025-07-14 190732
      屏幕截圖 2025-07-14 190742
      舊消息網上走:
      屏幕截圖 2025-07-14 190913
      屏幕截圖 2025-07-14 190952

      HeadShot For Weapon

      屏幕截圖 2025-07-15 115122
      屏幕截圖 2025-07-15 115155
      屏幕截圖 2025-07-15 115226
      屏幕截圖 2025-07-15 115241
      屏幕截圖 2025-07-15 115303
      屏幕截圖 2025-07-15 150752

      posted @ 2025-01-23 16:26  pone1  閱讀(86)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲AV无码久久精品日韩| 亚洲欧美人成人综合在线播放 | 国内不卡不区二区三区| 中文字幕在线精品人妻| 老子午夜精品888无码不卡| 国内精品久久久久影院网站| 亚洲第一香蕉视频啪啪爽| 日韩成人无码影院| 亚洲欧美综合精品成人网站| 在线日韩日本国产亚洲| 亚洲更新最快无码视频| 亚洲成a∨人片在线观看不卡| 精品偷拍一区二区三区| 亚洲日韩一区二区| 深夜释放自己在线观看| 男人的天堂av一二三区| 国产99青青成人A在线| 国产激情一区二区三区在线| 深夜释放自己在线观看| 欧美精品高清在线观看| 亚洲2022国产成人精品无码区| 亚洲成av人片天堂网无码| 久久人人97超碰精品| 好吊妞人成视频在线观看| 麻豆精品一区二正一三区| 午夜成人理论无码电影在线播放| 公天天吃我奶躁我的在线观看| 亚洲色大成网站www永久男同 | 香河县| 国产精品制服丝袜白丝| 国产乱妇乱子视频在播放| 国产亚洲精品AA片在线播放天| 中文字幕在线亚洲精品| 97国产成人无码精品久久久| 日本大片在线看黄a∨免费| 亚洲AVAV天堂AV在线网阿V| 亚洲夜色噜噜av在线观看| 国产在线观看免费观看| 成人综合婷婷国产精品久久蜜臀| 久久婷婷大香萑太香蕉AV人| 一本无码av中文出轨人妻|