Quellcode durchsuchen

Merge remote-tracking branch 'remotes/origin/master' into insertcoin

slambb vor 11 Monaten
Ursprung
Commit
c79cc8e528
22 geänderte Dateien mit 2519 neuen und 525 gelöschten Zeilen
  1. 104 29
      Assets/BowArrow/InfraredCamera/InfraredDemo.cs
  2. 562 112
      Assets/BowArrow/InfraredCamera/Resources/InfraredDemo.prefab
  3. 17 18
      Assets/BowArrow/Modules/InfraredGuider/InfraredGuider.prefab
  4. 2 2
      Assets/BowArrow/Modules/InfraredGuider/InfraredLightGuider2.prefab
  5. 336 12
      Assets/BowArrow/Resources/Prefabs/Views/Home/DeviceViewInfrared.prefab
  6. 0 95
      Assets/BowArrow/Scenes/GameDouble.unity
  7. 60 8
      Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/cn.json
  8. 61 11
      Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/en.json
  9. 47 0
      Assets/BowArrow/Scripts/View/Home/DeviceView_ItemShow.cs
  10. 0 95
      Assets/DuckHunter/Scenes/DuckHunter.unity
  11. 3 2
      Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/InterLineGuess.cs
  12. 0 0
      Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/InterLineGuess.cs.meta
  13. 10 0
      Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/LineIdentified.cs
  14. 14 9
      Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs
  15. 2 2
      Assets/InfraredProject/WebCamera/Script/ZIM/ScreenLocate.cs
  16. 657 94
      Assets/SmartBow/Resources/SmartBow/Prefabs/Views/Home/InfraredScreenPositioningView.prefab
  17. 119 4
      Assets/SmartBow/Resources/SmartBow/Prefabs/ZIM/LineGenerator.cs
  18. 143 22
      Assets/SmartBow/Scripts/Views/InfraredViewParts/InfraredScreenPositioningView.cs
  19. 252 5
      Assets/SmartBow/Scripts/Views/InfraredViewParts/Line.cs
  20. 7 5
      Assets/SmartBow/Scripts/Views/InfraredViewParts/PointMarker.cs
  21. BIN
      Assets/SmartBow/Textures/Guidance/Infrared/FrameLine2.png
  22. 123 0
      Assets/SmartBow/Textures/Guidance/Infrared/FrameLine2.png.meta

+ 104 - 29
Assets/BowArrow/InfraredCamera/InfraredDemo.cs

@@ -43,6 +43,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
 
         //直接初始化一次
         _ins.InitInfraredCamera();
+
+        //生成一个控制台
+        UserPlayer.InitLogReporter();
     }
 
 
@@ -59,7 +62,7 @@ public class InfraredDemo : JCUnityLib.ViewBase
         }
         else {
             mBtnSee.interactable = false;
-            mBtnSee.transform.Find("Text").GetComponent<Text>().text = "等待初始化..";
+            mBtnSee.transform.Find("Text").GetComponent<Text>().text = TextAutoLanguage2.GetTextByKey("WaitingForInitialization"); // "等待初始化..";
         }
 
         //直接初始化一次
@@ -113,9 +116,19 @@ public class InfraredDemo : JCUnityLib.ViewBase
         {
             mBtnSee.gameObject.SetActive(value);
         }
-        mBtnSee.GetComponentInChildren<Text>().text = value ? "隐藏界面" : "调试红外";
+        updateBtnSee();
+        Action<Text> onApplyToNext = (t) => {
+            updateBtnSee();
+        };
+        mBtnSee.GetComponentInChildren<TextAutoLanguage2>().onApplyToNext += onApplyToNext;
         //if (value) InitInfraredCamera();
 
+        //刷新翻译的Dropdown
+        if (value) {
+            UpdateLanguage(); 
+            updateDropdownResolution2();
+        }
+
         if (!hasCalled && value)
         {
             hasCalled = true;
@@ -124,6 +137,10 @@ public class InfraredDemo : JCUnityLib.ViewBase
             Debug.Log("[InfraredDemo] SetVisiable Function!");
         }
     }
+    void updateBtnSee() {
+        mBtnSee.GetComponentInChildren<Text>().text = _visiable ? TextAutoLanguage2.GetTextByKey("HideInterface") : TextAutoLanguage2.GetTextByKey("DebugInfrared");//"隐藏界面" : "调试红外";
+    }
+    
 
     Text _spText;
     Vector2 _screenPoint;
@@ -176,7 +193,7 @@ public class InfraredDemo : JCUnityLib.ViewBase
     [SerializeField] Dropdown _dropdownResolution2;
 
     [SerializeField] Slider _sliderLineWidth;
-
+    [SerializeField] Slider _fanWidth;
     //红外线阈值
     [SerializeField] Slider _infraredFilter;
 
@@ -201,7 +218,7 @@ public class InfraredDemo : JCUnityLib.ViewBase
     public ParamFloatValue resoutionNew = new ParamFloatValue("ic_resoutionNew", 10);
     //摄像机分辨率 -只处理高低分辨率情况
     public ParamFloatValue resoution = new ParamFloatValue("ic_resoution", 0);
-    string[] resolutions = { "高分辨率", "低分辨率" };
+    //string[] resolutions = { "高分辨率", "低分辨率" };
 #endif
 
     //抖动过滤值 - 6.0
@@ -211,7 +228,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
 
 
     //线段宽度阈值
-    public ParamFloatValue lineWidth = new ParamFloatValue("ic_lineWidth", 10.0f);
+    public ParamFloatValue lineWidth = new ParamFloatValue("ic_lineWidth", 4.0f);
+    //扇形宽度
+    public ParamFloatValue fanWidth = new ParamFloatValue("ic_fanWidth", 90.0f);
 
     public ParamFloatValue captureValue = new ParamFloatValue("ic_captureValue", 30.0f);
     public ParamFloatValue delayValue = new ParamFloatValue("ic_delayValue", 30.0f);
@@ -275,6 +294,21 @@ public class InfraredDemo : JCUnityLib.ViewBase
         if (currentCameraInfo != null) return;
         currentCameraInfo = cameraInfo;
 
+        string[] sliderNameArrayKey = new string[] {
+            "AutoExposureMode",          // "自动曝光模式"
+            "ExposureTimeAbsolute",      // "曝光时间(绝对)"
+            "Brightness",                // "亮度"
+            "Contrast",                  // "对比度"
+            "Hue",                       // "色调"
+            "Saturation",                // "饱和度"
+            "Sharpness",                 // "锐度"
+            "Gamma",                     // "伽玛"
+            "BacklightCompensation",     // "背光补偿"
+            "Gain"                       // "增益"
+        };
+
+
+
         for (int i = 0; i < sliderStrArray.Length; i++)
         {
             string typeStr = sliderStrArray[i];
@@ -292,7 +326,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
                 toggleObject.name = typeStr;
 
                 Text labelObj = toggleObject.transform.Find("Label").GetComponent<Text>();
-                labelObj.text = sliderNameArray[i];
+                //labelObj.text = sliderNameArray[i];
+                labelObj.gameObject.AddComponent<TextAutoLanguage2>().SetTextKey(sliderNameArrayKey[i]);
+
                 Toggle toggle = toggleObject.GetComponent<Toggle>();
                 CTRLAEToggle = toggle;
 
@@ -332,7 +368,8 @@ public class InfraredDemo : JCUnityLib.ViewBase
 
                 Text textObj = sliderObject.transform.Find("text").GetComponent<Text>();
                 Text titleTextObj = sliderObject.transform.Find("title").GetComponent<Text>();
-                titleTextObj.text = sliderNameArray[i];//类型名字
+                //titleTextObj.text = sliderNameArray[i];//类型名字
+                titleTextObj.gameObject.AddComponent<TextAutoLanguage2>().SetTextKey(sliderNameArrayKey[i]);
                 if (slider != null)
                 {
 
@@ -479,6 +516,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
     string[] sliderNameArrayPC = new string[]{
         "亮度",
         "对比度",};
+    string[] sliderNameArrayPCKey = new string[]{
+        "Brightness",
+        "Contrast",};
     string[] sliderStrArrayPC = new string[]{
         "PU_BRIGHTNESS",
         "PU_CONTRAST"};
@@ -497,7 +537,8 @@ public class InfraredDemo : JCUnityLib.ViewBase
             Slider slider = sliderObject.GetComponent<Slider>();
             Text textObj = sliderObject.transform.Find("text").GetComponent<Text>();
             Text titleTextObj = sliderObject.transform.Find("title").GetComponent<Text>();
-            titleTextObj.text = sliderNameArrayPC[i];//类型名字
+            //titleTextObj.text = TextAutoLanguage2.GetTextByKey(sliderNameArrayPCKey[i]);// sliderNameArrayPC[i];//类型名字
+            titleTextObj.gameObject.AddComponent<TextAutoLanguage2>().SetTextKey(sliderNameArrayPCKey[i]);
             if (slider != null)
             {
                 slider.minValue = -1;
@@ -612,7 +653,8 @@ public class InfraredDemo : JCUnityLib.ViewBase
                 Debug.Log("初始化摄像机!");
                 //可以操作按钮
                 mBtnSee.interactable = true;
-                mBtnSee.transform.Find("Text").GetComponent<Text>().text = "调试红外";
+                //mBtnSee.transform.Find("Text").GetComponent<Text>().text = "调试红外";
+                updateBtnSee();
                 //延迟重新设置一次分辨率
                 StartCoroutine(delayInitOhterInfo(camera));
 
@@ -634,6 +676,18 @@ public class InfraredDemo : JCUnityLib.ViewBase
             };
         }
     }
+
+    private void updateDropdownResolution2()
+    {
+        string[] resolutions = {
+            TextAutoLanguage2.GetTextByKey("HighResolution"),
+            TextAutoLanguage2.GetTextByKey("LowResolution")
+        };
+        // 清除默认选项
+        _dropdownResolution2.ClearOptions();
+        // 将分辨率字符串数组转换为 Dropdown 选项
+        _dropdownResolution2.AddOptions(new List<string>(resolutions));
+    }
     /// <summary>
     /// 初始化一些游戏配置
     /// </summary>
@@ -646,11 +700,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
         initSlider(camera);
 
         camera.GetResolutionsStrs();
-        // 清除默认选项
-        _dropdownResolution2.ClearOptions();
-        // 将分辨率字符串数组转换为 Dropdown 选项
-        _dropdownResolution2.AddOptions(new List<string>(resolutions));
+
         // 默认设置
+        updateDropdownResolution2();
         int index = (int)resoution.Get();
         _dropdownResolution2.value = index;
         _dropdownResolution2.RefreshShownValue();
@@ -687,6 +739,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
         SetLineWidth(lineWidth.Get());
         _sliderLineWidth.onValueChanged.AddListener(SetLineWidth);
 
+        SetFanWidth(fanWidth.Get());
+        _fanWidth.onValueChanged.AddListener(SetFanWidth);
+
         //检测红外亮度阈值
         SetInfraredFilterValue(infraredFileterValue.Get());
         _infraredFilter.onValueChanged.AddListener(SetInfraredFilterValue);
@@ -945,9 +1000,12 @@ public class InfraredDemo : JCUnityLib.ViewBase
         //{
         //    options.Add($"Quad {i + 1}");
         //}
-        options.Add("自动识别");
-        options.Add("半自动识别");
-        options.Add("手动识别");
+        //options.Add("自动识别");
+        //options.Add("半自动识别");
+        //options.Add("手动识别");
+        options.Add(TextAutoLanguage2.GetTextByKey("AutoRecognition"));    // "自动识别"
+        options.Add(TextAutoLanguage2.GetTextByKey("SemiAutoRecognition")); // "半自动识别"
+        options.Add(TextAutoLanguage2.GetTextByKey("ManualRecognition"));   // "手动识别"
         dropdown.AddOptions(options);
 
         // 添加监听器来处理选择事件
@@ -1093,20 +1151,26 @@ public class InfraredDemo : JCUnityLib.ViewBase
     // 按钮用于导出所有纹理
     public Button exportAllButton;
     // 定义纹理名称
-    string[] textureNames = {
-            "A屏幕原图",
-            "B半自动识别线段",
-            "C黑白色差",
-            "D识别结果",
-            "E色差叠加识别结果",
-            "F半自动备选线段"
+    string[] textureNames;
+    /// <summary>
+    /// 更新一下菜单
+    /// </summary>
+    public void UpdateLanguage() {
+        string[] _textureNames = {
+            TextAutoLanguage2.GetTextByKey("ScreenAOriginal"), // "A屏幕原图"
+            TextAutoLanguage2.GetTextByKey("SemiAutoSegmentB"), // "B半自动识别线段"
+            TextAutoLanguage2.GetTextByKey("BlackWhiteContrastC"), // "C黑白色差"
+            TextAutoLanguage2.GetTextByKey("RecognitionResultD"), // "D识别结果"
+            TextAutoLanguage2.GetTextByKey("ColorContrastOverlayE"), // "E色差叠加识别结果"
+            TextAutoLanguage2.GetTextByKey("SemiAutoAlternativeF") // "F半自动备选线段"
         };
-    void initExport() {
-     
+        textureNames = _textureNames;
         // 设置下拉菜单的选项
         textureDropdown.ClearOptions();
         textureDropdown.AddOptions(new System.Collections.Generic.List<string>(textureNames));
-
+    }
+    void initExport() {
+        UpdateLanguage();
         // 添加导出选中纹理的按钮点击事件
         exportSelectedButton.onClick.AddListener(() => SaveTextureToLocal(textureDropdown.value));
 
@@ -1353,8 +1417,9 @@ public class InfraredDemo : JCUnityLib.ViewBase
         //选择下标+1
         int v = optionIndex + 1;
         duckHunterLevel.Set(v);
-        _sliderLineWidth.SetValueWithoutNotify(duckHunterLevel.Get());
-        _sliderLineWidth.transform.Find("Value").GetComponent<Text>().text = duckHunterLevel.Get().ToString("f1");
+        int defLevel = (int)duckHunterLevel.Get() - 1 < 0 ? 0 : (int)duckHunterLevel.Get() - 1;
+        _duckLevelDropdown.SetValueWithoutNotify(defLevel);
+        //_duckLevelDropdown.transform.Find("Value").GetComponent<Text>().text = defLevel+"";
     }
 
     void OnClick_Reset()
@@ -1364,7 +1429,8 @@ public class InfraredDemo : JCUnityLib.ViewBase
         //SetContrast(1);
 
         SetShakeFilterValue(6);
-        SetLineWidth(10);
+        SetLineWidth(4);
+        SetFanWidth(90);
         SetInfraredFilterValue(0.8f);
         SetCaptureValue(30.0f);
         SetDelayValue(30.0f);
@@ -1389,6 +1455,8 @@ public class InfraredDemo : JCUnityLib.ViewBase
 
     void OnClick_ScreenLocateManualAuto()
     {
+        ResetCenterOffset();
+        ResetPositioningData();
         infraredCameraHelper.EnterScreenLocateManualAuto();
     }
 
@@ -1600,6 +1668,13 @@ public class InfraredDemo : JCUnityLib.ViewBase
         _sliderLineWidth.SetValueWithoutNotify(lineWidth.Get());
         _sliderLineWidth.transform.Find("Value").GetComponent<Text>().text = lineWidth.Get().ToString("f1");
     }
+    public void SetFanWidth(float v)
+    {
+        fanWidth.Set(v);
+        _fanWidth.SetValueWithoutNotify(fanWidth.Get());
+        _fanWidth.transform.Find("Value").GetComponent<Text>().text = fanWidth.Get().ToString("f1");
+    }
+    
 #endregion
 #region 亮度检测部分
     public void SetInfraredFilterValue(float v)

Datei-Diff unterdrückt, da er zu groß ist
+ 562 - 112
Assets/BowArrow/InfraredCamera/Resources/InfraredDemo.prefab


+ 17 - 18
Assets/BowArrow/Modules/InfraredGuider/InfraredGuider.prefab

@@ -2189,7 +2189,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 0.5}
   m_AnchorMax: {x: 0.5, y: 0.5}
   m_AnchoredPosition: {x: 0, y: 0}
-  m_SizeDelta: {x: 950, y: 168}
+  m_SizeDelta: {x: 1400, y: 168}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &6403133998221557019
 CanvasRenderer:
@@ -2229,7 +2229,7 @@ MonoBehaviour:
     m_Alignment: 4
     m_AlignByGeometry: 0
     m_RichText: 1
-    m_HorizontalOverflow: 1
+    m_HorizontalOverflow: 0
     m_VerticalOverflow: 1
     m_LineSpacing: 1
   m_Text: "Double click the button on the device to calibrate the center of gravity.\nThen,
@@ -2649,7 +2649,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 0.5}
   m_AnchorMax: {x: 0.5, y: 0.5}
   m_AnchoredPosition: {x: 0, y: 0}
-  m_SizeDelta: {x: 950, y: 168}
+  m_SizeDelta: {x: 1400, y: 168}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &767148841805902699
 CanvasRenderer:
@@ -2681,7 +2681,7 @@ MonoBehaviour:
       m_Calls: []
   m_FontData:
     m_Font: {fileID: 12800000, guid: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
-    m_FontSize: 37
+    m_FontSize: 36
     m_FontStyle: 0
     m_BestFit: 0
     m_MinSize: 3
@@ -2689,13 +2689,13 @@ MonoBehaviour:
     m_Alignment: 4
     m_AlignByGeometry: 0
     m_RichText: 1
-    m_HorizontalOverflow: 1
+    m_HorizontalOverflow: 0
     m_VerticalOverflow: 1
     m_LineSpacing: 1
-  m_Text: "Remove the magazine module, double-click the button on it to calibrate
-    the center \nof sight, quickly reinstall the magazine, aim at the target with
-    a three-point line\n shooting posture, and complete the center of sight calibration
-    after 10 seconds."
+  m_Text: Remove the magazine module and double-click the button on it to calibrate
+    the crosshair. Quickly reinsert the magazine, then aim at the target center using
+    a three-point shooting posture. After {0} seconds, the crosshair will move to
+    the target center, completing the crosshair calibration.
 --- !u!114 &4107198112651785395
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -4190,7 +4190,7 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_text: "\u5355\u51FB\u6A21\u5757\u4E0A\u7684 <sprite=0> \u6309\u952E\uFF0C\u8FD9\u662F\u8FDB\u5165\u51C6\u5FC3\u8C03\u6574\u754C\u9762\u7684\u5F00/\u5173\uFF0C\n\u8BF7\u8FDE\u7EED\u64CD\u4F5C\u4E24\u6B21\u3002"
+  m_text: "\u5355\u51FB\u8BBE\u5907\u4E0A\u7684\u6309\u952E <sprite=0>\uFF0C\u8FDB\u5165\u51C6\u5FC3\u8C03\u6574\u754C\u9762\u7684\u5F00/\u5173\uFF0C\\n\u8BF7\u5355\u51FB\u4E24\u6B21\uFF08\u95F4\u9694\u4E00\u79D2\uFF09\u3002"
   m_isRightToLeft: 0
   m_fontAsset: {fileID: 11400000, guid: bbcfb1567bce0b641adc9310d760d234, type: 2}
   m_sharedMaterial: {fileID: -8666424993308654677, guid: bbcfb1567bce0b641adc9310d760d234, type: 2}
@@ -4229,7 +4229,7 @@ MonoBehaviour:
   m_textAlignment: 65535
   m_characterSpacing: 0
   m_wordSpacing: 0
-  m_lineSpacing: 0
+  m_lineSpacing: 31
   m_lineSpacingMax: 0
   m_paragraphSpacing: 0
   m_charWidthMaxAdj: 0
@@ -4271,7 +4271,7 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 0f4efe98aab6c6b41a7ee1f4c49df27b, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  textKey: TopTip_CrossHair
+  textKey: TopTip_CrossHairPro
   layoutRebuildObject: {fileID: 0}
   languageFontSizes:
   - language: 0
@@ -6626,10 +6626,9 @@ MonoBehaviour:
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_text: Press and hold the button<sprite=0>on the module for 3 seconds to calibrate
-    the center of sight. Then, use the normal bow position and aim at the target
-    with the head of the arrow tube as the reference point. After 10 seconds, complete
-    the center of sight calibration
+  m_text: Press and hold the button on the device <sprite=0>, then assume a normal
+    bow-drawing posture. Aim the arrowhead at the target center, and after 10 seconds,
+    the crosshair will move to the target center, completing the crosshair calibration.
   m_isRightToLeft: 0
   m_fontAsset: {fileID: 11400000, guid: bbcfb1567bce0b641adc9310d760d234, type: 2}
   m_sharedMaterial: {fileID: -8666424993308654677, guid: bbcfb1567bce0b641adc9310d760d234, type: 2}
@@ -6656,8 +6655,8 @@ MonoBehaviour:
   m_faceColor:
     serializedVersion: 2
     rgba: 4294967295
-  m_fontSize: 37
-  m_fontSizeBase: 37
+  m_fontSize: 36
+  m_fontSizeBase: 36
   m_fontWeight: 400
   m_enableAutoSizing: 0
   m_fontSizeMin: 18

+ 2 - 2
Assets/BowArrow/Modules/InfraredGuider/InfraredLightGuider2.prefab

@@ -475,7 +475,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 1}
   m_AnchorMax: {x: 0.5, y: 1}
   m_AnchoredPosition: {x: 716, y: -275}
-  m_SizeDelta: {x: 160, y: 50}
+  m_SizeDelta: {x: 400, y: 50}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5225210364050453330
 CanvasRenderer:
@@ -2119,7 +2119,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 1}
   m_AnchorMax: {x: 0.5, y: 1}
   m_AnchoredPosition: {x: 734, y: -279}
-  m_SizeDelta: {x: 160, y: 50}
+  m_SizeDelta: {x: 400, y: 50}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5623726213436862701
 CanvasRenderer:

+ 336 - 12
Assets/BowArrow/Resources/Prefabs/Views/Home/DeviceViewInfrared.prefab

@@ -77,7 +77,7 @@ RectTransform:
   m_ConstrainProportionsScale: 0
   m_Children:
   - {fileID: 3319966071402702626}
-  - {fileID: 5368886303976252795}
+  - {fileID: 9195925919553701895}
   m_Father: {fileID: 2624584339530074265}
   m_RootOrder: 2
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -520,6 +520,7 @@ MonoBehaviour:
   - {fileID: 21300000, guid: 4083f8e1ca929ce4bb6ec7d9c29c9365, type: 3}
   _TextAutoLanguage2: {fileID: 4288816417670544630}
   deviceIndex: 0
+  omitText: {fileID: 5895775015745707182}
 --- !u!1 &1049268609651015207
 GameObject:
   m_ObjectHideFlags: 0
@@ -1310,6 +1311,7 @@ MonoBehaviour:
   - {fileID: 21300000, guid: 4083f8e1ca929ce4bb6ec7d9c29c9365, type: 3}
   _TextAutoLanguage2: {fileID: 2040204180109477403}
   deviceIndex: 1
+  omitText: {fileID: 8172346654568656097}
 --- !u!1 &1805942828472048259
 GameObject:
   m_ObjectHideFlags: 0
@@ -2866,6 +2868,71 @@ MonoBehaviour:
   m_FillOrigin: 0
   m_UseSpriteMesh: 0
   m_PixelsPerUnitMultiplier: 1
+--- !u!1 &3663055746462982435
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 9195925919553701895}
+  - component: {fileID: 5424964691604017367}
+  m_Layer: 5
+  m_Name: statusParent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &9195925919553701895
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3663055746462982435}
+  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_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 5368886303976252795}
+  - {fileID: 6540119674589221142}
+  m_Father: {fileID: 8809921120636371870}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 310, y: -131.5}
+  m_SizeDelta: {x: 600, y: 45}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &5424964691604017367
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3663055746462982435}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 4
+  m_Spacing: 0
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
 --- !u!1 &3975078034313454886
 GameObject:
   m_ObjectHideFlags: 0
@@ -5419,7 +5486,7 @@ RectTransform:
   m_ConstrainProportionsScale: 0
   m_Children:
   - {fileID: 5756235976269569222}
-  - {fileID: 5224722728605276788}
+  - {fileID: 2942170420610414968}
   m_Father: {fileID: 8359389633136827950}
   m_RootOrder: 2
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -5608,6 +5675,102 @@ MonoBehaviour:
   m_FillOrigin: 0
   m_UseSpriteMesh: 0
   m_PixelsPerUnitMultiplier: 1
+--- !u!1 &7830343383463296454
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5016398519639811147}
+  - component: {fileID: 2108338989013650304}
+  - component: {fileID: 8172346654568656097}
+  - component: {fileID: 3584349997327841576}
+  m_Layer: 5
+  m_Name: omit
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5016398519639811147
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7830343383463296454}
+  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_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 2942170420610414968}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 500, y: -22.5}
+  m_SizeDelta: {x: 200, y: 45}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &2108338989013650304
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7830343383463296454}
+  m_CullTransparentMesh: 1
+--- !u!114 &8172346654568656097
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7830343383463296454}
+  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: 0.19607843, g: 0.19607843, b: 0.19607843, 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: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 45
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 1
+    m_MaxSize: 45
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: ...
+--- !u!114 &3584349997327841576
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7830343383463296454}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0f4efe98aab6c6b41a7ee1f4c49df27b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  textKey: Connect_BLE_Connect
+  layoutRebuildObject: {fileID: 0}
+  languageFontSizes: []
 --- !u!1 &7867030853648936596
 GameObject:
   m_ObjectHideFlags: 0
@@ -5892,13 +6055,13 @@ RectTransform:
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_ConstrainProportionsScale: 0
   m_Children: []
-  m_Father: {fileID: 8809921120636371870}
-  m_RootOrder: 1
+  m_Father: {fileID: 9195925919553701895}
+  m_RootOrder: 0
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 1}
   m_AnchorMax: {x: 0, y: 1}
-  m_AnchoredPosition: {x: 310, y: -131.5}
-  m_SizeDelta: {x: 285, y: 45}
+  m_AnchoredPosition: {x: 200, y: -22.5}
+  m_SizeDelta: {x: 400, y: 45}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &2148228175767830763
 CanvasRenderer:
@@ -5935,7 +6098,7 @@ MonoBehaviour:
     m_BestFit: 0
     m_MinSize: 1
     m_MaxSize: 50
-    m_Alignment: 4
+    m_Alignment: 5
     m_AlignByGeometry: 0
     m_RichText: 1
     m_HorizontalOverflow: 1
@@ -7361,13 +7524,13 @@ RectTransform:
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_ConstrainProportionsScale: 0
   m_Children: []
-  m_Father: {fileID: 3115437585392817648}
-  m_RootOrder: 1
+  m_Father: {fileID: 2942170420610414968}
+  m_RootOrder: 0
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 1}
   m_AnchorMax: {x: 0, y: 1}
-  m_AnchoredPosition: {x: 310, y: -131.5}
-  m_SizeDelta: {x: 285, y: 45}
+  m_AnchoredPosition: {x: 200, y: -22.5}
+  m_SizeDelta: {x: 400, y: 45}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &49497840751108719
 CanvasRenderer:
@@ -7404,7 +7567,7 @@ MonoBehaviour:
     m_BestFit: 0
     m_MinSize: 1
     m_MaxSize: 45
-    m_Alignment: 4
+    m_Alignment: 5
     m_AlignByGeometry: 0
     m_RichText: 1
     m_HorizontalOverflow: 1
@@ -7801,6 +7964,167 @@ MonoBehaviour:
     m_VerticalOverflow: 1
     m_LineSpacing: 1
   m_Text: "\u672A\u8FDE\u63A5"
+--- !u!1 &9031970122640690138
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2942170420610414968}
+  - component: {fileID: 8667097138556066916}
+  m_Layer: 5
+  m_Name: statusParent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2942170420610414968
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9031970122640690138}
+  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_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 5224722728605276788}
+  - {fileID: 5016398519639811147}
+  m_Father: {fileID: 3115437585392817648}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 310, y: -131.5}
+  m_SizeDelta: {x: 600, y: 45}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &8667097138556066916
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9031970122640690138}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 0
+  m_Spacing: 0
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!1 &9143769868297749396
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6540119674589221142}
+  - component: {fileID: 4561199668158207216}
+  - component: {fileID: 5895775015745707182}
+  - component: {fileID: 1955914322198322870}
+  m_Layer: 5
+  m_Name: omit
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6540119674589221142
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9143769868297749396}
+  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_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 9195925919553701895}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 500, y: -22.5}
+  m_SizeDelta: {x: 200, y: 45}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &4561199668158207216
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9143769868297749396}
+  m_CullTransparentMesh: 1
+--- !u!114 &5895775015745707182
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9143769868297749396}
+  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: 0.19607843, g: 0.19607843, b: 0.19607843, 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: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 45
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 1
+    m_MaxSize: 50
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: ...
+--- !u!114 &1955914322198322870
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9143769868297749396}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0f4efe98aab6c6b41a7ee1f4c49df27b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  textKey: Connect_BLE_Connect
+  layoutRebuildObject: {fileID: 0}
+  languageFontSizes: []
 --- !u!1 &9222168600980044169
 GameObject:
   m_ObjectHideFlags: 0

+ 0 - 95
Assets/BowArrow/Scenes/GameDouble.unity

@@ -2351,101 +2351,6 @@ Transform:
   m_Father: {fileID: 1188418089}
   m_RootOrder: 0
   m_LocalEulerAnglesHint: {x: -1.2711266, y: -6.284285, z: -5.6597686}
---- !u!1 &132979278
-GameObject:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  serializedVersion: 6
-  m_Component:
-  - component: {fileID: 132979281}
-  - component: {fileID: 132979280}
-  - component: {fileID: 132979279}
-  m_Layer: 0
-  m_Name: Reporter
-  m_TagString: Untagged
-  m_Icon: {fileID: 0}
-  m_NavMeshLayer: 0
-  m_StaticEditorFlags: 0
-  m_IsActive: 1
---- !u!114 &132979279
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 132979278}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 6767a180de870304caa2013b2772dd62, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
---- !u!114 &132979280
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 132979278}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 600c02144c4813244abd262cbcbe8825, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
-  show: 0
-  UserData: 
-  fps: 0
-  fpsText: 
-  images:
-    clearImage: {fileID: 0}
-    collapseImage: {fileID: 0}
-    clearOnNewSceneImage: {fileID: 0}
-    showTimeImage: {fileID: 0}
-    showSceneImage: {fileID: 0}
-    userImage: {fileID: 0}
-    showMemoryImage: {fileID: 0}
-    softwareImage: {fileID: 0}
-    dateImage: {fileID: 0}
-    showFpsImage: {fileID: 0}
-    infoImage: {fileID: 0}
-    saveLogsImage: {fileID: 0}
-    searchImage: {fileID: 0}
-    copyImage: {fileID: 0}
-    copyAllImage: {fileID: 0}
-    closeImage: {fileID: 0}
-    buildFromImage: {fileID: 0}
-    systemInfoImage: {fileID: 0}
-    graphicsInfoImage: {fileID: 0}
-    backImage: {fileID: 0}
-    logImage: {fileID: 0}
-    warningImage: {fileID: 0}
-    errorImage: {fileID: 0}
-    barImage: {fileID: 0}
-    button_activeImage: {fileID: 0}
-    even_logImage: {fileID: 0}
-    odd_logImage: {fileID: 0}
-    selectedImage: {fileID: 0}
-    reporterScrollerSkin: {fileID: 0}
-  size: {x: 32, y: 32}
-  maxSize: 20
-  numOfCircleToShow: 1
-  Initialized: 0
---- !u!4 &132979281
-Transform:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 132979278}
-  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_ConstrainProportionsScale: 0
-  m_Children: []
-  m_Father: {fileID: 0}
-  m_RootOrder: 3
-  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 --- !u!1 &133226967
 GameObject:
   m_ObjectHideFlags: 0

+ 60 - 8
Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/cn.json

@@ -552,11 +552,13 @@
   手动识别部分
   **/
   "TitleTip1": "调整激光定位器的角度和位置,\n使整个电视屏幕完整地位于梯形框内",
-  "TitleTipHasData": "如定位白框与电视屏幕匹配,可点击“确认”按键,跳过定位流程否则调整激光定位器的角度和位置,使整个电视屏幕完整地位于梯形框内,点击“自动”按键",
+  "TitleTipHasData": "如定位白框与电视屏幕位置一致,可点击“确认”按键,跳过定位流程否则调整激光定位器的角度和位置,使整个电视屏幕完整的位于梯形框内,点击“自动定位”按键",
   "TitleTip2": "如自动识别不准确,可调整激光定位器或调整图像对比度,使屏幕\n边缘更清晰后,再次自动识别;\n如多次自动识别不成功,可点击手动功能,并用手指拖动定位区域\n四个角进行调整,点击确认进入下一步。",
+  "TitleTipManual": "用手动拖动白色线条框来标记出电视屏幕的显示区域",
   "Withdrawal": "撤销",
   "Automatic": "自动",
   "Manual": "手动",
+  "ManualSetting": "手动设置",
   "Confirm": "确认",
   "Finish": "完成",
   "Reset": "重置",
@@ -566,7 +568,7 @@
   "TitleTipMarker-HOUYIPro": "HOUYI Pro瞄准模块",
   "TitleTipMarker-ArtemisPro": "Artemis Pro",
   "TitleTipMarker-M9": "操作M9手枪依次瞄准屏幕的四个角\n扣动扳机进行标记(四角位置标签)",
-  "TitleTipMarker2": "操作设备对准电视,按提示依次用光点瞄准梯形框中电视屏幕内定位框的四个角,并单击准心键进行标记。标记需位于定位框内。",
+  "TitleTipMarker2": "操作瞄准器设备对准电视,按提示依次用红外光点瞄准摄像头中显示区域内白框的四个角,并单击瞄准器的准心键进行标记。\n①  如白框与电视屏幕显示区域位置一致,点击“完成”按键\n②  如标记中发现白框与电视屏幕显示区域差异较大,点击“自动定位”按键,\n重新进行自动识别\n③  如多次自动识别无效后,点击“手动设置”按键,进入手动设置方式",
   "TipMiddle": "请标记:{0}角的点",
   "TipTopLeft": "左上",
   "TipTopRight": "右上",
@@ -575,8 +577,9 @@
   "TipMarkComplete": "标记完成!",
   "TipMarkerError": "定位失败,需按要求重新标记。",
   "TipQuadError": "定位失败,不是有效的四边形。",
-  "TipAutoEnd": "① 如无法识别出屏幕,需屏蔽环境干扰光源后,点击“自动”按键重新识别\n② 如白框与电视屏幕匹配,点击“确认”按键,跳过定位流程 \n③ 如白框与电视屏幕不匹配,点击“环境测光”按键,继续定位流程",
-  "TipLightCtrl": "操作设备对准电视,将光点位于梯形框中电视屏幕,红色十字会在光点上,并随光点移动;如没有,需要找出干扰光源关闭它、调整激光定位器位置或调小亮度和对比度",
+  "TipAutoEnd": "① 如无法识别出屏幕,需屏蔽环境干扰光源后,点击“自动定位”按键重新识别\n② 如白框与电视屏幕显示区域位置一致,点击“确认”按键,跳过定位流程\n③ 如白框与电视屏幕显示区域位置不一致,点击“环境测光”按键,继续定位流程",
+  "TipLightCtrl": "操作设备对准电视,将瞄准器的红外光点位于梯形框内的电视屏幕,红色十字会在光点上,并随光点移动;如没有,需要找出干扰光源关闭它或调小亮度和对比度",
+
 
   "ScreenPositioningSuccessful-title": "\u3000\u3000请用手指点击选择最合适的屏幕区域结果。如未发现明显差异,请任选其一。如识别到的屏幕区域不合适,请点击“返回”重新识别。",
   "FirstResult": "结果一",
@@ -589,11 +592,11 @@
    红外连接后游戏射击页面
   **/
   "TopTip_CrossHair": "单击模块上的 <sprite=0> 按键,这是进入准心调整界面的开/关,\n请单击两次(间隔一秒)。",
-  "TopTip_CrossHairPro": "单击设备上的按键,这是进入准心调整界面的开/关,\n请单击两次(间隔一秒)。",
+  "TopTip_CrossHairPro": "单击设备上的按键 <sprite=0>,进入准心调整界面的开/关,\n请单击两次(间隔一秒)。",
   "TopTip_CrossHairGunPro": "取出弹夹模块,单击其上的按键,这是进入准心\n调整界面的开/关,请单击两次(间隔一秒)。",
-  "TopTip_ARTEMISPro": " 双击设备上的按键进行准心校准,之后请用正常的拉弓姿势,\n以箭筒头部瞄准靶心,{0}秒后准心会移动到靶心,完成准心校准。",
+  "TopTip_ARTEMISPro": " 双击设备上的按键,之后用正常的拉弓姿势,\n以箭筒头部瞄准靶心,10秒后准心会移动到靶心,完成准心校准。",
   "TopTip_GunPro": "取出弹夹模块,双击其上的按键进行准心校准,快速装回弹夹后,\n用三点一线的射击姿势瞄准靶心,{0}秒后准心会移动到靶心,完成准心校准。",
-  "TopTip": " 长按模块上的按键 <sprite=0> 3秒进行准心校准,之后请用正常的拉弓姿势,以箭筒头部瞄准靶心,{0}秒后准心会移动到靶心,完成准心校准。",
+  "TopTip": " 长按设备上的按键 <sprite=0>,之后用正常的拉弓姿势,以箭筒头部瞄准靶心,10秒后准心会移动到靶心,完成准心校准。",
   "TopTip2": "准心已校准,请射中靶子后,自动退出界面。",
   "LeftTitle": "异常问题检测",
   "LeftTip": "1、如发现光标不顺滑,或光标的移动范围不够大,请调整图像亮度或重新进行屏幕定位。\n\n2、如发现光标移动时有延时的现象,请调整分辨率或更换性能更好的手机后,再重新进行测试。\n\n3、如发现光标会随机闪烁不同的位置,或无法移动时,请点击环境测光寻找干扰源,并屏蔽干扰源。",
@@ -632,6 +635,55 @@
   "BulletTip": "请更换弹夹!",
 
   //偏移量
-  "CalibrationOffset": "校准"
+  "CalibrationOffset": "校准",
+
+  /**
+  Infrared Demo 界面字段
+  **/
+  "ManualPositioning": "手动定位",
+  "AutomaticPositioning": "自动定位",
+  "QuasiCenterOffset": "准心偏移量",
+  "Export": "导出",
+  "ExportAll": "导出全部",
+  "AdjustUVCParameters": "调整UVC参数",
+  "CaptureValue": "Capture 值",
+  "DelayValue": "Delay 值",
+  "CameraResolution": "摄像机分辨率",
+  "LineSegmentWidth": "绘制线段宽度",
+  "FanOuterRadius": "扇形半径",
+  "JitterFilterValue": "抖动过滤值",
+  "BrightnessDetectionThreshold": "检测亮度的阈值",
+  "ResetParameters": "重置参数",
+  "ClearAllData": "清空所有数据",
+  "DuckHuntLevelSelection": "野鸭开始关卡选择",
+  "ZoomOut": "缩小",
+  "AutoCalibrationFixedResolution": "自动校准的固定分辨率",
+  "CurrentCameraRenderedResolution": "当前摄像机渲染的分辨率",
+  "ScreenAOriginal": "A屏幕原图",
+  "SemiAutoSegmentB": "B半自动识别线段",
+  "BlackWhiteContrastC": "C黑白色差",
+  "RecognitionResultD": "D识别结果",
+  "ColorContrastOverlayE": "E色差叠加识别结果",
+  "SemiAutoAlternativeF": "F半自动备选线段",
+  "AutoRecognition": "自动识别",
+  "SemiAutoRecognition": "半自动识别",
+  "ManualRecognition": "手动识别",
+  "HideInterface": "隐藏界面",
+  "DebugInfrared": "调试红外",
+  "Close": "关闭",
+  "WaitingForInitialization": "等待初始化..",
+  "CurrentRenderingWhite": "当前渲染(白)",
+  "AutomaticYellow": "自动(黄)",
+  "SemiAutomaticRed": "半自动(红)",
+  "ManualGreen": "手动(绿)",
+
+  "AutoExposureMode": "自动曝光模式",
+  "ExposureTimeAbsolute": "曝光时间(绝对)",
+  "Hue": "色调",
+  "Saturation": "饱和度",
+  "Sharpness": "锐度",
+  "Gamma": "伽玛",
+  "BacklightCompensation": "背光补偿",
+  "Gain": "增益"
 
 }

+ 61 - 11
Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/en.json

@@ -601,12 +601,13 @@
   手动识别部分
   **/
   "TitleTip1": "Adjust the angle and position of the laser locator,so that the \nentire TV screen fits completely within the trapezoidal frame.",
-  "TitleTipHasData": "If the white positioning frame matches the TV screen, you can click the 'Confirm' button to skip the positioning process; otherwise, adjust the angle and position of the laser locator so that the entire TV screen fits completely within the trapezoidal frame, then click the 'Auto' button.",
-
+  "TitleTipHasData": "If the positioned white frame matches the TV screen's position, click the 'Confirm' button to skip the positioning process. Otherwise, adjust the angle and position of the laser locator so that the entire TV screen is fully within the trapezoidal frame, then click the 'Auto Positioning' button.",
   "TitleTip2": "If the automatic recognition is not accurate, you can adjust the laser locator or adjust the \nimage contrast to make the screen edge clearer and then automatically recognize it again; \n If automatic recognition fails multiple times, click the manual function and drag the four \ncorners of the positioning area with your finger to adjust. Click OK to proceed to the next step. ",
+  "TitleTipManual": "Manually drag the white line frame to mark the display area of the TV screen.",
   "Withdrawal": "Revoke",
   "Automatic": "Automatic",
   "Manual": "Manual",
+  "ManualSetting": "Manual Setting",
   "Confirm": "Confirm",
   "Finish": "Finish",
   "Reset": "Reset",
@@ -616,7 +617,7 @@
   "TitleTipMarker-HOUYIPro": "HOUYI Pro Aiming Module",
   "TitleTipMarker-ArtemisPro": "Artemis Pro",
   "TitleTipMarker-M9": "Operate M9 pistol to aim at the four corners of the screen \nin sequence, pull the trigger to mark (four corner position label)",
-  "TitleTipMarker2": "Position the device facing the TV, and follow the instructions to aim the light point at the four corners of the target box within the TV screen one by one. Click the reticle button to mark each corner. The marks must be within the target box.",
+  "TitleTipMarker2": "Operate the aiming device to face the TV, and follow the instructions to aim the infrared light dot at the four corners of the white frame within the displayed area on the camera. Press the crosshair button on the aiming device to mark each corner.\n① If the white frame matches the TV screen's display area, click the 'Finish' button.\n② If there is a significant difference between the white frame and the TV screen's display area during marking, click the 'Auto Positioning' button to retry automatic detection.\n③ If multiple automatic detections fail, click the 'Manual Setup' button to enter manual setup mode.",
   "TipMiddle": "Please mark: Point at the {0} corner",
   "TipTopLeft": "Top-Left",
   "TipTopRight": "Top-Right",
@@ -625,8 +626,8 @@
   "TipMarkComplete": "Mark Complete!",
   "TipMarkerError": "Positioning failed. You need to re-mark as instructed.",
   "TipQuadError": "Positioning failed. The shape is not a valid quadrilateral.",
-  "TipAutoEnd": "① If the screen cannot be recognized, block the environmental light interference and click the 'Auto' button to re-recognize.\n② If the white frame matches the TV screen, click the 'Confirm' button to skip the positioning process.\n③ If the white frame does not match the TV screen, click the 'Environment Light Measurement' button to continue the positioning process.",
-  "TipLightCtrl": "Position the device facing the TV, placing the light point within the trapezoidal frame on the TV screen. A red cross will appear at the light point and move with it. If not, identify and turn off the interfering light source, adjust the position of the laser locator, or reduce the brightness and contrast.",
+  "TipAutoEnd": "① If the screen cannot be detected, eliminate any ambient light interference and click the 'Auto Positioning' button to retry detection.\n② If the white frame matches the TV screen's display area, click the 'Confirm' button to skip the positioning process.\n③ If the white frame does not match the TV screen's display area, click the 'Ambient Light Measurement' button to continue the positioning process.",
+  "TipLightCtrl": "Position the device facing the TV and ensure the infrared light dot from the aiming device is within the TV screen inside the trapezoidal frame. A red cross should appear on the light dot and move with it. If not, identify and eliminate any interfering light sources or reduce the brightness and contrast.",
 
   "ScreenPositioningSuccessful-title": "\u3000\u3000Please tap with your finger to select the most suitable screen region result. If no obvious difference is found, choose any one. If the identified screen region is not suitable, click 'Back' to re-recognize.",
   "FirstResult": "First Result",
@@ -639,12 +640,11 @@
    红外连接后游戏射击页面
   **/
   "TopTip_CrossHair": "Click the <sprite=0> button on the module to enter the center adjustment \n interface. Please click twice (with an interval of one second)",
-  "TopTip_CrossHairPro": "Click the button on the device. This toggles the crosshair adjustment interface on/off.Please click twice (with an interval of one second).",
+  "TopTip_CrossHairPro": "Click the button on the device <sprite=0> to toggle the crosshair adjustment interface on/off. Please click twice with a one-second interval.",
   "TopTip_CrossHairGunPro": "Remove the magazine module and click the button on it. This is the on/off button to enter the alignment adjustment interface. Please click twice (with an interval of one second)",
-  "TopTip_ARTEMISPro": "Double-click the button on the device for reticle calibration. Then, use \nthe normal bow-drawing posture, aim the bow at the bullseye, and after {0} seconds, \nthe reticle will move to the bullseye, completing the calibration.",
-  "TopTip_GunPro": "Remove the magazine module, double-click the button on it for reticle calibration. \nAfter quickly reattaching the magazine, use a three-point alignment shooting posture \nto aim at the bullseye. After {0} seconds, the reticle will move to the bullseye, completing the calibration.",
-  "TopTip": "Press and hold the button on the module <sprite=0> for 3 seconds to calibrate the reticle. Then, use the normal bow-drawing posture, aim the bow at the bullseye, and after {0} seconds, the reticle will move to the bullseye, completing the calibration.",
-
+  "TopTip_ARTEMISPro": "Double-click the button on the device, then assume a normal bow-drawing posture. Aim the arrowhead at the target center, and after 10 seconds, the crosshair will move to the target center, completing the crosshair calibration.",
+  "TopTip_GunPro": "Remove the magazine module and double-click the button on it to calibrate the crosshair. Quickly reinsert the magazine, then aim at the target center using a three-point shooting posture. After {0} seconds, the crosshair will move to the target center, completing the crosshair calibration.",
+  "TopTip": "Press and hold the button on the device <sprite=0>, then assume a normal bow-drawing posture. Aim the arrowhead at the target center, and after 10 seconds, the crosshair will move to the target center, completing the crosshair calibration.",
 
   "TopTip2": "Accurate heart calibration, please hit the target and automatically exit the interface.",
   "LeftTitle": "Abnormal Problem Detection",
@@ -685,5 +685,55 @@
   **/
   "BulletTip": "Please replace the magazine!",
   //偏移量
-  "CalibrationOffset": "Calibration"
+  "CalibrationOffset": "Calibration",
+
+  /**
+  Infrared Demo 界面字段
+  **/
+  "ManualPositioning": "Manual Positioning",
+  "AutomaticPositioning": "Automatic Positioning",
+  "QuasiCenterOffset": "Quasi Center Offset",
+  "Export": "Export",
+  "ExportAll": "Export All",
+  "AdjustUVCParameters": "Adjust UVC Parameters",
+  "CaptureValue": "Capture Value",
+  "DelayValue": "Delay Value",
+  "CameraResolution": "Camera Resolution",
+  "LineSegmentWidth": "Line Segment Width",
+  "FanOuterRadius": "Fan Outer Radius",
+  "JitterFilterValue": "Jitter Filter Value",
+  "BrightnessDetectionThreshold": "Brightness Detection Threshold",
+  "ResetParameters": "Reset Parameters",
+  "ClearAllData": "Clear All Data",
+  "DuckHuntLevelSelection": "Duck Hunt Level Selection",
+  "ZoomOut": "Zoom Out",
+  "AutoCalibrationFixedResolution": "Auto Calibration Fixed Resolution",
+  "CurrentCameraRenderedResolution": "Current Camera Rendered Resolution",
+  "ScreenAOriginal": "Screen A Original",
+  "SemiAutoSegmentB": "Semi Auto Segment B",
+  "BlackWhiteContrastC": "Black White Contrast C",
+  "RecognitionResultD": "Recognition Result D",
+  "ColorContrastOverlayE": "Color Contrast Overlay E",
+  "SemiAutoAlternativeF": "Semi Auto Alternative F",
+  "AutoRecognition": "Auto Recognition",
+  "SemiAutoRecognition": "Semi Auto Recognition",
+  "ManualRecognition": "Manual Recognition",
+  "HideInterface": "Hide Interface",
+  "DebugInfrared": "Debug Infrared",
+  "Close": "Close",
+  "WaitingForInitialization": "Waiting For Initialization..",
+  "CurrentRenderingWhite": "Current Rendering (White)",
+  "AutomaticYellow": "Automatic (Yellow)",
+  "SemiAutomaticRed": "Semi Automatic (Red)",
+  "ManualGreen": "Manual (Green)",
+
+  "AutoExposureMode": "Auto Exposure Mode",
+  "ExposureTimeAbsolute": "Exposure Time (Absolute)",
+  "Hue": "Hue",
+  "Saturation": "Saturation",
+  "Sharpness": "Sharpness",
+  "Gamma": "Gamma",
+  "BacklightCompensation": "Backlight Compensation",
+  "Gain": "Gain"
+
 }

+ 47 - 0
Assets/BowArrow/Scripts/View/Home/DeviceView_ItemShow.cs

@@ -47,6 +47,13 @@ public class DeviceView_ItemShow : MonoBehaviour
     bool bShowInfo = false;
     // Start is called before the first frame update
     // bool bProcess = false;
+
+
+    [SerializeField] Text omitText;
+    private int dotCount = 0;
+    private float interval = 0.5f; // 标点更新间隔
+    private float timer = 0f;
+
     private void Awake()
     {
         AimHandler.ins.aimDeviceInfoChangeEvent += onShowDeviceInfo;
@@ -252,6 +259,26 @@ public class DeviceView_ItemShow : MonoBehaviour
         }
     }
 
+    void UpdateLoadingText()
+    {
+        timer += Time.deltaTime;
+
+        // 每隔 `interval` 秒更新一次标点符号
+        if (timer >= interval)
+        {
+            dotCount = (dotCount + 1) % 4; // 标点数量从 0 到 3 循环
+            omitText.text = new string('.', dotCount); // 添加相应数量的点
+            timer = 0f; // 重置计时器
+        }
+    }
+
+    // 停止加载效果
+    public void StopLoading()
+    {
+        dotCount = 0;
+        omitText.text = ""; // 停止时恢复为基础文本
+    }
+
     void RequestBatteryForBow()
     {
         try
@@ -337,6 +364,16 @@ public class DeviceView_ItemShow : MonoBehaviour
             string name = BluetoothStatus.GetStatusTextKey(BluetoothAim.ins.status);
             if (name != _TextAutoLanguage2.GetTextKey())
                 _TextAutoLanguage2.SetTextKey(name);
+
+            if (BluetoothAim.ins.status == BluetoothStatusEnum.Connecting)
+            {
+                omitText.gameObject.SetActive(true);
+                UpdateLoadingText();
+            }
+            else
+            {
+                StopLoading();
+            }
         }
         else if (bluetoothPlayer == BluetoothPlayer.SECONDE_PLAYER)
         {
@@ -346,6 +383,16 @@ public class DeviceView_ItemShow : MonoBehaviour
             if (name != _TextAutoLanguage2.GetTextKey())
                 _TextAutoLanguage2.SetTextKey(name);
 
+            if (smartBowHelper.GetBluetoothStatus() == SmartBowSDK.BluetoothStatusEnum.Connecting)
+            {
+                omitText.gameObject.SetActive(true);
+                UpdateLoadingText();
+            }
+            else
+            {
+                StopLoading();
+            }
+
         }
 
     }

+ 0 - 95
Assets/DuckHunter/Scenes/DuckHunter.unity

@@ -1179,101 +1179,6 @@ RectTransform:
   m_AnchoredPosition: {x: 0, y: 0}
   m_SizeDelta: {x: 0, y: 0}
   m_Pivot: {x: 0, y: 0}
---- !u!1 &295685091
-GameObject:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  serializedVersion: 6
-  m_Component:
-  - component: {fileID: 295685094}
-  - component: {fileID: 295685093}
-  - component: {fileID: 295685092}
-  m_Layer: 0
-  m_Name: Reporter
-  m_TagString: Untagged
-  m_Icon: {fileID: 0}
-  m_NavMeshLayer: 0
-  m_StaticEditorFlags: 0
-  m_IsActive: 1
---- !u!114 &295685092
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 295685091}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 6767a180de870304caa2013b2772dd62, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
---- !u!114 &295685093
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 295685091}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 600c02144c4813244abd262cbcbe8825, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
-  show: 0
-  UserData: 
-  fps: 0
-  fpsText: 
-  images:
-    clearImage: {fileID: 2800000, guid: 112c6fcf56e349449ab2e6ad76b67816, type: 3}
-    collapseImage: {fileID: 2800000, guid: 4623f326a884a2546ab39078bf7822c3, type: 3}
-    clearOnNewSceneImage: {fileID: 2800000, guid: 3a6bc61a8319b1949ab9f1f2db1302b4, type: 3}
-    showTimeImage: {fileID: 2800000, guid: 782e03669fa4a614e89ef56252134250, type: 3}
-    showSceneImage: {fileID: 2800000, guid: ff4dfb29f203a174ab8e4c498afe908a, type: 3}
-    userImage: {fileID: 2800000, guid: 2bcdc012e7356f1449ce7d3a31dc458c, type: 3}
-    showMemoryImage: {fileID: 2800000, guid: f447d62f2dacf9843be7cbf168a3a9d0, type: 3}
-    softwareImage: {fileID: 2800000, guid: 6c91fc88ee6c791468318d85febfb48d, type: 3}
-    dateImage: {fileID: 2800000, guid: a7561cd0a9f62a84e99bff1abce2a222, type: 3}
-    showFpsImage: {fileID: 2800000, guid: 90b2f48155dc0e74f8e428561ac79da5, type: 3}
-    infoImage: {fileID: 2800000, guid: 2954bef266e6d794aba08ceacc887a0f, type: 3}
-    saveLogsImage: {fileID: 2800000, guid: 4a4821d80a1fc774fb76eac6213544e7, type: 3}
-    searchImage: {fileID: 2800000, guid: bfef37b5a26d2264798616d960451329, type: 3}
-    copyImage: {fileID: 2800000, guid: 7f36d71624c630046b855909c497be17, type: 3}
-    copyAllImage: {fileID: 2800000, guid: 10189803ef22ba546b7f511c1b908fe5, type: 3}
-    closeImage: {fileID: 2800000, guid: b65e9be99974bc94eab5d6698811d0b8, type: 3}
-    buildFromImage: {fileID: 2800000, guid: 8702be598dd9f504ca33be2afee2ca33, type: 3}
-    systemInfoImage: {fileID: 2800000, guid: e9011b1dc9256ad4d9c19a31c595f95f, type: 3}
-    graphicsInfoImage: {fileID: 2800000, guid: 999d31716332cc04eb4abc9c9270b0ca, type: 3}
-    backImage: {fileID: 2800000, guid: a0632a18e7c665641b94fea66506ab50, type: 3}
-    logImage: {fileID: 2800000, guid: e876b803a4dd5c5488078071d15aa9c0, type: 3}
-    warningImage: {fileID: 2800000, guid: 1066be8e7b994b94c8a182b8dbe30705, type: 3}
-    errorImage: {fileID: 2800000, guid: 7640ebf8b3a92124d821d3b4b8b3fd7e, type: 3}
-    barImage: {fileID: 2800000, guid: 8128d4f4c0193e34586f9631ef7d4787, type: 3}
-    button_activeImage: {fileID: 2800000, guid: 2580a2e903691e44282e56ed6e0ff37a, type: 3}
-    even_logImage: {fileID: 2800000, guid: d27aad55b568c6544b0b95a95da44bc7, type: 3}
-    odd_logImage: {fileID: 2800000, guid: 8ffbb44a2c3adae45913474e4fd487f5, type: 3}
-    selectedImage: {fileID: 2800000, guid: 17117a429b08e7e43b0b6c8421de69fe, type: 3}
-    reporterScrollerSkin: {fileID: 11400000, guid: 1cc68832d00d3284a9324a4dc05be753, type: 2}
-  size: {x: 32, y: 32}
-  maxSize: 20
-  numOfCircleToShow: 1
-  Initialized: 0
---- !u!4 &295685094
-Transform:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 295685091}
-  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_ConstrainProportionsScale: 0
-  m_Children: []
-  m_Father: {fileID: 0}
-  m_RootOrder: 2
-  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 --- !u!1 &319739768
 GameObject:
   m_ObjectHideFlags: 0

+ 3 - 2
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/LineGuess.cs → Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/InterLineGuess.cs

@@ -7,8 +7,9 @@ using UnityEngine;
 
 namespace o0.Project
 {
+    // 猜测屏幕内部的线,用于识别屏幕的黑边
     // 大于阈值则猜测是Line,但是这个类不考虑梯度,外部仍需结合梯度评估
-    public class LineGuess
+    public class InterLineGuess
     {
         public static float isLineThreshold = 1.0f;
         // 记录分段的线段数据
@@ -66,7 +67,7 @@ namespace o0.Project
         public float GradientLength;
         public float MinLineLength;
 
-        public LineGuess(List<Matrix> screenLocateMatList, float gradientLength, float minLineLength)
+        public InterLineGuess(List<Matrix> screenLocateMatList, float gradientLength, float minLineLength)
         {
             ScreenLocateMatList = screenLocateMatList;
             GradientLength = gradientLength;

+ 0 - 0
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/LineGuess.cs.meta → Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/InterLineGuess.cs.meta


+ 10 - 0
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/LineIdentify/LineIdentified.cs

@@ -46,6 +46,16 @@ namespace o0.Project
                 DrawLine = lineParams.line;
         }
 
+        bool? _isInterLine;
+        // 评估是否是屏幕内部的线
+        public bool GuessIsInterLine(InterLineGuess guess)
+        {
+            if (_isInterLine == null)
+                _isInterLine = guess.GuessIsLine(this);
+
+            return _isInterLine.Value;
+        }
+
         public void Offset(Vector offset)
         {
             Line += offset;

+ 14 - 9
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs

@@ -985,6 +985,8 @@ namespace o0.Project
 
             // 角度阈值,用来判断线段的梯度方向是否指向屏幕中心(avgPoint)
             var avaAngleHalf = 75f;
+            // 评估屏幕内部的Line
+            var interLineGuess = new InterLineGuess(screenLocateMatList, gradientLength * 2, minLength);
 
             #region 内部函数
             float ScreenGrad(LineIdentified line)
@@ -1003,13 +1005,15 @@ namespace o0.Project
                 }
                 return Math.Abs(lg.Mean());
             }
-            // 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以最大距离
+            // 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以距离阈值
             float estimateGradient(LineIdentified line, float distanceRatio)
             {
                 var gM = ScreenGrad(line);
+                if (line.Batch > 0)       // 其他batch的图,梯度权重小
+                    gM /= 3;
                 float e = (float)Math.Sqrt(Math.Ceiling(line.Line.Length / minLength));       // 长度系数,筛选时梯度更大、长度更长的线段更优
-                float d = (1.3f - distanceRatio) / 0.3f;             // 距离系数,距离越近,系数越大
-                line.ZIMGradient = e * d * gM;      // 记录一下综合梯度,新增的识别黑边功能会二次使用
+                float d = (10f - distanceRatio * distanceRatio) / 10f;             // 距离系数,距离越近,系数越大
+                line.ZIMGradient = e * gM + d;      // 记录一下综合梯度,新增的识别黑边功能会二次使用
                 return line.ZIMGradient;
             }
             // 根据线段梯度的角度,判断是不是屏幕的边,index代表是哪条边(顺序是: 下、右、上、左)
@@ -1050,6 +1054,7 @@ namespace o0.Project
                 Debug.Log($"[IdentifyLineLSD] 根据已有定位数据做筛选, QuadManual: {QuadManual}");
                 manualLines = QuadManual.GetLines().Select((i) => new LineIdentified(0, i, 0, 0, true)).ToArray();
                 var calibration = ScreenLocate.Main.ReDoLocateCalibrationRatio * Size.y;
+                var distanceMeasure = 0.02f * Size.y;
                 var avgPointCross = manualLines.Select((i) => i.Line.LineCrossWithPoint(avgPoint)).ToArray();     // 对于平均点的corss值
                 var avgPointPedal = manualLines.Select((i) => o0Extension.PointPedal(i.Line, avgPoint, out _)).ToArray();     // 当前定位的垂足,下、右、上、左
 
@@ -1066,7 +1071,7 @@ namespace o0.Project
                             var middleToOldLine = o0Extension.PointPedal(manualLines[line.ScreenLineIndex].Line, (line.Line.A + line.Line.B) / 2, out bool inLineSegment);
                             if (inLineSegment)
                             {
-                                quadLinesSemiAuto[line.ScreenLineIndex].Add((estimateGradient(line, distanceToOld / calibration), line));
+                                quadLinesSemiAuto[line.ScreenLineIndex].Add((estimateGradient(line, (float)Math.Floor(distanceToOld / distanceMeasure)), line));
                                 possibleLines.Add(line);
                             }
                         }
@@ -1084,7 +1089,7 @@ namespace o0.Project
             }
             // 新增功能(解决黑边问题):根据 result 再找平行线,判断是否替换(1-在 result 内部,且离中点最近,2-接近平行)
             UpdateResultlines(resultSemiAuto, FindInterLinePair(
-                (i) => true,
+                interLineGuess,
                 GetInterSelectableLines(quadLinesSemiAuto, resultSemiAuto, resultSemiAutoPedal, avgPoint)));
 
             #endregion
@@ -1109,7 +1114,7 @@ namespace o0.Project
             }
             // 新增功能(解决黑边问题):根据 resultAuto 再找平行线,判断是否替换(1-在 result 内部,且离中点最近,2-接近平行,3-LineGuess判断是直线)
             UpdateResultlines(resultAuto, FindInterLinePair(
-                new LineGuess(screenLocateMatList, gradientLength * 2, minLength).GuessIsLine,
+                interLineGuess,
                 GetInterSelectableLines(quadLinesAuto, resultAuto, resultAutoPedal, avgPoint)));
             #endregion
 
@@ -1123,7 +1128,7 @@ namespace o0.Project
             {
                 foreach (var (_, line) in ql)
                 {
-                    if (line != resultLines[line.ScreenLineIndex])
+                    if (line != resultLines[line.ScreenLineIndex] && line.Batch < 1) // batch0才做黑边的内部线条检测
                     {
                         var pedal = o0Extension.PointPedal(line.Line, avgPoint, out _);
                         var a0 = pedal - avgPoint;
@@ -1151,7 +1156,7 @@ namespace o0.Project
                 result[inter.b.ScreenLineIndex] = inter.b;
         }
 
-        (LineIdentified a, LineIdentified b) FindInterLinePair(Func<LineIdentified, bool> guessIsLine, List<LineIdentified> interSelectable, int maxCountToSelect = 8)
+        (LineIdentified a, LineIdentified b) FindInterLinePair(InterLineGuess lineGuess, List<LineIdentified> interSelectable, int maxCountToSelect = 8)
         {
             Debug.Log("[ScreenIdentification] selectable inter line count: " + interSelectable.Count);
             interSelectable.Sort((a, b) => b.ZIMGradient.CompareTo(a.ZIMGradient));
@@ -1159,7 +1164,7 @@ namespace o0.Project
             LineIdentified[] selected = new LineIdentified[4];
             foreach (var line in interSelectable)
             {
-                if (guessIsLine(line))        // 评价是不是Line, 并且找到离中心点最近的
+                if (line.GuessIsInterLine(lineGuess))        // 评价是不是Line, 并且找到离中心点最近的
                 {
                     if (ScreenLocate.Main.DebugOnZIMDemo)
                         Debug.Log($"[ScreenIdentification] {interSelectable.IndexOf(line)}, guess is line: (index)" + line.ScreenLineIndex);

+ 2 - 2
Assets/InfraredProject/WebCamera/Script/ZIM/ScreenLocate.cs

@@ -950,8 +950,8 @@ public partial class ScreenLocate : MonoBehaviour
     // threshold 的值是0-1,0代表最近,1代表最远
     public void SetReDoLocateCalibrationRatio(float threshold)
     {
-        const float MIN = 0.005f;
-        const float MAX = 0.305f;
+        const float MIN = 0.02f;
+        const float MAX = 0.32f;
         ReDoLocateCalibrationRatio = MIN + (MAX - MIN) * threshold;
     }
 

Datei-Diff unterdrückt, da er zu groß ist
+ 657 - 94
Assets/SmartBow/Resources/SmartBow/Prefabs/Views/Home/InfraredScreenPositioningView.prefab


+ 119 - 4
Assets/SmartBow/Resources/SmartBow/Prefabs/ZIM/LineGenerator.cs

@@ -21,6 +21,14 @@ namespace ZIM
         [Tooltip("是否每次绘制两点之间的线段")]
         public bool DrawTwoPointsAtATime = false;
 
+        //控制扇形角绘制
+        [Header("扇形角绘制")]
+        [SerializeField] private bool bDrawFan = false;
+        [SerializeField] private Color fanColor = Color.white;
+        [SerializeField] private int fanSegments = 20; // 扇形的平滑度
+        [SerializeField] private float fanOuterRadius = 150f; // 扇形的半径
+        private float fanInnerRadius = 0f;
+
         [SerializeField]
         private Vector2[] _points;
         /// <summary>
@@ -88,6 +96,7 @@ namespace ZIM
                         DrawLine(vh, start, end, LineThickness);
                     }
                 }
+
             }
             else
             {
@@ -110,6 +119,8 @@ namespace ZIM
                     }
                 }
             }
+
+            if (bDrawFan) DrawFansAtCorners(vh);
         }
 
         private void DrawLine(VertexHelper vh, Vector2 start, Vector2 end, float thickness)
@@ -144,10 +155,114 @@ namespace ZIM
                 drawnLength += currentDashLength + gapLength;
             }
         }
-        //void Update()
-        //{
-        //    //SetVerticesDirty();
-        //}
+        /// <summary>
+        /// 1. 计算角度方向:
+        /// 使用 Vector2.Angle 可以得到两个向量之间的夹角大小,但它不能确定角度的方向。为此,我们需要使用 Mathf.Atan2 来计算相对坐标的角度。Atan2 可以返回一个在 -π 到 π 之间的角度值,并且考虑了顺时针和逆时针的方向。
+        /// 2. 从 X 轴正方向为 0 计算角度:
+        /// 将角度计算为相对于 x 轴正方向的角度,并根据 Atan2 结果进行调整。
+        /// </summary>
+        /// <param name="vh"></param>
+        private void DrawFansAtCorners(VertexHelper vh)
+        {
+            List<Vector2> _Points = new List<Vector2>(Points);
+            if (Loop)
+            {
+                _Points.Add(Points[0]);
+                _Points.Add(Points[1]);
+            }
+
+            float width = rectTransform.rect.width / 2;
+            float height = rectTransform.rect.height / 2;
+            float pivotX = rectTransform.pivot.x * rectTransform.rect.width - width;
+            float pivotY = rectTransform.pivot.y * rectTransform.rect.height - height;
+
+            //比如现在是6个点,实际从第二个点开始绘制
+            for (int i = 1; i < _Points.Count - 1; i++)
+            {
+                Vector2 pre = _Points[i - 1];
+                Vector2 start = _Points[i];
+                Vector2 end = _Points[i + 1];
+
+                Vector2 previousPos = new Vector2(pre.x * width - pivotX, pre.y * height - pivotY);
+                Vector2 currentPos = new Vector2(start.x * width - pivotX, start.y * height - pivotY);
+                Vector2 nextPos = new Vector2(end.x * width - pivotX, end.y * height - pivotY);
+
+  
+                // 计算当前点到前一点的方向
+                Vector2 prevDir = (currentPos - previousPos).normalized;
+                // 计算当前点到下一点的方向
+                Vector2 currentDir = (nextPos - currentPos).normalized;
+
+                // 使用 Atan2 计算方向相对于 x 轴的角度
+                float prevAngle = Mathf.Atan2(prevDir.y, prevDir.x) * Mathf.Rad2Deg; // 前一个方向相对于 x 轴的角度
+                float currentAngle = Mathf.Atan2(currentDir.y, currentDir.x) * Mathf.Rad2Deg; // 当前方向相对于 x 轴的角度
+
+                // 计算两个方向之间的角度差
+                float angleBetween = Vector2.Angle(prevDir, currentDir);
+
+                // 判断旋转方向
+                float cross = prevDir.x * currentDir.y - prevDir.y * currentDir.x;
+                if (cross < 0)
+                {
+                    // 逆时针旋转
+                    angleBetween = 360f - angleBetween;
+                }
+
+                // 内角的计算(补充180度)
+                float innerAngle = 180f - angleBetween;
+
+                // 计算开始角度,这里用的是 x 轴为起始点来计算
+                float startAngle = currentAngle;
+
+                //Debug.Log($"Index {i}: startAngle = {startAngle}, innerAngle = {innerAngle}");
+
+                // 根据当前角的位置调整内角和起始角
+                DrawFanAtCorner(vh, currentPos, startAngle, innerAngle, fanInnerRadius, fanOuterRadius, fanSegments, fanColor);
+
+            }
+        }
+        private void DrawFanAtCorner(VertexHelper vh, Vector2 center, float startAngle, float angleDegree, float innerRadius, float outerRadius, int segments, Color color)
+        {
+            UIVertex vert = UIVertex.simpleVert;
+            vert.color = color;
+
+            float angleRad = Mathf.Deg2Rad * angleDegree;        // 将绘制角度转换为弧度
+            float startAngleRad = Mathf.Deg2Rad * startAngle;    // 将起始角度转换为弧度
+            float angleStep = angleRad / segments;               // 每个扇形段的角度步长
+
+            int initialVertCount = vh.currentVertCount;          // 记录当前顶点数量
+
+            // 添加中心点顶点
+            vert.position = center;
+            vert.uv0 = new Vector2(0.5f, 0.5f);                  // 中心UV值
+            vh.AddVert(vert);
+
+            // 绘制外圈和内圈的顶点
+            for (int i = 0; i <= segments; i++)
+            {
+                float currentAngle = startAngleRad + i * angleStep;
+                float cosA = Mathf.Cos(currentAngle);
+                float sinA = Mathf.Sin(currentAngle);
+
+                // 外圈顶点
+                vert.position = center + new Vector2(cosA * outerRadius, sinA * outerRadius);
+                vert.uv0 = new Vector2(0.5f + cosA * 0.5f, 0.5f + sinA * 0.5f);
+                vh.AddVert(vert);
+
+                // 内圈顶点
+                vert.position = center + new Vector2(cosA * innerRadius, sinA * innerRadius);
+                vert.uv0 = new Vector2(0.5f + cosA * innerRadius / outerRadius * 0.5f, 0.5f + sinA * innerRadius / outerRadius * 0.5f);
+                vh.AddVert(vert);
+            }
+
+            // 创建三角形索引来绘制扇形
+            for (int i = 1; i <= segments; i++)
+            {
+                int baseIndex = initialVertCount + (i - 1) * 2;
+                vh.AddTriangle(initialVertCount, baseIndex + 1, baseIndex + 3);  // 中心点连接外圈
+                vh.AddTriangle(baseIndex + 1, baseIndex + 2, baseIndex + 3);    // 内圈连接外圈
+            }
+        }
 
     }
 }

+ 143 - 22
Assets/SmartBow/Scripts/Views/InfraredViewParts/InfraredScreenPositioningView.cs

@@ -18,6 +18,7 @@ public enum ScreenPositioningStep {
   Start,//开始界面
   AutoEnd,//自动定位结束后界面
   Marker,//进行标记界面
+  Manual,//手动界面
   LightCtrl,//灯光调整界面
   Successful,//结果选择界面
 }
@@ -108,6 +109,14 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     [Header("AutoEnd Layout Group")]
     [SerializeField]
     GameObject LayoutAutoEnd;
+
+    [Header("LightCtrl Layout Group")]
+    [SerializeField]
+    GameObject LayoutLightCtrl;
+    [SerializeField] Slider sliderContrast;
+    //亮度
+    [SerializeField] Slider sliderBrightness;
+
     [Header("Marker Layout Group")]
     [SerializeField]
     GameObject LayoutMarker;
@@ -115,13 +124,17 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     RectTransform crosshairSmall;
     [Tooltip("标记页面标题提示")]
     [SerializeField] TextAutoLanguage2 markerTextAutoLanguage2;
+    [SerializeField]
+    RectTransform markerPointsParent;
+    [SerializeField]
+    List<RectTransform> markerPosList;
+    [SerializeField]
+    Line markerPointsLine;
 
-    [Header("LightCtrl Layout Group")]
+    [Header("Manual Layout Group")]
     [SerializeField]
-    GameObject LayoutLightCtrl;
-    [SerializeField] Slider sliderContrast;
-    //亮度
-    [SerializeField] Slider sliderBrightness;
+    GameObject LayoutManual;
+
 
     [Header("Successful Layout Group")]
     [SerializeField]
@@ -143,7 +156,8 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     RawImage CameraSecondImage; //第二个结果屏幕
     [SerializeField] LineGenerator FirstUILineGenerator;//第一个结果屏幕线条
     [SerializeField] LineGenerator SecondUILineGenerator;//第二个结果屏幕线条
-
+    bool bMarkerFinish = false;
+    ScreenPositioningStep perStepView = ScreenPositioningStep.None;//最后一次进入LayoutSuccessful的页面
 
     //标记当前页面情况
     ScreenPositioningStep curStepView = ScreenPositioningStep.Start;//设置一个开始页面 
@@ -261,7 +275,11 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
 
 
 
-            offset = line.MyThickness = infraredDemo.lineWidth.Get();
+            offset = line.MyThickness = markerPointsLine.MyThickness  = infraredDemo.lineWidth.Get();
+            //LineGenerator 比 line 宽少了大概2倍 
+            CurrentUILineGenerator.LineThickness = infraredDemo.lineWidth.Get() * 2;
+            //扇形宽
+            markerPointsLine.MyFanWidth = line.MyFanWidth = infraredDemo.fanWidth.Get();
 
 
             ZIM.Unity.QuadrilateralInCamera screen = ScreenLocate.Main.ScreenIdentification.Screen.QuadInCamera;
@@ -446,20 +464,34 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
                 pointsParent.gameObject.SetActive(false);
                 CurrentUILineGenerator.enabled = true;
                 break;
+            case ScreenPositioningStep.LightCtrl:
+                maskLine.SetDrawMask(false);
+                LayoutLightCtrl.SetActive(true);
+                CurrentUILineGenerator.enabled = true;
+                pointsParent.gameObject.SetActive(false);
+                //setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true);
+                break;
             case ScreenPositioningStep.Marker:
+                perStepView = ScreenPositioningStep.Marker;
+                bMarkerFinish = false;
                 maskLine.SetDrawMask(true);
                 LayoutMarker.SetActive(true);
                 CurrentUILineGenerator.enabled = false;
                 pointsParent.gameObject.SetActive(false);
-                setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true);
+                SyncQuadUnityVectorListToMarkerPointesPos();
+                //setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true);
                 break;
-            case ScreenPositioningStep.LightCtrl:
-                maskLine.SetDrawMask(false);
-                LayoutLightCtrl.SetActive(true);
-                CurrentUILineGenerator.enabled = false;
-                pointsParent.gameObject.SetActive(true);
-                setPointsLocation(ScreenLocate.quadUnityVectorList, pointsParent.gameObject, true);
+            case ScreenPositioningStep.Manual:
+                SaveStartOldLinePosition();
+                perStepView = ScreenPositioningStep.Manual;
+                bMarkerFinish = false;
+                LayoutManual.SetActive(true);
+                bAuto = false;
+                doLocateAuto = false;
+                draggableParent.gameObject.SetActive(true);
+                pointsParent.gameObject.SetActive(false);
                 break;
+         
             case ScreenPositioningStep.Successful:
                 LayoutSuccessful.SetActive(true);
                 pointsParent.gameObject.SetActive(false);
@@ -472,6 +504,7 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     {
         LayoutStart.SetActive(false);
         LayoutMarker.SetActive(false);
+        LayoutManual.SetActive(false);
         LayoutAutoEnd.SetActive(false);
         LayoutLightCtrl.SetActive(false);
         LayoutSuccessful.SetActive(false);
@@ -507,8 +540,13 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     /// </summary>
     public void OnClick_BackLayoutStart()
     {
-        //返回上一步操作
-        infraredDemo.RevokeCenterOffset();
+        //重置中心点0
+        infraredDemo.ResetCenterOffset();
+        //清除白线数据
+        infraredDemo.ResetPositioningData();
+        //上面应该清空了 ScreenLocate.Main.ScreenIdentification.QuadAuto
+        onClearCurrentUILineGenerator();
+
         SetScreenPositioningStepState(ScreenPositioningStep.Start);
     }
     /// <summary>
@@ -524,6 +562,20 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     public void OnClick_EnterMarker() {
         SetScreenPositioningStepState(ScreenPositioningStep.Marker);
     }
+
+    /// <summary>
+    /// successful 返回页面时候,根据ScreenPositioningStep区分
+    /// </summary>
+    public void OnClick_BackByScreenPositioningStep()
+    {
+        SetScreenPositioningStepState(ScreenPositioningStep.LightCtrl);
+        //清空两个绘制线
+        onClearSuccessfullLineGenerator();
+        //if(perStepView == ScreenPositioningStep.Manual)
+        //    SetScreenPositioningStepState(ScreenPositioningStep.Manual);
+        //else
+        //    SetScreenPositioningStepState(ScreenPositioningStep.Marker);
+    }
     /// <summary>
     /// 直接进入游戏流程
     /// </summary>
@@ -537,6 +589,7 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     /// </summary>
     public void OnClick_EnterAuto()
     {
+        Debug.LogError("OnClick_EnterAuto");
         //自动按钮时候进入之前的校准流程
         //重置偏移量
         infraredDemo.ResetCenterOffset();
@@ -572,7 +625,13 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
 
      
     }
-
+    /// <summary>
+    /// 进入手动界面
+    /// </summary>
+    public void OnClick_EnterManual()
+    {
+        SetScreenPositioningStepState(ScreenPositioningStep.Manual);
+    }
     /// <summary>
     /// 切换成手动方式
     /// </summary>
@@ -596,13 +655,15 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
         Debug.Log("texSize:" + texSize + " = " + canvasRectTransform.rect);
         SyncQuadUnityVectorListToPos();
         SetRectanglePoints(linePosConversion(pos1.localPosition, pos2.localPosition, pos3.localPosition, pos4.localPosition));
+        SyncQuadUnityVectorListToMarkerPointesPos();
+
         if (curStepView == ScreenPositioningStep.Start || curStepView == ScreenPositioningStep.AutoEnd) {
             //如果是开始页面进行自动定位的
             if(curStepView != ScreenPositioningStep.AutoEnd) SetScreenPositioningStepState(ScreenPositioningStep.AutoEnd);
         }
-        else if (curStepView == ScreenPositioningStep.Marker) {
+        else if (curStepView == ScreenPositioningStep.Marker || curStepView == ScreenPositioningStep.Manual) {
             //显示最后结果
-            SetScreenPositioningStepState(ScreenPositioningStep.Successful);
+            if(bMarkerFinish) SetScreenPositioningStepState(ScreenPositioningStep.Successful);
         }
         //屏幕变化情况下。同步修改对应的line
         //设置两个线段
@@ -628,7 +689,20 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
             Debug.LogError("screenSemiAuto 不存在!");
         }
     }
-
+    /// <summary>
+    /// 清空白线数据
+    /// </summary>
+    void onClearCurrentUILineGenerator() {
+        if (CurrentUILineGenerator.Points.Length != 0) CurrentUILineGenerator.Points = new Vector2[0];//System.Array.Clear(CurrentUILineGenerator.Points, 0, CurrentUILineGenerator.Points.Length);
+    }
+    /// <summary>
+    /// 清空最后识别的两个自动和半自动数据线
+    /// </summary>
+    void onClearSuccessfullLineGenerator()
+    {
+        if(FirstUILineGenerator.Points.Length !=0) FirstUILineGenerator.Points = new Vector2[0]; //System.Array.Clear(FirstUILineGenerator.Points, 0, FirstUILineGenerator.Points.Length);
+        if (SecondUILineGenerator.Points.Length !=0) SecondUILineGenerator.Points = new Vector2[0];  //System.Array.Clear(SecondUILineGenerator.Points, 0, SecondUILineGenerator.Points.Length);
+    }
     #region 绘制线段部分
 
 
@@ -690,6 +764,22 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
         linePosition.pos = screenPositions;
         oldLinePosition.Add(linePosition);
     }
+    /// <summary>
+    /// 记录一个开始位置
+    /// </summary>
+    void SaveStartOldLinePosition() {
+        oldLinePosition.Clear();
+        //记录一个操作点的操作位置
+        List<Vector3> screenPositions = new List<Vector3>();
+        screenPositions.Add(pos1.localPosition);
+        screenPositions.Add(pos2.localPosition);
+        screenPositions.Add(pos3.localPosition);
+        screenPositions.Add(pos4.localPosition);
+        LinePosition linePosition = new LinePosition();
+        linePosition.index = 1;
+        linePosition.pos = screenPositions;
+        oldLinePosition.Add(linePosition);
+    }
 
     //转换绘制线段的点
     List<Vector2> linePosConversion(Vector3 _pos1, Vector3 _pos2, Vector3 _pos3, Vector3 _pos4)
@@ -770,9 +860,9 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
 
         if (oldLinePosition.Count > 1) // 确保列表不为空
         {
-            LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1];
+            //LinePosition lastElement = oldLinePosition[oldLinePosition.Count - 1];
             oldLinePosition.Clear();
-            oldLinePosition.Add(lastElement);
+            //oldLinePosition.Add(lastElement);
         }
 
         if (InfraredDemo.running)
@@ -860,6 +950,7 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
         //再记录一次最后的点
         SetLinePos();
     }
+
     /// <summary>
     ///  处理新流程,先记录手动,然后到自动识别处理
     /// </summary>
@@ -903,6 +994,13 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
         //自动校准
         InfraredDemo.infraredCameraHelper.EnterScreenLocateManualAuto();
     }
+    /// <summary>
+    /// PointMarker 调用
+    /// </summary>
+    public void onFinishManualToAutomatic() {
+        bMarkerFinish = true;
+        onManualToAutomatic();
+    }
 
     #endregion
 
@@ -1509,4 +1607,27 @@ public class InfraredScreenPositioningView : JCUnityLib.ViewBase
     }
 
     #endregion
+
+
+
+
+    #region marker line 部分渲染
+    /// <summary>
+    /// maker 界面渲染
+    /// </summary>
+    void SyncQuadUnityVectorListToMarkerPointesPos()
+    {
+        Debug.Log("[ScreenLocate] SyncQuadUnityVectorListToMarkerPointesPos quadUnityVectorList:" + ScreenLocate.Main.PrintVector2List(ScreenLocate.quadUnityVectorList));
+        markerPosList[0].anchoredPosition = ScreenLocate.quadUnityVectorList[0].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect);
+        markerPosList[1].anchoredPosition = ScreenLocate.quadUnityVectorList[1].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect);
+        markerPosList[2].anchoredPosition = ScreenLocate.quadUnityVectorList[3].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect);
+        markerPosList[3].anchoredPosition = ScreenLocate.quadUnityVectorList[2].pixelToLocalPosition_AnchorCenter(Vector2.one, canvasRectTransform.rect);
+
+        SetMarkerRectanglePoints(linePosConversion(markerPosList[0].localPosition, markerPosList[1].localPosition, markerPosList[2].localPosition, markerPosList[3].localPosition));
+    }
+    void SetMarkerRectanglePoints(List<Vector2> screenPositions)
+    {
+        markerPointsLine.SetLine(screenPositions);
+    }
+    #endregion
 }

+ 252 - 5
Assets/SmartBow/Scripts/Views/InfraredViewParts/Line.cs

@@ -4,25 +4,63 @@ using UnityEngine.UI;
 
 namespace LineUI
 {
+    // 定义 ArrowInfo 类
+    public class ArrowInfo
+    {
+        public Vector2 Position { get; set; }
+        public Vector2 Direction { get; set; }
+
+        public ArrowInfo(Vector2 position, Vector2 direction)
+        {
+            Position = position;
+            Direction = direction;
+        }
+    }
+
     [RequireComponent(typeof(CanvasRenderer))]
     [RequireComponent(typeof(RectTransform))]
     public class Line : Graphic
     {
+        [Header("绘制线段")]
         [SerializeField] private bool loop = false;
         [SerializeField] private float thickness = 1f;
         [SerializeField] private int roundCount = 0;
-        [SerializeField] private Vector2 quadrilateralSize = new Vector2(100, 100);
-        [SerializeField] private Color quadColor = Color.red;
         [SerializeField] private List<Vector2> screenPositions = new List<Vector2>();
         //获取当前的points
         [HideInInspector]
         public List<Vector2> ScreenPositions => screenPositions;
 
-        [SerializeField] private Color maskColor = Color.red;
+        [Header("绘制内四边形")]
         //是否绘制内四边形
         [SerializeField] bool bDrawQuad = true;
+        [SerializeField] private Vector2 quadrilateralSize = new Vector2(100, 100);
+        [SerializeField] private Color quadColor = Color.red;
+
+        [Header("绘制外围蒙板")]
         //是否绘制外围蒙板
         [SerializeField] bool bDrawMask = false;
+        [SerializeField] private Color maskColor = Color.red;
+        //控制扇形角绘制
+        [Header("扇形角绘制")]
+        [SerializeField] private bool bDrawFan = false; 
+        [SerializeField] private Color fanColor = Color.white;
+        [SerializeField] private int  fanSegments = 20; // 扇形的平滑度
+        [SerializeField] private float fanOuterRadius = 150f; // 扇形的半径
+        private float fanInnerRadius = 0f;
+
+        [Tooltip("扇形指向箭头")]
+        [SerializeField] private bool bDrawArrow = false;
+        [SerializeField] private Color arrowColor = Color.white;
+        [SerializeField] float arrowLength = 50f;
+        [SerializeField] float arrowWidth = 50f; 
+        [SerializeField] float arrowHeadHeight = 30f;
+        [SerializeField] float arrowDis = 100f;
+
+        private List<ArrowInfo> arrowInfos = new List<ArrowInfo>();
+        //获取当前的points
+        [HideInInspector]
+        public List<ArrowInfo> ArrowInfos => arrowInfos;
+
         //[SerializeField] private Color quadTextColor = Color.black;
         //[SerializeField] private int quadFontSize = 14;
 
@@ -41,12 +79,23 @@ namespace LineUI
             get => thickness;
             set
             {
-                if (value >= 10)
+                if (value >= 1)
                 {
                     thickness = value;
                 }
             }
         }
+        public float MyFanWidth
+        {
+            get => fanOuterRadius;
+            set
+            {
+                if (value >= 1)
+                {
+                    fanOuterRadius = value;
+                }
+            }
+        }
 
         public void SetLine(List<Vector2> screenPositions)
         {
@@ -63,9 +112,17 @@ namespace LineUI
             bDrawMask = value;
             SetVerticesDirty();
         }
+
+        public void SetDrawFan(bool value)
+        {
+            bDrawFan = value;
+            SetVerticesDirty();
+        }
+
         protected override void OnPopulateMesh(VertexHelper vh)
         {
             vh.Clear();
+            arrowInfos.Clear();
             //quadsToDraw.Clear();
             //quadTextToDraw.Clear();
 
@@ -79,6 +136,8 @@ namespace LineUI
             if(bDrawQuad) SetQuadrilateralVertices(vh);
 
             if(bDrawMask) DrawMask(vh); // 绘制蒙版
+
+            if (bDrawFan) DrawFansAtCorners(vh); // 在转折角绘制扇形
         }
 
         private void SetLineVertices(VertexHelper vh)
@@ -261,11 +320,199 @@ namespace LineUI
             vert.position = corner4;
             vh.AddVert(vert);
 
-            Debug.Log("vh.currentVertCount:"+ vh.currentVertCount);
+            //Debug.Log("vh.currentVertCount:"+ vh.currentVertCount);
             int startIndex = vh.currentVertCount - 4;
             vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
             vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
         }
+        /// <summary>
+        /// 1. 计算角度方向:
+        /// 使用 Vector2.Angle 可以得到两个向量之间的夹角大小,但它不能确定角度的方向。为此,我们需要使用 Mathf.Atan2 来计算相对坐标的角度。Atan2 可以返回一个在 -π 到 π 之间的角度值,并且考虑了顺时针和逆时针的方向。
+        /// 2. 从 X 轴正方向为 0 计算角度:
+        /// 将角度计算为相对于 x 轴正方向的角度,并根据 Atan2 结果进行调整。
+        /// </summary>
+        /// <param name="vh"></param>
+        private void DrawFansAtCorners(VertexHelper vh)
+        {
+            List<Vector2> _screenPositions = new List<Vector2>(screenPositions);
+            if (loop)
+            {
+                _screenPositions.Add(screenPositions[0]);
+                _screenPositions.Add(screenPositions[1]);
+            }
+            //比如现在是6个点,实际从第二个点开始绘制
+            for (int i = 1; i < _screenPositions.Count - 1; i++)
+            {
+                Vector2 previousPos = _screenPositions[i - 1];
+                Vector2 currentPos = _screenPositions[i];
+                Vector2 nextPos = _screenPositions[i + 1];
+
+                // 计算当前点到前一点的方向
+                Vector2 prevDir = (currentPos - previousPos).normalized;
+                // 计算当前点到下一点的方向
+                Vector2 currentDir = (nextPos - currentPos).normalized;
+
+                // 使用 Atan2 计算方向相对于 x 轴的角度
+                float prevAngle = Mathf.Atan2(prevDir.y, prevDir.x) * Mathf.Rad2Deg; // 前一个方向相对于 x 轴的角度
+                float currentAngle = Mathf.Atan2(currentDir.y, currentDir.x) * Mathf.Rad2Deg; // 当前方向相对于 x 轴的角度
+
+                // 计算两个方向之间的角度差
+                float angleBetween = Vector2.Angle(prevDir, currentDir);
+
+                // 判断旋转方向
+                float cross = prevDir.x * currentDir.y - prevDir.y * currentDir.x;
+                if (cross < 0)
+                {
+                    // 逆时针旋转
+                    angleBetween = 360f - angleBetween;
+                }
+
+                // 内角的计算(补充180度)
+                float innerAngle = 180f - angleBetween;
+
+                // 计算开始角度,这里用的是 x 轴为起始点来计算
+                float startAngle = currentAngle;
+
+                //Debug.Log($"Index {i}: startAngle = {startAngle}, innerAngle = {innerAngle}");
+
+                // 根据当前角的位置调整内角和起始角
+                DrawFanAtCorner(vh, currentPos, startAngle, innerAngle, fanInnerRadius, fanOuterRadius, fanSegments, fanColor);
+
+
+                // 计算箭头的中心角度,确保角度在 0-360° 范围内
+                float centerAngle = (startAngle + innerAngle / 2) % 360f;
+                float radians = Mathf.Deg2Rad * centerAngle;
+
+                // 计算箭头位置:在扇形外半径的基础上延长一定距离(箭头偏移量)
+                float arrowOffset = fanOuterRadius + arrowDis;
+                Vector2 arrowPosition = currentPos + new Vector2(Mathf.Cos(radians), Mathf.Sin(radians)) * arrowOffset;
+
+                // 箭头方向
+                Vector2 arrowDirection = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians)).normalized;
+
+                // 将箭头信息保存到列表中
+                arrowInfos.Add(new ArrowInfo(arrowPosition, arrowDirection));
+
+                // 在所有扇形处绘制箭头
+                // 在扇形中心绘制箭头
+                if (bDrawArrow)
+                {
+                    // 调试信息
+                    //Debug.Log($"Index {i}: arrowPosition = {arrowPosition}, startAngle = {startAngle}, centerAngle = {centerAngle}, direction = {arrowDirection}");
+                    // 绘制箭头
+                    DrawArrow(vh, arrowPosition, arrowDirection, arrowLength, arrowWidth, arrowHeadHeight);
+                }
+
+
+            }
+        } 
+        private void DrawFanAtCorner(VertexHelper vh, Vector2 center, float startAngle, float angleDegree, float innerRadius, float outerRadius, int segments ,Color color)
+        {
+            UIVertex vert = UIVertex.simpleVert;
+            vert.color = color;
+
+            float angleRad = Mathf.Deg2Rad * angleDegree;        // 将绘制角度转换为弧度
+            float startAngleRad = Mathf.Deg2Rad * startAngle;    // 将起始角度转换为弧度
+            float angleStep = angleRad / segments;               // 每个扇形段的角度步长
+
+            int initialVertCount = vh.currentVertCount;          // 记录当前顶点数量
+
+            // 添加中心点顶点
+            vert.position = center;
+            vert.uv0 = new Vector2(0.5f, 0.5f);                  // 中心UV值
+            vh.AddVert(vert);
+
+            // 绘制外圈和内圈的顶点
+            for (int i = 0; i <= segments; i++)
+            {
+                float currentAngle = startAngleRad + i * angleStep;
+                float cosA = Mathf.Cos(currentAngle);
+                float sinA = Mathf.Sin(currentAngle);
+
+                // 外圈顶点
+                vert.position = center + new Vector2(cosA * outerRadius, sinA * outerRadius);
+                vert.uv0 = new Vector2(0.5f + cosA * 0.5f, 0.5f + sinA * 0.5f);
+                vh.AddVert(vert);
+
+                // 内圈顶点
+                vert.position = center + new Vector2(cosA * innerRadius, sinA * innerRadius);
+                vert.uv0 = new Vector2(0.5f + cosA * innerRadius / outerRadius * 0.5f, 0.5f + sinA * innerRadius / outerRadius * 0.5f);
+                vh.AddVert(vert);
+            }
+
+            // 创建三角形索引来绘制扇形
+            for (int i = 1; i <= segments; i++)
+            {
+                int baseIndex = initialVertCount + (i - 1) * 2;
+                vh.AddTriangle(initialVertCount, baseIndex + 1, baseIndex + 3);  // 中心点连接外圈
+                vh.AddTriangle(baseIndex + 1, baseIndex + 2, baseIndex + 3);    // 内圈连接外圈
+            }
+        }
+
+        // 新增箭头绘制方法
+        private void DrawArrow(VertexHelper vh, Vector2 position, Vector2 direction, float arrowLength, float arrowWidth, float arrowHeadHeight)
+        {
+            // 标准化方向向量
+            direction.Normalize();
+
+            // 反向箭头的方向(箭头指向扇形方向)
+            Vector2 reversedDirection = -direction;
+
+            // 箭头尾部位置
+            Vector2 basePosition = position - reversedDirection * arrowLength;
+
+            // 计算垂直向量用于箭头宽度
+            Vector2 perpendicular = new Vector2(-reversedDirection.y, reversedDirection.x);
+
+            // 让箭头矩形部分的宽度比三角形的底边窄
+            float adjustedArrowWidth = arrowWidth * 0.6f;  // 调整宽度,使矩形比三角形窄
+
+            // 箭头矩形部分的四个顶点
+            Vector2 baseLeft = basePosition + perpendicular * (adjustedArrowWidth / 2);
+            Vector2 baseRight = basePosition - perpendicular * (adjustedArrowWidth / 2);
+            Vector2 headLeft = position + perpendicular * (adjustedArrowWidth / 2);
+            Vector2 headRight = position - perpendicular * (adjustedArrowWidth / 2);
+
+            Vector2 triangleHeadLeft = position + perpendicular * (arrowHeadHeight / 2);
+            Vector2 triangleHeadRight = position - perpendicular * (arrowHeadHeight / 2);
+
+            // 顶点颜色
+            UIVertex vert = UIVertex.simpleVert;
+            vert.color = arrowColor; 
+
+            // 先添加矩形部分的顶点
+            int rectStartIndex = vh.currentVertCount;
+            vert.position = baseLeft;
+            vh.AddVert(vert);
+            vert.position = baseRight;
+            vh.AddVert(vert);
+            vert.position = headLeft;
+            vh.AddVert(vert);
+            vert.position = headRight;
+            vh.AddVert(vert);
+
+            // 添加矩形部分的两条三角形索引
+            vh.AddTriangle(rectStartIndex, rectStartIndex + 1, rectStartIndex + 2);
+            vh.AddTriangle(rectStartIndex + 1, rectStartIndex + 3, rectStartIndex + 2);
+
+            // 然后添加三角形头部的顶点
+            Vector2 headPosition = position + reversedDirection * arrowHeadHeight;
+            int headStartIndex = vh.currentVertCount;
+
+            vert.position = triangleHeadLeft;
+            vh.AddVert(vert);
+            vert.position = triangleHeadRight;
+            vh.AddVert(vert);
+            vert.position = headPosition;  // 添加箭头尖端
+            vh.AddVert(vert);
+
+            // 添加三角形的索引
+            int triangleStartIndex = vh.currentVertCount - 3; // 三角形部分的开始索引
+            vh.AddTriangle(triangleStartIndex, triangleStartIndex + 1, triangleStartIndex + 2);  // 三角形索引
+        }
+
+
+
 
 
 

+ 7 - 5
Assets/SmartBow/Scripts/Views/InfraredViewParts/PointMarker.cs

@@ -205,10 +205,12 @@ public class PointMarker : MonoBehaviour
     }
 
     void UpdateLine() {
-        RectTransform rectTransform = markerParent as RectTransform;
-        Vector2 pivot = rectTransform.pivot; // 获取父物体的 pivot 值
-        Vector2 texSize = rectTransform.rect.size;
-        line.Points = InfraredDemo._ins.ConvertPointsToCoordinates(markedPoints.ToArray(), texSize, pivot);
+        if (line.gameObject.activeSelf) {
+            RectTransform rectTransform = markerParent as RectTransform;
+            Vector2 pivot = rectTransform.pivot; // 获取父物体的 pivot 值
+            Vector2 texSize = rectTransform.rect.size;
+            line.Points = InfraredDemo._ins.ConvertPointsToCoordinates(markedPoints.ToArray(), texSize, pivot);
+        }
     }
 
     void UpdateInstruction()
@@ -245,7 +247,7 @@ public class PointMarker : MonoBehaviour
             int index = i;
             infraredScreenPositioningView.onManualNewPos(3 - index, markerObjects[index].transform.localPosition);
         }
-        infraredScreenPositioningView.onManualToAutomatic();
+        infraredScreenPositioningView.onFinishManualToAutomatic();
 
         ////清空数据
         //currentPointIndex = 0;

BIN
Assets/SmartBow/Textures/Guidance/Infrared/FrameLine2.png


+ 123 - 0
Assets/SmartBow/Textures/Guidance/Infrared/FrameLine2.png.meta

@@ -0,0 +1,123 @@
+fileFormatVersion: 2
+guid: 7bb7a87e467972c49a9021fa28ed5b41
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  ignoreMasterTextureLimit: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  cookieLightType: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Android
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.