Procházet zdrojové kódy

兔子关卡联机

lvjincheng před 4 roky
rodič
revize
6324a6bdfe
29 změnil soubory, kde provedl 1413 přidání a 63 odebrání
  1. 605 2
      Assets/BowArrow/Resources/Prefabs/Views/RankView.prefab
  2. 7 2
      Assets/BowArrow/Scenes/GameChallengeScene/ChallengeGameMode.cs
  3. 18 2
      Assets/BowArrow/Scenes/GameChallengeScene/HunterGameSettleView.cs
  4. 16 0
      Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGamePlayerScoreCounter.cs
  5. 11 0
      Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGamePlayerScoreCounter.cs.meta
  6. 35 11
      Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGameView_LocalPK.cs
  7. 100 9
      Assets/BowArrow/Scenes/GameChallengeScene/Rabbit.cs
  8. 3 0
      Assets/BowArrow/Scenes/GameChallengeScene/RabbitHuntGameMode.cs
  9. 1 1
      Assets/BowArrow/Scripts/CommonConfig.cs
  10. 2 0
      Assets/BowArrow/Scripts/Game/Arrow.cs
  11. 38 5
      Assets/BowArrow/Scripts/Game/ArrowCamera.cs
  12. 10 0
      Assets/BowArrow/Scripts/Game/TargetAnimal.cs
  13. 9 1
      Assets/BowArrow/Scripts/Manager/GameMgr.cs
  14. 42 2
      Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/ArrowSync.cs
  15. 36 0
      Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/RabbitSyncData.cs
  16. 11 0
      Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/RabbitSyncData.cs.meta
  17. 16 0
      Assets/BowArrow/Scripts/Manager/GameMode/OnlinePKTest.cs
  18. 11 0
      Assets/BowArrow/Scripts/Manager/GameMode/OnlinePKTest.cs.meta
  19. 13 5
      Assets/BowArrow/Scripts/Manager/GameMode/PKGameMode_OnlinePK.cs
  20. 6 1
      Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_LocalPK.cs
  21. 375 0
      Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_OnlinePK.cs
  22. 11 0
      Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_OnlinePK.cs.meta
  23. 5 0
      Assets/BowArrow/Scripts/Manager/GameMode/WolfHuntGameMode_LocalPK.cs
  24. 5 1
      Assets/BowArrow/Scripts/Manager/GameMode/YejiHuntGameMode_LocalPK.cs
  25. 4 1
      Assets/BowArrow/Scripts/Network/SocketPlayer.cs
  26. 3 4
      Assets/BowArrow/Scripts/Network/UserPlayer.cs
  27. 7 7
      Assets/BowArrow/Scripts/View/PKGameSettleView.cs
  28. 8 4
      Assets/BowArrow/Scripts/View/PKMatchingView.cs
  29. 5 5
      Assets/BowArrow/Scripts/View/RankView.cs

+ 605 - 2
Assets/BowArrow/Resources/Prefabs/Views/RankView.prefab

@@ -320,6 +320,85 @@ MonoBehaviour:
     m_VerticalOverflow: 0
     m_LineSpacing: 1
   m_Text: "\u56FD\u5BB6"
+--- !u!1 &4868626077579382378
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4750727927633246154}
+  - component: {fileID: 8278285284904108403}
+  - component: {fileID: 1333441395956434271}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &4750727927633246154
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4868626077579382378}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 5790944857696283716}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8278285284904108403
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4868626077579382378}
+  m_CullTransparentMesh: 1
+--- !u!114 &1333441395956434271
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4868626077579382378}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 1ad2cf6c2f09744489d8c60b3fe3bab2, type: 3}
+    m_FontSize: 20
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u91CE\u9E21\u95EF\u5173PK"
 --- !u!1 &5035129765619884284
 GameObject:
   m_ObjectHideFlags: 0
@@ -395,6 +474,206 @@ MonoBehaviour:
   m_FillOrigin: 0
   m_UseSpriteMesh: 0
   m_PixelsPerUnitMultiplier: 1
+--- !u!1 &5069818613333091997
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 385094491447534090}
+  - component: {fileID: 6167912902804215099}
+  - component: {fileID: 7901233949644201254}
+  - component: {fileID: 3812206686544494114}
+  m_Layer: 5
+  m_Name: BtnTab1
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &385094491447534090
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5069818613333091997}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 59179234504702565}
+  m_Father: {fileID: 5531302799040942389}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 140, y: 54}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &6167912902804215099
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5069818613333091997}
+  m_CullTransparentMesh: 1
+--- !u!114 &7901233949644201254
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5069818613333091997}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: c47a37ca02f38af4ebddf3df3de7273e, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &3812206686544494114
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5069818613333091997}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 7901233949644201254}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls: []
+--- !u!1 &5347140485885614652
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 59179234504702565}
+  - component: {fileID: 3367789342090389185}
+  - component: {fileID: 2602637349329257045}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &59179234504702565
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5347140485885614652}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 385094491447534090}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &3367789342090389185
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5347140485885614652}
+  m_CullTransparentMesh: 1
+--- !u!114 &2602637349329257045
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5347140485885614652}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 1ad2cf6c2f09744489d8c60b3fe3bab2, type: 3}
+    m_FontSize: 20
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u91CE\u5154\u95EF\u5173PK"
 --- !u!1 &5531302797138384335
 GameObject:
   m_ObjectHideFlags: 0
@@ -1942,7 +2221,7 @@ MonoBehaviour:
   m_TargetGraphic: {fileID: 5531302799128653533}
   m_HandleRect: {fileID: 5531302799128653532}
   m_Direction: 2
-  m_Value: 0
+  m_Value: 1
   m_Size: 1
   m_NumberOfSteps: 0
   m_OnValueChanged:
@@ -2064,7 +2343,7 @@ RectTransform:
   m_AnchorMin: {x: 0, y: 0}
   m_AnchorMax: {x: 0, y: 0}
   m_AnchoredPosition: {x: 0, y: 0}
-  m_SizeDelta: {x: 129, y: 54}
+  m_SizeDelta: {x: 140, y: 54}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5531302798396986682
 CanvasRenderer:
@@ -2732,6 +3011,9 @@ RectTransform:
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_Children:
   - {fileID: 5531302798396986663}
+  - {fileID: 385094491447534090}
+  - {fileID: 5790944857696283716}
+  - {fileID: 5093784077550714272}
   m_Father: {fileID: 5531302797580967972}
   m_RootOrder: 3
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -3671,6 +3953,206 @@ MonoBehaviour:
     m_VerticalOverflow: 0
     m_LineSpacing: 1
   m_Text: "\u56FD\u5BB6"
+--- !u!1 &8720175997838672107
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6912752654222811876}
+  - component: {fileID: 4361469474808502914}
+  - component: {fileID: 4601559730808017644}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6912752654222811876
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8720175997838672107}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 5093784077550714272}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &4361469474808502914
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8720175997838672107}
+  m_CullTransparentMesh: 1
+--- !u!114 &4601559730808017644
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8720175997838672107}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 1ad2cf6c2f09744489d8c60b3fe3bab2, type: 3}
+    m_FontSize: 20
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u91CE\u72FC\u95EF\u5173PK"
+--- !u!1 &8931323987653056293
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5093784077550714272}
+  - component: {fileID: 6566048745220497}
+  - component: {fileID: 1978230980168214059}
+  - component: {fileID: 5956848243840075727}
+  m_Layer: 5
+  m_Name: BtnTab3
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5093784077550714272
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8931323987653056293}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 6912752654222811876}
+  m_Father: {fileID: 5531302799040942389}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 140, y: 54}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &6566048745220497
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8931323987653056293}
+  m_CullTransparentMesh: 1
+--- !u!114 &1978230980168214059
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8931323987653056293}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: c47a37ca02f38af4ebddf3df3de7273e, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &5956848243840075727
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8931323987653056293}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 1978230980168214059}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls: []
 --- !u!1 &9024451854686393318
 GameObject:
   m_ObjectHideFlags: 0
@@ -3761,6 +4243,127 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_ShowMaskGraphic: 0
+--- !u!1 &9038984024943268064
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5790944857696283716}
+  - component: {fileID: 7977812859582727201}
+  - component: {fileID: 4005059296065482767}
+  - component: {fileID: 2278980399641433728}
+  m_Layer: 5
+  m_Name: BtnTab2
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5790944857696283716
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9038984024943268064}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children:
+  - {fileID: 4750727927633246154}
+  m_Father: {fileID: 5531302799040942389}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 140, y: 54}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7977812859582727201
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9038984024943268064}
+  m_CullTransparentMesh: 1
+--- !u!114 &4005059296065482767
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9038984024943268064}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: c47a37ca02f38af4ebddf3df3de7273e, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &2278980399641433728
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9038984024943268064}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 4005059296065482767}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls: []
 --- !u!1 &9207967438185793125
 GameObject:
   m_ObjectHideFlags: 0

+ 7 - 2
Assets/BowArrow/Scenes/GameChallengeScene/ChallengeGameMode.cs

@@ -37,9 +37,10 @@ public abstract class ChallengeGameMode : GameMode
         //变量初始化
         animalsBaseT = GameObject.Find("Animals").transform;
         hunterT = this.gameMgr.GetComponentInChildren<ArmBow>().transform;
-
+    
         //监听箭的射出,统计剩余的箭数
         GameEventCenter.ins.onBowArrowShootOut += delegate(ArmBow armBow, Arrow arrow) {
+            if (banOnBowArrowShootOut) return;
             if (arrowCount > 0) {
                 arrowCount--;
             }
@@ -94,6 +95,10 @@ public abstract class ChallengeGameMode : GameMode
 
     //当前挑战的关卡是否为狼关卡
     public static bool IsChallengeWolf() {
-        return GameMgr.gameType == 5 || GameMgr.gameType == 8; 
+        return GameMgr.gameType == 5 || GameMgr.gameType == 8 || GameMgr.gameType == 12; 
     }
+
+    #region  //网络联机新增参数
+        public bool banOnBowArrowShootOut = false;
+    #endregion
 }

+ 18 - 2
Assets/BowArrow/Scenes/GameChallengeScene/HunterGameSettleView.cs

@@ -13,8 +13,10 @@ public class HunterGameSettleView : MonoBehaviour
         string res = gameMode.Settle()[0].ToString();
         if (res == "胜利") {
             #region 
-                LoginMgr.myUserInfo.SetChallengeLevelPass(GameMgr.gameType, gameMode.currentlevel);
-                LoginMgr.myUserInfo.Save();
+                if (GlobalData.pkMatchType == PKMatchType.None) {
+                    LoginMgr.myUserInfo.SetChallengeLevelPass(GameMgr.gameType, gameMode.currentlevel);
+                    LoginMgr.myUserInfo.Save();
+                }
             #endregion
             this.transform.Find("Fail").gameObject.SetActive(false);
             AudioMgr.ins.PlayWin();
@@ -25,9 +27,23 @@ public class HunterGameSettleView : MonoBehaviour
         this.transform.Find("Btns/Btn1").GetComponent<Button>().onClick.AddListener(TryAgain);
         this.transform.Find("Btns/Btn3").GetComponent<Button>().onClick.AddListener(BackHome);
         CheckOpenNextLevelBtn(gameMode, res);
+        if (GlobalData.pkMatchType == PKMatchType.OnlinePK && res == "胜利") {
+            ChallengeGameModeLocalPK gm = (ChallengeGameModeLocalPK)gameMode;
+            int myIndex = GlobalData.playerIndexInRoom;
+            int otherIndex = (GlobalData.playerIndexInRoom + 1) % 2;
+            HunterGamePlayerScoreCounter counter = gm.getHunterGamePlayerScoreCounter();
+            int score = 10; //分数低于其他人
+            if (counter.hitScores[myIndex] > counter.hitScores[otherIndex]) {
+                score = 20; //分数高于其他人
+            } else if (counter.hitScores[myIndex] == counter.hitScores[otherIndex]) {
+                score = 15; //平分
+            }
+            UserPlayer.ins.call("rankComp.uploadGameScore", GameMgr.gameType, score);
+        }
     }
 
     void CheckOpenNextLevelBtn(ChallengeGameMode gameMode, string gameRes) {
+        if (GlobalData.pkMatchType != PKMatchType.None) return;
         Transform btnT = this.transform.Find("Btns/Btn2");
         bool open = gameRes == "胜利" && gameMode.currentlevel < 5;
         btnT.gameObject.SetActive(open);

+ 16 - 0
Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGamePlayerScoreCounter.cs

@@ -0,0 +1,16 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HunterGamePlayerScoreCounter
+{
+    public int[] hitScores = {0, 0};
+    ChallengeGameModeLocalPK gameModeLocalPK;
+    public HunterGamePlayerScoreCounter(ChallengeGameModeLocalPK gameModeLocalPK) {
+        this.gameModeLocalPK = gameModeLocalPK;
+        GameEventCenter.ins.onTargetAnimalHurt += (a, hurtValue) => {
+            int playerIndex = gameModeLocalPK.GetCurrentPlayIndex();
+            hitScores[playerIndex] += hurtValue;
+        };
+    }
+}

+ 11 - 0
Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGamePlayerScoreCounter.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4c1d97049875d7a40bd32588bdc1326d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 35 - 11
Assets/BowArrow/Scenes/GameChallengeScene/LocalPK/HunterGameView_LocalPK.cs

@@ -8,23 +8,32 @@ public class HunterGameView_LocalPK : MonoBehaviour
     int[] hitScores = {0, 0};
     int curPlayerIndex = -1;
     ChallengeGameModeLocalPK gameModeLocalPK;
+    HunterGamePlayerScoreCounter scoreCounter;
 
     void Awake() {
         gameModeLocalPK = (ChallengeGameModeLocalPK) GameMgr.ins.gameMode;
-        InitRenderPlayerInfo(0, GlobalData.localPK_playerRoleIDs[0], 0);
-        InitRenderPlayerInfo(1, GlobalData.localPK_playerRoleIDs[1], 0);
-        GameEventCenter.ins.onTargetAnimalHurt += (a, hurtValue) => {
-            
-            int playerIndex = gameModeLocalPK.GetCurrentPlayIndex();
-            hitScores[playerIndex] += hurtValue;
-            RenderScore(playerIndex, hitScores[playerIndex]);
-        };
+        scoreCounter = gameModeLocalPK.getHunterGamePlayerScoreCounter();
+        if (GlobalData.pkMatchType == PKMatchType.LocalPK) {
+            InitRenderPlayerInfo_Local(0, GlobalData.localPK_playerRoleIDs[0], 0);
+            InitRenderPlayerInfo_Local(1, GlobalData.localPK_playerRoleIDs[1], 0);
+        } else if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
+            MatchPlayerInfo info0 = GlobalData.matchPlayerInfos[0];
+            MatchPlayerInfo info1 = GlobalData.matchPlayerInfos[1];
+            InitRenderPlayerInfo_Online(0, info0.avatarID, info0.nickname, 0);
+            InitRenderPlayerInfo_Online(1, info1.avatarID, info1.nickname, 0);
+        }
     }
 
     void Update() {
         if (gameModeLocalPK.GetCurrentPlayIndex() != curPlayerIndex) {
             curPlayerIndex = gameModeLocalPK.GetCurrentPlayIndex();
-            (Sprite avatar, string nickName) = RoleMgr.GetRoleInfo(GlobalData.localPK_playerRoleIDs[curPlayerIndex]);
+            (Sprite avatar, string nickName) = (null, null);
+            if (GlobalData.pkMatchType == PKMatchType.LocalPK) {
+                (avatar, nickName) = RoleMgr.GetRoleInfo(GlobalData.localPK_playerRoleIDs[curPlayerIndex]);
+            } else if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
+                (avatar, nickName) = RoleMgr.GetRoleInfo(GlobalData.matchPlayerInfos[curPlayerIndex].avatarID);
+                nickName = GlobalData.matchPlayerInfos[curPlayerIndex].nickname;
+            }
             this.transform.Find("CurrentPlayer/Avatar").GetComponent<Image>().sprite = avatar;
             this.transform.Find("CurrentPlayer/Name").GetComponent<Text>().text = nickName;
         } else {
@@ -33,20 +42,35 @@ public class HunterGameView_LocalPK : MonoBehaviour
             this.transform.Find("CurrentPlayer/Progress").GetComponent<Image>().fillAmount = t / tMax;
             this.transform.Find("CurrentPlayer/Time").GetComponent<Text>().text = TimeUtil.GetTimeStr(t);
         }
+        //渲染得分
+        for (int i = 0; i < 2; i++) {
+            if (hitScores[i] != scoreCounter.hitScores[i]) {
+                RenderScore(i, scoreCounter.hitScores[i]);
+            }
+        }
         if (GameMgr.ins.gameOver) {
             this.transform.Find("CurrentPlayer").gameObject.SetActive(false);
         }
     }
 
-    void InitRenderPlayerInfo(int posNum, int playerID, int score)
+    void InitRenderPlayerInfo_Local(int posNum, int roleID, int score)
     {
-        (Sprite avatar, string nickName) = RoleMgr.GetRoleInfo(playerID);
+        (Sprite avatar, string nickName) = RoleMgr.GetRoleInfo(roleID);
         this.transform.Find("ScoreBox/Item" + posNum + "/Avatar/Sprite").GetComponent<Image>().sprite = avatar;
         this.transform.Find("ScoreBox/Item" + posNum + "/Name").GetComponent<Text>().text = nickName;
         RenderScore(posNum, score);
     }
 
+    void InitRenderPlayerInfo_Online(int posNum, int avatarID, string nickname, int score)
+    {
+        Sprite avatar = RoleMgr.GetAvatar(avatarID);
+        this.transform.Find("ScoreBox/Item" + posNum + "/Avatar/Sprite").GetComponent<Image>().sprite = avatar;
+        this.transform.Find("ScoreBox/Item" + posNum + "/Name").GetComponent<Text>().text = nickname;
+        RenderScore(posNum, score);
+    }
+
     void RenderScore(int posNum, int score) {
+        hitScores[posNum] = score;
         this.transform.Find("ScoreBox/Item" + posNum + "/Score").GetComponent<Text>().text = "得分: " + score.ToString();
     }
 

+ 100 - 9
Assets/BowArrow/Scenes/GameChallengeScene/Rabbit.cs

@@ -13,14 +13,56 @@ public class Rabbit : TargetAnimal
     [System.NonSerialized] public int hp = 1;
     [SerializeField] Material[] materials;
 
+    [System.NonSerialized] public int colorType = -1;
     public void ChangeColorByType(int type) {
+        colorType = type;
         GetComponentInChildren<SkinnedMeshRenderer>().material = materials[type - 1];
     }
 
+    #region 联机附加部分
+        public static HashSet<Rabbit> rabbitSet = new HashSet<Rabbit>();
+        //碰撞体
+        List<Transform> targetAnimalParts = new List<Transform>();
+        //识别ID
+        [System.NonSerialized] public int uid;
+        //是否为镜像,即只负责渲染,还有作为接收器,接收到外部输入(比如被箭击中)会通知主机
+        [System.NonSerialized] public bool isMirror;
+        public RabbitSyncData outputSyncData;
+        private RabbitSyncData _inputSyncData;
+        public RabbitSyncData inputSyncData {
+            get {
+                return _inputSyncData;
+            }
+            set {
+                _inputSyncData = value;
+                uid = value.id;
+                syncRotation.x = value.rx;
+                syncRotation.y = value.ry;
+                syncRotation.z = value.rz;
+                syncRotation.w = value.rw;
+                syncPosition.x = value.px;
+                syncPosition.y = value.py;
+                syncPosition.z = value.pz;
+            }
+        }
+        private Quaternion syncRotation;
+        private Vector3 syncPosition;
+        private bool hasUpdateBySyncData = false;
+        [System.NonSerialized] public bool isInvalid = false;  //外部运算用的
+        [System.NonSerialized] public string onHitData = null;
+        [System.NonSerialized] public bool onDoNextShootWillDestroy = false;
+        [System.NonSerialized] public int injuredID = 0;
+    #endregion
+
     void Awake()
     {
+        rabbitSet.Add(this);
         ap = GetComponent<AnimationPlayer>();
         agent = GetComponent<NavMeshAgent>();
+        if (isMirror) {
+            Destroy(agent);
+        }
+        GetTargetAnimalParts(transform, targetAnimalParts);
     }
 
     void Start()
@@ -33,8 +75,46 @@ public class Rabbit : TargetAnimal
         InitAutoStrategy();
     }
 
-    void Update()
+    void OnDestroy()
     {
+        rabbitSet.Remove(this);
+    }
+
+    void Update()
+    {   
+        if (isMirror) {
+            if (inputSyncData == null) return;
+            if (!hasUpdateBySyncData) {
+                transform.position = syncPosition;
+                transform.rotation = syncRotation;
+                hasUpdateBySyncData = true;
+            } else {
+                transform.position = Vector3.Lerp(transform.position, syncPosition, Time.deltaTime * 15);
+                transform.rotation = Quaternion.Lerp(transform.rotation, syncRotation, Time.deltaTime * 15);     
+            }
+            if (colorType != inputSyncData.ct) {
+                ChangeColorByType(inputSyncData.ct);
+            }
+            if (inputSyncData.ai != curAnimIndex) {
+                curAnimIndex = inputSyncData.ai;
+                if (IsAniForIdle()) {
+                    ap.play(curAnimIndex, WrapMode.Loop);
+                } else if (isAniJump()) {
+                    playAniJump();
+                } else if (isAniDie()) {
+                    playAniDie();
+                }
+            }
+            if (inputSyncData.ii != injuredID) {
+                injuredID = inputSyncData.ii;
+                AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject));
+            }
+            return;
+        }
+        if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
+            if (outputSyncData == null) outputSyncData = new RabbitSyncData();
+            outputSyncData.SetData(this);
+        }
         //寻路过程监测
         if (HasCloseToDestination()) {
             OnReachDestination();
@@ -46,14 +126,18 @@ public class Rabbit : TargetAnimal
         UpdateAutoStrategy();
     }
 
-    public void Disappear() {
-        Destroy(this.gameObject);
-    }
-
     public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName)
     {
         arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f;
         arrow.Hit();
+        if (isMirror) {
+            onHitData = uid.ToString() + "," + partName;
+            return;
+        }
+        OnHitLogic(arrow, partName);
+    }
+
+    public void OnHitLogic(Arrow arrow, string partName) {
         int hurtValue = 0;
         if (partName == "Leg" || partName == "Ear") hurtValue = 1;
         else if (partName == "Body") hurtValue = 2;
@@ -69,14 +153,20 @@ public class Rabbit : TargetAnimal
 
     void Die(Arrow arrow) {
         if (dead) return;
-        arrow.onDoNextShoot += delegate() {
-            Disappear();
-        };
+        if (arrow != null) {
+            arrow.onDoNextShoot += delegate() {
+                Destroy(this.gameObject);
+            };
+        } else {
+            //需要借住关卡的GameMode来清除
+            onDoNextShootWillDestroy = true;
+        }
         dead = true;
         this.agent.enabled = false;
         PuaseAutoStrategy();
         onDie?.Invoke(this);
         AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject));
+        injuredID++;
     }
 
     void Hurt() {
@@ -84,6 +174,7 @@ public class Rabbit : TargetAnimal
         addHurtFlag();
         PuaseAutoStrategy();
         AudioMgr.ins.PlayAnimalEffect("rabbit_injured", AudioMgr.GetAudioSource(this.gameObject));
+        injuredID++;
     }
     
     JC.CS.CountLocker hurtFlag = new JC.CS.CountLocker();
@@ -253,7 +344,7 @@ public class Rabbit : TargetAnimal
     }
 
     //当前动画索引
-    int curAnimIndex = 0;
+    [System.NonSerialized] public int curAnimIndex = -1;
     void playAniEat() {
         ap.play(curAnimIndex = 0, WrapMode.Loop);
     }

+ 3 - 0
Assets/BowArrow/Scenes/GameChallengeScene/RabbitHuntGameMode.cs

@@ -58,7 +58,9 @@ public class RabbitHuntGameMode : ChallengeGameMode
     float baseCreateDistance = 0;
     float plusCreateDistance = 2.5f;
 
+    public bool banCreateAnimal = false;
     void CreateAnimal() {
+        if (banCreateAnimal) return;
         if (animalCreateIndex >= animalCreateList.Length) return;
         int animalStyleID = animalCreateList[animalCreateIndex++];
 
@@ -76,6 +78,7 @@ public class RabbitHuntGameMode : ChallengeGameMode
         animalObject.SetActive(true);
 
         Rabbit rabbit = animalObject.GetComponent<Rabbit>();
+        rabbit.uid = animalCreateIndex;
         rabbit.baseDistance = createDistance;
         rabbit.baseDistanceMoveRange = plusCreateDistance;
         rabbit.hp = animalStyleID;

+ 1 - 1
Assets/BowArrow/Scripts/CommonConfig.cs

@@ -13,7 +13,7 @@ public class CommonConfig
     public static float arrowWeight = 75; 
 
     public enum ServerType {LocalTest, Produce};
-    private static ServerType serverType = ServerType.Produce;
+    private static ServerType serverType = ServerType.LocalTest;
     //业务服务端访问地址
     public static string businessServerURI {
         get {

+ 2 - 0
Assets/BowArrow/Scripts/Game/Arrow.cs

@@ -294,11 +294,13 @@ public class Arrow : MonoBehaviour
     }
 
     [NonSerialized] public int hitType = 0;
+    [NonSerialized] public Transform raycastHitTransform; //射线击中的目标变换
     //飞行逻辑中检测到碰撞
     void OnHitAnyInFlyLogic(RaycastHit raycastHit) {
         this.Head().position = raycastHit.point;
         this.transform.SetParent(raycastHit.transform.parent);
         string targetName = raycastHit.transform.gameObject.name;
+        this.raycastHitTransform = raycastHit.transform;
         if (targetName == "TargetBody") {
             Vector3 hitPoint = raycastHit.point;
             if (rayHitTargetBody && canPerfectHit) {

+ 38 - 5
Assets/BowArrow/Scripts/Game/ArrowCamera.cs

@@ -54,6 +54,8 @@ class ArrowCameraTemplate3 : ArrowCameraTemplate
     public ArrowCameraTemplate3(ArrowCamera arrowCamera)  : base(arrowCamera) {
         if (!arrowCamera.isArrowSync) {
             this.arrowCamera.arrow.activeEffectCyclone(true);
+        } else {
+            this.arrowCamera.arrowSync.activeEffectCyclone(true);
         }
     }
     
@@ -72,7 +74,8 @@ class ArrowCameraTemplate3 : ArrowCameraTemplate
         }
         Transform cameraT = this.arrowCamera.transform;
         Vector3 cameraPosition = cameraT.localPosition;
-        if (this.arrowCamera.arrow.isHit) {
+        if ((!this.arrowCamera.isArrowSync && this.arrowCamera.arrow.isHit) || 
+            (this.arrowCamera.isArrowSync && this.arrowCamera.arrowSync.isHit)) {
             cameraPosition = Vector3.Lerp(cameraPosition, cameraFinalPosition, Time.deltaTime * 6);
             cameraT.localPosition = cameraPosition;
             if (hasBlockByTree) {
@@ -84,15 +87,21 @@ class ArrowCameraTemplate3 : ArrowCameraTemplate
                 Sequence seq = DOTween.Sequence();
                 if (!quicklyNextShoot) seq.AppendInterval(1f);
                 seq.AppendCallback(delegate() {
-                    this.arrowCamera.arrow.nextShoot();
-                    this.arrowCamera.arrow.enabled = false;
+                    if (!this.arrowCamera.isArrowSync) {
+                        this.arrowCamera.arrow.nextShoot();
+                        this.arrowCamera.arrow.enabled = false;
+                    }
                     GameObject.Destroy(container?container:this.arrowCamera.gameObject);
                 });
             }
         } else {
             cameraPosition = Vector3.Lerp(cameraPosition, cameraToRunPosition, Time.deltaTime * 6);
             cameraT.localPosition = cameraPosition;
-            cameraT.LookAt(this.arrowCamera.arrow.Head());
+            if (this.arrowCamera.isArrowSync) {
+                cameraT.LookAt(this.arrowCamera.arrowSync.Head());
+            } else {
+                cameraT.LookAt(this.arrowCamera.arrow.Head());
+            }
         }
     }
     GameObject container = null;
@@ -123,13 +132,37 @@ class ArrowCameraTemplate3 : ArrowCameraTemplate
                 }
             }
         }
+        //记录需要同步的消息
+        if (!this.arrowCamera.isArrowSync) {
+            if (this.arrowCamera.arrow.outputSyncData != null) {
+                this.arrowCamera.arrow.outputSyncData.SetArrowCameraTemplate3(this.hasBlockByTree, this.quicklyNextShoot);
+            }
+        }
+    }
+    public void beforHitWhenSync(bool hasBlockByTree) {
+        this.hasBlockByTree = hasBlockByTree;
+        container = new GameObject("CameraContainer");
+        container.transform.position = this.arrowCamera.arrowSync.transform.position;
+        container.transform.rotation = this.arrowCamera.arrowSync.transform.rotation;
+        this.arrowCamera.transform.SetParent(container.transform);
+        if (hasBlockByTree) {
+            cameraFinalPosition = cameraFinalPosition_whenBlockByTree;
+            ArrowSync arrowSync = this.arrowCamera.arrowSync;
+            blockByTreeLookAtPoint = arrowSync.Head().position - arrowSync.transform.forward * 0.5f;
+        }
     }
 
-    bool quicklyNextShoot = ChallengeGameMode.IsChallengeWolf();
+    public bool quicklyNextShoot = ChallengeGameMode.IsChallengeWolf();
     public override void SendMsg(int id, object msg) {
         if (id == 0) {
             quicklyNextShoot = true;
         }
+        //记录需要同步的消息
+        if (!this.arrowCamera.isArrowSync) {
+            if (this.arrowCamera.arrow.outputSyncData != null) {
+                this.arrowCamera.arrow.outputSyncData.SetArrowCameraTemplate3(this.hasBlockByTree, this.quicklyNextShoot);
+            }
+        }
     }    
 }
 /* 模板2:从侧面看箭飞 */

+ 10 - 0
Assets/BowArrow/Scripts/Game/TargetAnimal.cs

@@ -30,4 +30,14 @@ public class TargetAnimal : MonoBehaviour
     public void RotateByWorldY(float angle) {
         transform.forward = Quaternion.AngleAxis(angle, Vector3.up) * transform.forward;
     }
+
+    public void GetTargetAnimalParts(Transform transformBase, List<Transform> outList) {
+        for (int i = 0; i < transformBase.childCount; i++) {
+            Transform child = transformBase.GetChild(i);
+            if (child.gameObject.name.StartsWith("TargetAnimalPart")) {
+                outList.Add(child);
+            }
+            GetTargetAnimalParts(child, outList);
+        }
+    }
 }

+ 9 - 1
Assets/BowArrow/Scripts/Manager/GameMgr.cs

@@ -16,6 +16,7 @@ public class GameMgr : MonoBehaviour
     void Awake() 
     {
         ins = this;
+        OnlinePKTest.Init();
         HomeMgr.HideCacheViews();
         if (Application.platform == RuntimePlatform.WindowsEditor)
         {
@@ -59,6 +60,11 @@ public class GameMgr : MonoBehaviour
         gameMode.Update();
     }
 
+    void Update()
+    {
+        gameMode.FrameUpdate();
+    }
+
     void InitGameMode() {
         if (gameType == 0) gameMode = new GameModeTest(this);
         if (gameType == 1) gameMode = new TimeLimitGameMode(this);
@@ -70,6 +76,7 @@ public class GameMgr : MonoBehaviour
         if (gameType == 7) gameMode = new YejiHuntGameMode_LocalPK(this);
         if (gameType == 8) gameMode = new WolfHuntGameMode_LocalPK(this);
         if (gameType == 9) gameMode = new PKGameMode_OnlinePK(this);
+        if (gameType == 10) gameMode = new RabbitHuntGameMode_OnlinePK(this);
     }
 
     public void StopGame() {
@@ -172,7 +179,8 @@ public abstract class GameMode
     public virtual bool DoNextShoot() { return true; }
     public virtual object[] Settle() {return null; }
     public virtual void Start() {}
-    public virtual void Update() {}
+    public virtual void Update() {} //fixedUpdate
+    public virtual void FrameUpdate() {}
     public virtual void onBowReady() {}
     public virtual void onBowShoot() {}
     public void BanBowReady() {

+ 42 - 2
Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/ArrowSync.cs

@@ -12,9 +12,13 @@ public class ArrowSync : MonoBehaviour
 
     void Update()
     {
-        transform.position = Vector3.Lerp(transform.position, position, Time.deltaTime * 15);
+        UpdatePosAndRot(Time.deltaTime * 15);
+    }
+
+    void UpdatePosAndRot(float t) {
+        transform.position = Vector3.Lerp(transform.position, position, t);
         Head().position = transform.position;
-        transform.rotation = Quaternion.Lerp(transform.rotation, rotation, Time.deltaTime * 15);     
+        transform.rotation = Quaternion.Lerp(transform.rotation, rotation, t);     
     }
 
     public Transform Head() {
@@ -53,6 +57,8 @@ public class ArrowSync : MonoBehaviour
     float mySpeed;
     bool hasPlayHitAudio = false;
     bool hasPlayHitEffect = false;
+    ArrowCamera arrowCameraComp;
+
     [System.NonSerialized] public bool isHit;
     [System.NonSerialized] public bool canUseSideCamera;
     [System.NonSerialized] public bool hasSetSyncData = false; //外部运算用的
@@ -65,6 +71,7 @@ public class ArrowSync : MonoBehaviour
         position.y = syncData.py;
         position.z = syncData.pz;
         canUseSideCamera = syncData.cs;
+        bool oldIsHit = isHit;
         isHit = syncData.ih;
         mySpeed = syncData.sp;
         if (apply) {
@@ -87,6 +94,28 @@ public class ArrowSync : MonoBehaviour
                 activeEffectCyclone(false);
                 activeEffectTrail(false);
             }
+        } else {
+            if (!oldIsHit && isHit) {
+                Transform cameraTF = this.transform.Find("Camera");
+                arrowCameraComp = cameraTF.gameObject.GetComponent<ArrowCamera>();
+                if (arrowCameraComp) {
+                    if (arrowCameraComp.arrowCameraTemplate == null) {
+                        isHit = false;
+                    } else if (arrowCameraComp.arrowCameraTemplate.GetType().Equals(typeof(ArrowCameraTemplate3))) {
+                        bool hasBlockByTree = false;
+                        if (syncData.HasArrowCameraTemplate3()) {
+                            hasBlockByTree = syncData.GetArrowCameraTemplate3().Item1;
+                        }
+                        UpdatePosAndRot(1f);
+                        ((ArrowCameraTemplate3) arrowCameraComp.arrowCameraTemplate).beforHitWhenSync(hasBlockByTree);
+                    }
+                }
+            }
+            if (syncData.HasArrowCameraTemplate3()) {
+                if (arrowCameraComp && arrowCameraComp.arrowCameraTemplate.GetType().Equals(typeof(ArrowCameraTemplate3))) {
+                    ((ArrowCameraTemplate3) arrowCameraComp.arrowCameraTemplate).quicklyNextShoot = syncData.GetArrowCameraTemplate3().Item2;
+                }
+            }
         }
         if (isHit && !hasPlayHitAudio) {
             hasPlayHitAudio = true;
@@ -123,6 +152,7 @@ public class ArrowSync : MonoBehaviour
         public bool ih;
         public int ht;
         public float sp;
+        public string act3; // ArrowCameraTemplate3
         public void SetData(Arrow arrow) {
             Quaternion r = arrow.transform.rotation;
             Vector3 p = arrow.Head().transform.position;
@@ -143,5 +173,15 @@ public class ArrowSync : MonoBehaviour
             }
             inited = true;
         }
+        public void SetArrowCameraTemplate3(bool hasBlockByTree, bool quicklyNextShoot) {
+            act3 = hasBlockByTree + "," + quicklyNextShoot;
+        }
+        public bool HasArrowCameraTemplate3() {
+            return act3 != null;
+        }
+        public System.Tuple<bool, bool> GetArrowCameraTemplate3() {
+            string[] strs = act3.Split(',');
+            return new System.Tuple<bool, bool>(bool.Parse(strs[0]), bool.Parse(strs[1]));
+        }
     }
 }

+ 36 - 0
Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/RabbitSyncData.cs

@@ -0,0 +1,36 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class RabbitSyncData
+{
+    [System.NonSerialized] public bool inited;
+    public int id;
+    public float rx;
+    public float ry;
+    public float rz;
+    public float rw;
+    public float px;
+    public float py;
+    public float pz;
+    public int ai;
+    public int ct;
+    public int ii;
+    public int di;
+    public void SetData(Rabbit rabbit) {
+        id = rabbit.uid;
+        Quaternion r = rabbit.transform.rotation;
+        Vector3 p = rabbit.transform.position;
+        rx = r.x;
+        ry = r.y;
+        rz = r.z;
+        rw = r.w;
+        px = p.x;
+        py = p.y;
+        pz = p.z;
+        ai = rabbit.curAnimIndex;
+        ct = rabbit.colorType;
+        ii = rabbit.injuredID;
+        inited = true;
+    }
+}

+ 11 - 0
Assets/BowArrow/Scripts/Manager/GameMode/OnlineObject/RabbitSyncData.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aafdb48cbcef6e746a1346ac7c97f99b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 16 - 0
Assets/BowArrow/Scripts/Manager/GameMode/OnlinePKTest.cs

@@ -0,0 +1,16 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class OnlinePKTest : MonoBehaviour
+{
+    static bool canTest = false;
+    public static void Init() {
+        if (!canTest) return;
+        #if UNITY_EDITOR
+            GlobalData.pkMatchType = PKMatchType.OnlinePK;
+            GlobalData.matchRoomType = 1;
+            GameMgr.gameType = 10;
+        #endif
+    }
+}

+ 11 - 0
Assets/BowArrow/Scripts/Manager/GameMode/OnlinePKTest.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2dbba4fecfb66574c88688d53d6bfd8a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 5
Assets/BowArrow/Scripts/Manager/GameMode/PKGameMode_OnlinePK.cs

@@ -18,12 +18,14 @@ public class PKGameMode_OnlinePK : GameMode {
     public PKGameMode_OnlinePK(GameMgr gameMgr) : base(gameMgr) {
         GlobalData.pkMatchType = PKMatchType.OnlinePK;
 
-        
+        bool hasSocketPlayer = false;
         if (GameObject.Find("SocketPlayer") == null) {
             PKMatchingView.MoniMatchForTestInGameScene(() => {
-                 myPlayerIndex = GlobalData.playerIndexInRoom;
+                myPlayerIndex = GlobalData.playerIndexInRoom;
+                ToInitGameView(); 
             });
         } else {
+            hasSocketPlayer = true;
             myPlayerIndex = GlobalData.playerIndexInRoom;
         }
 
@@ -33,9 +35,9 @@ public class PKGameMode_OnlinePK : GameMode {
         //记录可射击的靶子
         targetBody = GameObject.Find("GameArea/TargetObject/TargetBody").GetComponent<TargetBody>();
         GameObject.FindObjectOfType<ArmBow>().validTargets.Add(targetBody);
-        //添加游戏界面
-        GameObject view = Resources.Load<GameObject>("Prefabs/Views/PKGameView");
-        GameObject.Instantiate(view);
+        if (hasSocketPlayer) {
+            ToInitGameView();
+        }
         //禁止动作-相机和手臂
         BanBowReady();
 
@@ -45,6 +47,12 @@ public class PKGameMode_OnlinePK : GameMode {
         socketPlayer.onReceivePKGameData = onReceivePKGameData;
     }
     
+    void ToInitGameView() {
+        //添加游戏界面
+        GameObject view = Resources.Load<GameObject>("Prefabs/Views/PKGameView");
+        GameObject.Instantiate(view);
+    }
+
     Quaternion bowTargetQua; 
     bool hasBowTargBtQua;
     void onReceivePKGameData(string key, string data) {

+ 6 - 1
Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_LocalPK.cs

@@ -8,7 +8,7 @@ public class RabbitHuntGameMode_LocalPK : RabbitHuntGameMode, ChallengeGameModeL
     float singleShootReadyTime = 30f;
     float singleShootReadyTimeMax = 30f;
     public RabbitHuntGameMode_LocalPK(GameMgr gameMgr) : base(gameMgr) {
-        
+        hunterGamePlayerScoreCounter = new HunterGamePlayerScoreCounter(this);
     }
 
     public override void Start()
@@ -65,9 +65,14 @@ public class RabbitHuntGameMode_LocalPK : RabbitHuntGameMode, ChallengeGameModeL
     public (float, float) GetSingleShootReadyTime() {
         return (singleShootReadyTime, singleShootReadyTimeMax);
     }
+    HunterGamePlayerScoreCounter hunterGamePlayerScoreCounter;
+    public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter() {
+        return hunterGamePlayerScoreCounter;
+    }
 }
 public interface ChallengeGameModeLocalPK {
     public int GetCurrentPlayIndex();
     //获取单次射击的准备时间/准备时间上限(就是当前玩家的操作倒计时)
     public (float, float) GetSingleShootReadyTime();
+    public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter();
 }

+ 375 - 0
Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_OnlinePK.cs

@@ -0,0 +1,375 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+public class RabbitHuntGameMode_OnlinePK : RabbitHuntGameMode, ChallengeGameModeLocalPK
+{
+    SocketPlayer socketPlayer;
+    public int myPlayerIndex = -1;
+    public bool IsMyPlayerInited() {
+        return myPlayerIndex >= 0;
+    }
+    public bool IsMyPlayerRunning() {
+        return myPlayerIndex == currentPlayerIndex;
+    }
+    public bool IsMainHost() {
+        return myPlayerIndex == 0;
+    }
+    public bool IsCopyHost() {
+        return myPlayerIndex > 0;
+    }
+    public int roundID = 0;
+    public int currentPlayerIndex = 0; // 双人0和1
+    float singleShootReadyTime = 30f;
+    float singleShootReadyTimeMax = 30f;
+    public RabbitHuntGameMode_OnlinePK(GameMgr gameMgr) : base(gameMgr) {
+        hunterGamePlayerScoreCounter = new HunterGamePlayerScoreCounter(this);
+    }
+
+    public override void Start()
+    {
+        if (GameObject.Find("SocketPlayer") == null) {
+            PKMatchingView.MoniMatchForTestInGameScene(() => {
+                myPlayerIndex = GlobalData.playerIndexInRoom;
+                OnStart();
+            });
+        } else {
+            myPlayerIndex = GlobalData.playerIndexInRoom;
+            OnStart();
+        }
+        socketPlayer = GameObject.Find("SocketPlayer").GetComponent<SocketPlayer>();
+        socketPlayer.onReceivePKGameData = onReceivePKGameData;
+
+        AutoSwitchBanUserControlBow();
+    }
+
+    private void OnStart() {
+        banCreateAnimal = IsCopyHost();
+        banOnBowArrowShootOut = IsCopyHost();
+        SetLevel(5);
+        AddHuntGameView();
+        this.gameMgr.transform.Find("HunterGameView_LocalPK").gameObject.SetActive(true);
+    }
+
+    public override void onBowShoot() {
+        if (IsCopyHost()) {
+            socketPlayer.UploadPKGameData("onBowShoot", "");
+        }
+    }
+
+    Quaternion bowTargetQua; 
+    bool hasBowTargBtQua;
+    void onReceivePKGameData(string key, string data) {
+        if (!IsMyPlayerInited()) return;
+        if (key == "logic") {
+            SyncLogicData syncLogicData = JsonConvert.DeserializeObject<SyncLogicData>(data);
+            // if (syncLogicData.roundID > roundID || 
+            //     (syncLogicData.roundID == roundID && syncLogicData.currentPlayerIndex != myPlayerIndex)
+            // ) {
+                
+            // }
+            syncLogicData.Output(this);
+            AutoSwitchBanUserControlBow();
+        }
+        if (key == "bow") {
+            if (!IsMyPlayerRunning()) {
+                string[] quaStr = data.Split(',');
+                if (quaStr.Length == 6) {
+                    bowTargetQua.x = float.Parse(quaStr[0]);
+                    bowTargetQua.y = float.Parse(quaStr[1]);
+                    bowTargetQua.z = float.Parse(quaStr[2]);
+                    bowTargetQua.w = float.Parse(quaStr[3]);
+                    hasBowTargBtQua = true;
+                    ArmBow.ins.phase = int.Parse(quaStr[4]);
+                    GameAssistUI.ins.playerScaleAimValue_OnlinePK = int.Parse(quaStr[5]);
+                } 
+            }
+        }
+        if (key == "arrow") {
+            List<ArrowSync.SyncData> arrowSyncDataList = JsonConvert.DeserializeObject<List<ArrowSync.SyncData>>(data);
+            foreach (var item in arrowSyncMap) {
+                item.Value.hasSetSyncData = false;
+            }
+            GameObject arrowPrefab = ArmBow.ins.arrow;
+            foreach (var item in arrowSyncDataList) {
+                ArrowSync arrowSync;
+                arrowSyncMap.TryGetValue(item.id, out arrowSync);
+                if (arrowSync == null) {
+                    GameObject arrowObj = GameObject.Instantiate(arrowPrefab);
+                    arrowSync = arrowObj.AddComponent<ArrowSync>();
+                    arrowSync.SetSyncData(item, true);
+                    arrowSyncMap[item.id] = arrowSync;
+                } else {
+                    arrowSync.SetSyncData(item);
+                }
+                arrowSync.hasSetSyncData = true;
+            }
+            List<int> removeIDs = null;
+            foreach (var item in arrowSyncMap) {
+                if (!item.Value.hasSetSyncData) {
+                    if (removeIDs == null) removeIDs = new List<int>();
+                    removeIDs.Add(item.Key);
+                } 
+            }
+            if (removeIDs != null) {
+                foreach (var id in removeIDs) {
+                    ArrowSync arrowSync = arrowSyncMap[id];
+                    arrowSyncMap.Remove(id);
+                    if (arrowSync && arrowSync.gameObject) {
+                        GameObject.Destroy(arrowSync.gameObject);
+                    }
+                }
+            }
+        }
+        if (key == "onBowShoot") {
+            GameEventCenter.ins.onBowArrowShootOut?.Invoke(null, null);
+        }
+        if (key == "DoNextShoot") {
+            DoNextShoot();
+        }
+        if (key == "animals") {
+            List<RabbitSyncData> syncDataList = JsonConvert.DeserializeObject<List<RabbitSyncData>>(data);
+            foreach (var item in animalSyncMap) {
+                item.Value.isInvalid = true;
+            }
+            foreach (var item in syncDataList) {
+                Rabbit animalSync;
+                animalSyncMap.TryGetValue(item.id, out animalSync);
+                if (animalSync == null) {
+                    GameObject animalObject = GameObject.Instantiate(animalPrefab, Vector3.zero, Quaternion.identity, animalsBaseT);
+                    animalSync = animalObject.GetComponent<Rabbit>();
+                    animalSync.isMirror = true;
+                    animalSync.inputSyncData = item;
+                    animalObject.SetActive(true);
+                    animalSyncMap[item.id] = animalSync;
+                } else {
+                    animalSync.inputSyncData = item;
+                }
+                animalSync.isInvalid = false;
+            }
+            List<int> removeIDs = null;
+            foreach (var item in animalSyncMap) {
+                if (item.Value.isInvalid) {
+                    if (removeIDs == null) removeIDs = new List<int>();
+                    removeIDs.Add(item.Key);
+                } 
+            }
+            if (removeIDs != null) {
+                foreach (var id in removeIDs) {
+                    Rabbit animalSync = animalSyncMap[id];
+                    animalSyncMap.Remove(id);
+                    if (animalSync && animalSync.gameObject) {
+                        GameObject.Destroy(animalSync.gameObject);
+                    }
+                }
+            }
+        }
+        if (key == "RUpdate") {
+            if (int.Parse(data) == roundID) {
+                OnUpdate(0.033f);
+            }
+        }
+        if (key == "OnHit") {
+            string[] dataSplits = data.Split(',');
+            int uid = int.Parse(dataSplits[0]);
+            string partName = dataSplits[1];
+            foreach (var item in Rabbit.rabbitSet) {
+                if (item.uid == uid) {
+                    item.OnHitLogic(null, partName);
+                    break; //一定要break,原因1:这是唯一ID,后续也没必要检测了,原因2:这里可能会触发死亡,死亡会触发下个动物生成,Set集合的元素+1,继续遍历会出现modifyException
+                }    
+            }
+        }
+    }
+
+    void AutoSwitchBanUserControlBow() {
+        BowCamera.ins.banLogic = ArmBow.ins.banLogic = !IsMyPlayerRunning();
+    }
+    
+    public override bool DoNextShoot() { 
+        if (IsCopyHost()) {
+            socketPlayer.UploadPKGameData("DoNextShoot", "");
+            return false;
+        }
+        foreach (var item in Rabbit.rabbitSet) {
+            if (item.onDoNextShootWillDestroy) {
+                GameObject.Destroy(item.gameObject);
+            }    
+        }
+        bool canDo = base.DoNextShoot();
+        if (canDo) {
+            NextPlayerFinal();
+        }
+        return canDo;
+    }
+
+    void AddReadyView() 
+    {
+        GameObject view = Resources.Load<GameObject>("Prefabs/Views/PKGameReadyView_Challenge");
+        GameObject o = GameObject.Instantiate(view);
+        PKGameReadyView_Challenge script = o.GetComponent<PKGameReadyView_Challenge>();
+        script.currentPlayerIndex = currentPlayerIndex;
+    }
+
+    void NextPlayerFinal() {
+        NextPlayer();
+        BanBowReady();
+        AddReadyView();
+    }
+
+    void NextPlayer() {
+        currentPlayerIndex++;
+        currentPlayerIndex %= 2;
+        singleShootReadyTime = singleShootReadyTimeMax;
+        roundID++;
+    }
+
+    public override void Update() {
+        if (!IsMyPlayerInited()) return;
+        if (!IsMainHost()) return;
+        if (!IsMyPlayerRunning()) return;
+        OnUpdate(Time.deltaTime);
+    }
+    void OnUpdate(float dt) {
+        if (gameMgr.gameOver || pauseTimeCounting) return;
+        if (this.time > 0) {
+            this.time -= dt;
+        } else {
+            this.time = 0;
+            AnnounceGameOver();
+        }
+        if (gameMgr.gameOver || pauseTimeCounting) return;
+        singleShootReadyTime -= dt;
+        if (singleShootReadyTime <= 0) {
+            //切换玩家
+            ArmBow.ins.readyShoot();
+            NextPlayerFinal();
+        }
+    }
+
+    int lastRoundID = -1;
+    bool gameEnd = false;
+    public override void FrameUpdate()
+    {
+        if (!IsMyPlayerInited()) return;
+        base.FrameUpdate();
+        AutoSwitchBanUserControlBow();
+        Upload();
+        if (!IsMyPlayerRunning() && hasBowTargBtQua) {
+            BowCamera.ins.transform.rotation = Quaternion.Lerp(BowCamera.ins.transform.rotation, bowTargetQua, Time.deltaTime * 12);
+        }
+        if (roundID > lastRoundID) {
+            lastRoundID = roundID;
+            AddReadyView();
+        }
+        if (gameEnd && !gameMgr.gameOver) {
+            AnnounceGameOver();
+        }
+    }
+
+    float lastUploadTime = 0;
+    void Upload() {
+        float curTime = Time.realtimeSinceStartup;
+        if (curTime - lastUploadTime > 0.033) {
+            lastUploadTime = curTime;
+            UploadLogic();
+            UploadBow();
+            UploadArrows();
+            UploadAnimals();
+            UploadRequestUpdate();
+            UploadOnHit();
+        }
+    }
+    void UploadLogic() {
+        if (!IsMainHost()) return;
+        SyncLogicData data = new SyncLogicData().Input(this);
+        socketPlayer.UploadPKGameData("logic", data);
+    }
+    void UploadBow() {
+        if (!IsMyPlayerRunning()) return;
+        Quaternion qua = BowCamera.ins.transform.rotation;
+        int aimScaleValue = GameAssistUI.ins.aimScaleValue;
+        if (!GameAssistUI.ins.scaleAimOn) aimScaleValue = 0;
+        socketPlayer.UploadPKGameData("bow", qua.x + "," + qua.y + "," + qua.z + "," + qua.w + "," + ArmBow.ins.phase + "," + aimScaleValue);
+    }
+    Dictionary<int, ArrowSync> arrowSyncMap = new Dictionary<int, ArrowSync>();
+    void UploadArrows() {
+        List<ArrowSync.SyncData> arrowSyncDataList = new List<ArrowSync.SyncData>();
+        foreach (var item in Arrow.arrowSet) {
+            if (item.outputSyncData == null || !item.outputSyncData.inited) continue;
+            arrowSyncDataList.Add(item.outputSyncData);
+        }
+        socketPlayer.UploadPKGameData("arrow", arrowSyncDataList);
+    }
+    Dictionary<int, Rabbit> animalSyncMap = new Dictionary<int, Rabbit>();
+    void UploadAnimals() {
+        if (!IsMainHost()) return;
+        List<RabbitSyncData> syncDataList = new List<RabbitSyncData>();
+        foreach (var item in Rabbit.rabbitSet) {
+            if (item.outputSyncData == null || !item.outputSyncData.inited) continue;
+            syncDataList.Add(item.outputSyncData);
+        }
+        socketPlayer.UploadPKGameData("animals", syncDataList);
+    }
+    void UploadRequestUpdate() {
+        if (!IsCopyHost()) return;
+        if (!IsMyPlayerRunning()) return;
+        if (pauseTimeCounting) return;
+        socketPlayer.UploadPKGameData("RUpdate", this.roundID.ToString());
+    }
+
+    void UploadOnHit() {
+        foreach (var item in Rabbit.rabbitSet) {
+            if (item.onHitData != null) {
+                socketPlayer.UploadPKGameData("OnHit", item.onHitData);
+                item.onHitData = null;
+            }    
+        }
+    }
+
+    //localPK interface
+    public int GetCurrentPlayIndex() {
+        return currentPlayerIndex;
+    }
+    public (float, float) GetSingleShootReadyTime() {
+        return (singleShootReadyTime, singleShootReadyTimeMax);
+    }
+    HunterGamePlayerScoreCounter hunterGamePlayerScoreCounter;
+    public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter() {
+        return hunterGamePlayerScoreCounter;
+    }
+
+    public class SyncLogicData {
+        public int roundID;
+        public int currentPlayerIndex;
+        public float singleShootReadyTime;
+        public int animalCount = 0;
+        public int arrowCount = 0;
+        public float time = 60;
+        public int[] hitScores;
+        public bool gameEnd = false;
+        public SyncLogicData Input(RabbitHuntGameMode_OnlinePK src) {
+            roundID = src.roundID;
+            currentPlayerIndex = src.currentPlayerIndex;
+            singleShootReadyTime = src.singleShootReadyTime;
+            animalCount = src.animalCount;
+            arrowCount = src.arrowCount;
+            time = src.time;
+            hitScores = src.getHunterGamePlayerScoreCounter().hitScores;
+            gameEnd = src.gameMgr.gameOver;
+            return this;
+        }
+        public void Output(RabbitHuntGameMode_OnlinePK dest) {
+            dest.roundID = roundID;
+            dest.currentPlayerIndex = currentPlayerIndex;
+            dest.singleShootReadyTime = singleShootReadyTime;
+            dest.animalCount = animalCount;
+            dest.arrowCount = arrowCount;
+            dest.time = time;
+            dest.getHunterGamePlayerScoreCounter().hitScores = hitScores;
+            dest.gameEnd = gameEnd;
+        }
+    }
+}

+ 11 - 0
Assets/BowArrow/Scripts/Manager/GameMode/RabbitHuntGameMode_OnlinePK.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cffe7bcbc464fd54ea110d158404b73f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 5 - 0
Assets/BowArrow/Scripts/Manager/GameMode/WolfHuntGameMode_LocalPK.cs

@@ -11,6 +11,7 @@ public class WolfHuntGameMode_LocalPK : WolfHuntGameMode, ChallengeGameModeLocal
     int[] playerHpList = {20, 20}; 
 
     public WolfHuntGameMode_LocalPK(GameMgr gameMgr) : base(gameMgr) {
+        hunterGamePlayerScoreCounter = new HunterGamePlayerScoreCounter(this);
         InitByCurPlayerIndex();
         GameEventCenter.ins.onBowArrowShootOut += (a, b) => {
             hasShootOut = true;
@@ -116,4 +117,8 @@ public class WolfHuntGameMode_LocalPK : WolfHuntGameMode, ChallengeGameModeLocal
     public (float, float) GetSingleShootReadyTime() {
         return (singleShootReadyTime, singleShootReadyTimeMax);
     }
+    HunterGamePlayerScoreCounter hunterGamePlayerScoreCounter;
+    public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter() {
+        return hunterGamePlayerScoreCounter;
+    }
 }

+ 5 - 1
Assets/BowArrow/Scripts/Manager/GameMode/YejiHuntGameMode_LocalPK.cs

@@ -8,7 +8,7 @@ public class YejiHuntGameMode_LocalPK : YejiHuntGameMode, ChallengeGameModeLocal
     float singleShootReadyTime = 30f;
     float singleShootReadyTimeMax = 30f;
     public YejiHuntGameMode_LocalPK(GameMgr gameMgr) : base(gameMgr) {
-        
+        hunterGamePlayerScoreCounter = new HunterGamePlayerScoreCounter(this);
     }
 
     public override void Start()
@@ -66,4 +66,8 @@ public class YejiHuntGameMode_LocalPK : YejiHuntGameMode, ChallengeGameModeLocal
     public (float, float) GetSingleShootReadyTime() {
         return (singleShootReadyTime, singleShootReadyTimeMax);
     }
+    HunterGamePlayerScoreCounter hunterGamePlayerScoreCounter;
+    public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter() {
+        return hunterGamePlayerScoreCounter;
+    }
 }

+ 4 - 1
Assets/BowArrow/Scripts/Network/SocketPlayer.cs

@@ -7,12 +7,15 @@ using UnityEngine.SceneManagement;
 
 public class SocketPlayer : JC.SocketIO.SocketIOClient
 {
+    public static SocketPlayer ins;
     void Awake() 
     {
+        ins = this;
         GlobalEventCenter.ins.onGameSceneDestroy += DestroySelf;
     }
     public override void OnDestroy()
     {
+        if (ins == this) ins = null;
         GlobalEventCenter.ins.onGameSceneDestroy -= DestroySelf;
         base.OnDestroy();
     }
@@ -53,7 +56,7 @@ public class SocketPlayer : JC.SocketIO.SocketIOClient
     {
         Debug.Log("onDestroy");
         onDestroy_?.Invoke();
-        if (canBackHome && UnityEngine.SceneManagement.SceneManager.GetActiveScene().name.StartsWith("Game")) {
+        if (canBackHome && UnityEngine.SceneManagement.SceneManager.GetActiveScene().name.StartsWith("Game") && !openInGameScene) {
             PopupMgr.ins.ShowBGTip("某方退出或掉线,联机游戏终止!");
             SceneManager.LoadScene("Home", LoadSceneMode.Single);
         }

+ 3 - 4
Assets/BowArrow/Scripts/Network/UserPlayer.cs

@@ -96,10 +96,9 @@ public class UserPlayer : JCEntity
         }
     }
     public void onInvitePK(int avatarID, string nickname, int roomID, int roomType) {
-        string tip = "";
-        if (roomType == 0) {
-            tip = "好友邀请你参加静止靶PK";
-        }
+        string[] pkTypeNames = {"静止靶", "野兔闯关", "野鸡闯关", "野狼闯关"};
+        string pkTypeName = pkTypeNames[roomType];
+        string tip = $"好友邀请你参加{pkTypeName}PK";
         System.Action cb = delegate() {
             if (SceneManager.GetActiveScene().name == "Home") {
                 PKMatchingView view = PKMatchingView.Create();

+ 7 - 7
Assets/BowArrow/Scripts/View/PKGameSettleView.cs

@@ -34,13 +34,13 @@ public class PKGameSettleView : MonoBehaviour
                 this.transform.Find("Score" + i + "/Text").GetComponent<Text>().text = ((PKGameMode_OnlinePK)gameMode).gameLogic.totalScores[i - 1].ToString();
             }
         }
-        if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
-            Transform btnsTF = this.transform.Find("Btns");
-            for (int i = 0; i < btnsTF.childCount; i++) {
-                Transform tf = btnsTF.GetChild(i);
-                tf.gameObject.SetActive(tf.gameObject.name == "BtnBack");
-            }
-        }
+        // if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
+        //     Transform btnsTF = this.transform.Find("Btns");
+        //     for (int i = 0; i < btnsTF.childCount; i++) {
+        //         Transform tf = btnsTF.GetChild(i);
+        //         tf.gameObject.SetActive(tf.gameObject.name == "BtnBack");
+        //     }
+        // }
         AudioMgr.ins.PlayWin();
         if (GlobalData.pkMatchType == PKMatchType.OnlinePK) {
             PKGameMode_OnlinePK gm = (PKGameMode_OnlinePK)gameMode;

+ 8 - 4
Assets/BowArrow/Scripts/View/PKMatchingView.cs

@@ -88,10 +88,6 @@ public class PKMatchingView : MonoBehaviour
             socketPlayer.RandomMatchRoom();
         };
         socketPlayer.onMatchSuccess = () => {
-            int otherIndex = (GlobalData.playerIndexInRoom + 1) % 2;
-            MatchPlayerInfo info = GlobalData.matchPlayerInfos[otherIndex];
-            (Sprite avatar, string nickname)  =  RoleMgr.GetRoleInfo(info.avatarID);
-            nickname = LoginMgr.myUserInfo.nickname;
             socketPlayer.AgreeStartGame();
         };
         socketPlayer.onAgreeStartGame = () => {
@@ -116,6 +112,14 @@ public class PKMatchingView : MonoBehaviour
                     GameMgr.gameType = 9;
                     SceneManager.LoadScene("Game", LoadSceneMode.Single);
                 }
+                //challenge-game
+                int[] roomTypes = {1, 2, 3};
+                int[] gameTypes = {10, 11, 12};
+                int curIndex = Array.IndexOf(roomTypes, GlobalData.matchRoomType);
+                if (curIndex >= 0) {
+                    GameMgr.gameType = gameTypes[curIndex];
+                    SceneManager.LoadScene("GameChallenge", LoadSceneMode.Single);
+                }
             }
         }
     }

+ 5 - 5
Assets/BowArrow/Scripts/View/RankView.cs

@@ -126,9 +126,12 @@ public class RankView : MonoBehaviour
 
     #region 顶部条目
         [SerializeField] Sprite[] btnTabTextures1;
-        Button[] btnTabs1 = {null};
+        Button[] btnTabs1 = {null, null, null, null};
         void InitBtnTabs1() {
             btnTabs1[0] = this.transform.Find("LineH/BtnTab0").GetComponent<Button>();
+            btnTabs1[1] = this.transform.Find("LineH/BtnTab1").GetComponent<Button>();
+            btnTabs1[2] = this.transform.Find("LineH/BtnTab2").GetComponent<Button>();
+            btnTabs1[3] = this.transform.Find("LineH/BtnTab3").GetComponent<Button>();
             for (int i = 0; i < btnTabs1.Length; i++) {
                 Button btnTab = btnTabs1[i];
                 int btnTabIndex = i;
@@ -136,7 +139,6 @@ public class RankView : MonoBehaviour
                     if (AudioMgr.ins) AudioMgr.ins.PlayBtn();
                     if (!IsBtnTabSelected1(btnTab)) {
                         SetBtnTabSelected1(btnTab);
-                        Debug.Log(2);
                     }
                 });
             }
@@ -155,9 +157,7 @@ public class RankView : MonoBehaviour
             HandleBtnTabSelectedLogic1(index);
         }
         void HandleBtnTabSelectedLogic1(int btnIndex) {
-            if (btnIndex == 0) {
-                rankGameType = 9;
-            }
+            rankGameType = 9 + btnIndex;
             EnterRankListBox();
         }
     #endregion