Prechádzať zdrojové kódy

3/9更新

2025/3/5 添加部分加载后台狗的数据功能(数据依然存在错误,待完善)
添加Home场景同时显示3只狗的问题。但是存在严重的穿模问题。可能方案1,给3只狗限定范围。
修改Playground狗的动画问题。
2025/3/7 完善创建狗的代码
修复Home场景下狗的移动范围和切换全景相机
修复Home场景狗移动速度(距离目标接近后回减速)
2025/3/8 完成注册用户的代码。待测试验证。
增加状态页面显示多只狗的功能。
2025/3/9 初步添加狗碰撞检测功能。
添加狗吃食物的功能。
添加吃食物喝水后后台通讯功能。(待后台验证)
Jees 4 mesiacov pred
rodič
commit
97701f97f3
28 zmenil súbory, kde vykonal 874 pridanie a 203 odobranie
  1. 28 4
      Assets/Resources/Data/languages.json
  2. 6 6
      Assets/Resources/Dog/AnimatorController/shibaInu/HomeDogAnimatorController.controller
  3. 4 4
      Assets/Resources/Dog/AnimatorController/shibaInu/PlaygroundDogBehavior.controller
  4. 7 7
      Assets/Resources/MessageBox/MessageBox.prefab
  5. 54 19
      Assets/Resources/Status/StatusController.cs
  6. 5 0
      Assets/Resources/Status/StatusUI.uxml
  7. 36 23
      Assets/Resources/VoiceAndManu/MenuController.cs
  8. 8 0
      Assets/Resources/VoiceAndManu/VoiceController.cs
  9. 122 19
      Assets/Resources/Warehouse/ItemUseController.cs
  10. 3 1
      Assets/Resources/Warehouse/WarehouseController.cs
  11. 106 6
      Assets/Scenes/Home.unity
  12. 17 5
      Assets/Scenes/Login.unity
  13. 3 2
      Assets/Scenes/Playground.unity
  14. 32 9
      Assets/Scripts/Develop Script/TestSetup.cs
  15. 3 1
      Assets/Scripts/EnviromentSetting.cs
  16. 6 0
      Assets/Scripts/Functions/WebController.cs
  17. 26 4
      Assets/Scripts/GameControllers/DogInitialize.cs
  18. 4 2
      Assets/Scripts/GameControllers/DogProperty.cs
  19. 1 1
      Assets/Scripts/GameControllers/GameData.cs
  20. 13 0
      Assets/Scripts/GameControllers/UserProperty.cs
  21. 8 2
      Assets/Scripts/Home/BowlColliderController.cs
  22. 148 57
      Assets/Scripts/Home/HomeController.cs
  23. 84 0
      Assets/Scripts/Home/ItemUseWebCommController.cs
  24. 2 0
      Assets/Scripts/Home/ItemUseWebCommController.cs.meta
  25. 48 10
      Assets/Scripts/Login/InitDogUIController.cs
  26. 19 7
      Assets/Scripts/Login/LoginController.cs
  27. 78 11
      Assets/Scripts/Login/RegisterUIController.cs
  28. 3 3
      Assets/Scripts/Playground/PlayToyController.cs

+ 28 - 4
Assets/Resources/Data/languages.json

@@ -138,6 +138,10 @@
         }
     },
     "game_message": {
+        "network_error":{
+            "en": "Network connection error, please check your network connection.",
+            "zh-cn": "网络连接错误,请检查你的网络连接。"
+        },
         "not_allow_version_IOS":{
             "en": "Your game version is not allowed. Please update in APP store.",
             "zh-cn": "你的游戏版本太低了。请在App Store 更新。"
@@ -158,7 +162,27 @@
             "en": "Login Fail. Please try again.",
             "zh-cn": "登陆失败。请再次尝试。"
         },
-        "no_more_food": {
+        "dog_name_duplicated":{
+            "en": "You already have a dog called <<dog_name>>.",
+            "zh-cn": "你已有有了一只叫做<<dog_name>>的狗了。"
+        },
+        "dog_create_success":{
+            "en": "<<dog_name>> is your good friend now.",
+            "zh-cn": "现在<<dog_name>>是你的好伙伴了。"
+        },
+        "cannot_add_dog":{
+            "en": "You can't have any more dogs. Unless you foster some dogs.",
+            "zh-cn": "你不能再拥有更多的狗了。除非你把一些狗寄养了。"
+        },
+        "reg_reminder":{
+            "en": "Register user information. It can help to retrieve game data in the future.",
+            "zh-cn": "注册一下用户信息。方便以后找回数据。"
+        },
+        "register_success":{
+            "en": "Register Success!",
+            "zh-cn": "注册成功!"
+        },
+        "from here not used. no_more_food": {
             "en": "<dog_name> is full. It doesn't want to eat anymore.",
             "zh-cn": "<dog_name>吃饱了。它不想再吃了。"
         },
@@ -436,9 +460,9 @@
             }
         },
         "error_msg":{
-            "duplicated_user_name":{
-                "en": "* This user name had been used.",
-                "zh-cn": "这个用户名已经被注册了。"
+            "duplicated_mobile":{
+                "en": "* This mobile phone had been used.",
+                "zh-cn": "这个手机号码已经被注册了。"
             },
             "user_name_is_empty":{
                 "en": "* User name is empty.",

+ 6 - 6
Assets/Resources/Dog/AnimatorController/shibaInu/HomeDogAnimatorController.controller

@@ -349,9 +349,9 @@ AnimatorStateTransition:
   m_Mute: 0
   m_IsExit: 0
   serializedVersion: 3
-  m_TransitionDuration: 0.25
-  m_TransitionOffset: 0
-  m_ExitTime: 0.75
+  m_TransitionDuration: 0.9128264
+  m_TransitionOffset: 0.1873528
+  m_ExitTime: 0.114338815
   m_HasExitTime: 1
   m_HasFixedDuration: 1
   m_InterruptionSource: 0
@@ -2304,9 +2304,9 @@ AnimatorStateTransition:
   m_Mute: 0
   m_IsExit: 0
   serializedVersion: 3
-  m_TransitionDuration: 0.25
-  m_TransitionOffset: 0
-  m_ExitTime: 0.7176471
+  m_TransitionDuration: 0.58529466
+  m_TransitionOffset: 0.78666335
+  m_ExitTime: 0
   m_HasExitTime: 1
   m_HasFixedDuration: 1
   m_InterruptionSource: 0

+ 4 - 4
Assets/Resources/Dog/AnimatorController/shibaInu/PlaygroundDogBehavior.controller

@@ -17,9 +17,9 @@ AnimatorStateTransition:
   m_Mute: 0
   m_IsExit: 0
   serializedVersion: 3
-  m_TransitionDuration: 0.25
-  m_TransitionOffset: 0
-  m_ExitTime: 0.5
+  m_TransitionDuration: 0.24999985
+  m_TransitionOffset: 0.8582306
+  m_ExitTime: 0.5000003
   m_HasExitTime: 1
   m_HasFixedDuration: 1
   m_InterruptionSource: 0
@@ -124,7 +124,7 @@ AnimatorState:
   m_MirrorParameterActive: 0
   m_CycleOffsetParameterActive: 0
   m_TimeParameterActive: 0
-  m_Motion: {fileID: -5967951987811087257, guid: 1a349bfe663f8a848a567303e35c613a, type: 3}
+  m_Motion: {fileID: -3372365221567839360, guid: 0faf4e66268a11e4d982d9a0163734ca, type: 3}
   m_Tag: 
   m_SpeedParameter: 
   m_MirrorParameter: 

+ 7 - 7
Assets/Resources/MessageBox/MessageBox.prefab

@@ -249,7 +249,7 @@ RectTransform:
   m_AnchorMin: {x: 0, y: 0}
   m_AnchorMax: {x: 0, y: 0}
   m_AnchoredPosition: {x: 350, y: 80}
-  m_SizeDelta: {x: 300, y: 80}
+  m_SizeDelta: {x: 300, y: 120}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &7955086310878262476
 CanvasRenderer:
@@ -382,7 +382,7 @@ RectTransform:
   m_AnchorMin: {x: 1, y: 0}
   m_AnchorMax: {x: 1, y: 0}
   m_AnchoredPosition: {x: -220, y: 80}
-  m_SizeDelta: {x: 300, y: 80}
+  m_SizeDelta: {x: 300, y: 120}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &2860975958448978396
 CanvasRenderer:
@@ -754,7 +754,7 @@ RectTransform:
   m_AnchorMin: {x: 1, y: 0}
   m_AnchorMax: {x: 1, y: 0}
   m_AnchoredPosition: {x: -350, y: 80}
-  m_SizeDelta: {x: 300, y: 80}
+  m_SizeDelta: {x: 300, y: 120}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &7841729400603993495
 CanvasRenderer:
@@ -889,7 +889,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 1}
   m_AnchorMax: {x: 0.5, y: 1}
   m_AnchoredPosition: {x: 0, y: -100}
-  m_SizeDelta: {x: 1300, y: 600}
+  m_SizeDelta: {x: 1300, y: 700}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5531893192627229921
 CanvasRenderer:
@@ -912,7 +912,7 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_Material: {fileID: 0}
-  m_Color: {r: 1, g: 1, b: 1, a: 0.7058824}
+  m_Color: {r: 0.4509804, g: 0.4509804, b: 0.4509804, a: 0.8235294}
   m_RaycastTarget: 1
   m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
   m_Maskable: 1
@@ -963,8 +963,8 @@ RectTransform:
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0.5, y: 1}
   m_AnchorMax: {x: 0.5, y: 1}
-  m_AnchoredPosition: {x: 99, y: -253}
-  m_SizeDelta: {x: 200, y: 50}
+  m_AnchoredPosition: {x: 99, y: -290}
+  m_SizeDelta: {x: 200, y: 60}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &2649271503232441644
 CanvasRenderer:

+ 54 - 19
Assets/Resources/Status/StatusController.cs

@@ -10,6 +10,7 @@ public class StatusController : MonoBehaviour
 {
     public Button backButton;
     public Label nameLabel, genderLabel, breedLabel, hostLabel, hostnameLabel, ageLabel, ageValueLabel, statusLabel, statusValueLabel;
+    private Label leftArrow, rightArrow;
     DogProperty puppy;
     public VisualElement selectElement;
     // Start is called before the first frame update
@@ -27,23 +28,39 @@ public class StatusController : MonoBehaviour
         statusLabel = root.Q<Label>("status");
         statusValueLabel = root.Q<Label>("statusValue");
         selectElement = root.Q("selectElement");
+        leftArrow = root.Q<Label>("leftArrow");
+        rightArrow = root.Q<Label>("rightArrow");
 
         // 绑定事件
         backButton.clicked += BackBtnClick;
+        leftArrow.RegisterCallback<ClickEvent>(e => LeftArrowClicked(e));
+        rightArrow.RegisterCallback<ClickEvent>(e => RightArrowClicked(e));
+
+        // 箭头是否显示
+        if (UserProperty.dogs.Count > 1)
+        {
+            leftArrow.visible = true;
+            rightArrow.visible = true;
+        }
+
 
-        // todo 目前只有一个狗,以后会添加这里要改
-        puppy = UserProperty.dogs[0];
-        StatusPageUpdate();
-        LabelLanguageSetting();
-        StatusSummary();
     }
 
-    // Update is called once per frame
-    //void Update()
+    //private void Start()
     //{
-
+        
     //}
 
+    // Update is called once per frame
+    void Update()
+    {
+        // 刷新狗的数据
+        puppy = UserProperty.dogs[GameData.focusDog];
+        StatusPageUpdate();
+        LabelLanguageSetting();
+        StatusSummary();
+    }
+
     //void BackPressed()
     //{
     //    if (backButton != null)
@@ -56,7 +73,7 @@ public class StatusController : MonoBehaviour
     void StatusPageUpdate()
     {
         //backButton.clicked += BackPressed;
-        nameLabel.text = puppy.name;
+        nameLabel.text = puppy.dog_name;
         if (puppy.sex == 1) {
             genderLabel.text = "♂";
         }
@@ -72,16 +89,16 @@ public class StatusController : MonoBehaviour
         ageValueLabel.text = ts.Days.ToString();
 
         //根据狗的数量添加选择球
-        int puppyQty = UserProperty.dogs.Count;
-        VisualTreeAsset selectBall = Resources.Load<VisualTreeAsset>("Status/SelectBall");
-        // 这里将VisualTreeAsset转换成VisualElement类型
-        VisualElement uiDocument = selectBall.CloneTree();
-        VisualElement[] selectBalls = new VisualElement[puppyQty];
-        for (int i = 0; i<puppyQty; i++)
-        {
-            selectBalls[i] = uiDocument;
-            selectElement.Add(selectBalls[i]);
-        }
+        //int puppyQty = UserProperty.dogs.Count;
+        //VisualTreeAsset selectBall = Resources.Load<VisualTreeAsset>("Status/SelectBall");
+        //// 这里将VisualTreeAsset转换成VisualElement类型
+        //VisualElement uiDocument = selectBall.CloneTree();
+        //VisualElement[] selectBalls = new VisualElement[puppyQty];
+        //for (int i = 0; i<puppyQty; i++)
+        //{
+        //    selectBalls[i] = uiDocument;
+        //    selectElement.Add(selectBalls[i]);
+        //}
         // todo 设置selectBall颜色对应选择
 
     }
@@ -203,6 +220,23 @@ public class StatusController : MonoBehaviour
         statusValueLabel.text = summary;
     }
 
+    void RightArrowClicked(ClickEvent e)
+    {
+        GameData.focusDog++;
+        if (GameData.focusDog == UserProperty.dogs.Count)
+        {
+            GameData.focusDog = 0;
+        }
+    }
+
+    void LeftArrowClicked(ClickEvent e)
+    {
+        GameData.focusDog--;
+        if (GameData.focusDog == -1)
+        {
+            GameData.focusDog = UserProperty.dogs.Count-1;
+        }
+    }
     void BackBtnClick()
     {
         var uiPlaceholder = GameObject.Find("UI Placeholder");
@@ -214,5 +248,6 @@ public class StatusController : MonoBehaviour
             vamUI.SetActive(true);
         }
     }
+
 }
 

+ 5 - 0
Assets/Resources/Status/StatusUI.uxml

@@ -1,5 +1,6 @@
 <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
     <Style src="project://database/Assets/Resources/Status/StatusStyle.uss?fileID=7433441132597879392&amp;guid=21d236151b567a34aafb4dd11ce02947&amp;type=3#StatusStyle" />
+    <Style src="project://database/Assets/UI%20Toolkit/Style/rootStyle.uss?fileID=7433441132597879392&amp;guid=b30eb17a0ca8bf64087af4e59d565fdd&amp;type=3#rootStyle" />
     <ui:VisualElement name="Basic" class="background" style="background-image: url(&quot;project://database/Assets/Pictures/status%20background.jpg?fileID=2800000&amp;guid=0152cbfe524647a4498a5a7ce74af4a2&amp;type=3#status background&quot;);">
         <ui:Label tabindex="-1" text="&lt;dog name&gt;" parse-escape-sequences="true" display-tooltip-when-elided="true" name="name" class="Labels" style="position: absolute; left: 5px; height: 40px; margin-top: 0; top: 10px; right: auto; align-items: center; justify-content: center; width: 200px;" />
         <ui:Label tabindex="-1" text="&lt;dog gender&gt;" parse-escape-sequences="true" display-tooltip-when-elided="true" name="gender" class="Labels" style="position: absolute; left: 202px; width: auto; height: 40px; right: 5px; margin-top: 0; top: 10px;" />
@@ -12,5 +13,9 @@
         <ui:Label tabindex="-1" text="&lt;To summarize status here&gt;" parse-escape-sequences="true" display-tooltip-when-elided="true" name="statusValue" class="Labels" style="top: 220px; left: 30px; height: auto; width: auto; -unity-text-align: upper-left; right: 93px; border-top-width: 0; border-right-width: 0; border-bottom-width: 0; border-left-width: 0; margin-right: 10px; margin-left: auto; margin-top: auto; margin-bottom: auto;" />
         <ui:Button text="Back" parse-escape-sequences="true" display-tooltip-when-elided="true" name="back" style="position: relative; bottom: -90%; -unity-text-align: middle-center; white-space: nowrap; top: auto; left: auto; background-color: rgba(22, 131, 245, 0.78); border-left-color: rgba(149, 149, 149, 0); border-right-color: rgba(149, 149, 149, 0); border-top-color: rgba(149, 149, 149, 0); border-bottom-color: rgba(149, 149, 149, 0); border-top-left-radius: 8px; border-top-right-radius: 8px; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; width: 100px; height: 30px; -unity-font: resource(&apos;Font/MaoKenZhuYuanTi-MaokenZhuyuanTi-2&apos;); font-size: 16px; color: rgb(255, 255, 255); -unity-font-style: bold; -unity-font-definition: url(&quot;project://database/Assets/Font/MaoKenZhuYuanTi-MaokenZhuyuanTi-2.ttf?fileID=12800000&amp;guid=50a63638b44907e46a3fa871d63b7d39&amp;type=3#MaoKenZhuYuanTi-MaokenZhuyuanTi-2&quot;);" />
         <ui:VisualElement name="selectElement" style="flex-grow: 1; position: absolute; height: 20px; top: 450px; width: auto; background-color: rgba(116, 116, 116, 0.47); border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; align-items: center; align-self: auto; justify-content: flex-start; flex-direction: row;" />
+        <ui:VisualElement name="arrowArea" style="flex-grow: 1; height: auto; min-height: auto; flex-direction: row; justify-content: space-between; align-self: auto; align-content: flex-start; align-items: center; position: absolute; bottom: 20%; width: 90%; visibility: visible; display: flex;">
+            <ui:Label text="⬅" name="leftArrow" class="arrow" style="visibility: visible; -unity-text-outline-color: rgba(22, 131, 245, 0.78); -unity-text-outline-width: 1px;" />
+            <ui:Label text="➡" emoji-fallback-support="false" name="rightArrow" class="arrow" style="visibility: visible; -unity-text-outline-color: rgba(22, 131, 245, 0.78); -unity-text-outline-width: 1px;" />
+        </ui:VisualElement>
     </ui:VisualElement>
 </ui:UXML>

+ 36 - 23
Assets/Resources/VoiceAndManu/MenuController.cs

@@ -7,13 +7,14 @@ using UnityEngine.SceneManagement;
 using UnityEngine.UIElements;
 
 /* 本文件控制游戏右侧的菜单按键逻辑
+ * 左侧的菜单按键逻辑
  */
 
 public class MenuController : MonoBehaviour
 {
     // Start is called once before the first execution of Update after the MonoBehaviour is created
     private VisualElement mainMenu, dogIcon, dogList;
-    private List<VisualElement> subMenus = new();
+    private List<VisualElement> subMenu = new();
     //private bool isSubMenuShow = false;
     private GameObject uiPlaceholder;       // Manu会控制其他子菜单显示和隐藏,因此所有子菜单都必须挂载在UI Placeholder下
     private GameObject vamUI;      // vamUI = Voice and Manu UI; 
@@ -35,17 +36,17 @@ public class MenuController : MonoBehaviour
         var menuArea = root.Q<VisualElement>("menuArea");
         mainMenu = menuArea.Q<VisualElement>("mainMenu");
         var home = menuArea.Q<VisualElement>("home");
-        subMenus.Add(home);
+        subMenu.Add(home);
         var playground = menuArea.Q<VisualElement>("playground");
-        subMenus.Add(playground);
+        subMenu.Add(playground);
         var shop = menuArea.Q<VisualElement>("shop");
-        subMenus.Add(shop);
+        subMenu.Add(shop);
         var warehouse = menuArea.Q<VisualElement>("warehouse");
-        subMenus.Add(warehouse);
+        subMenu.Add(warehouse);
         var cameraBtn = menuArea.Q<VisualElement>("camera");
-        subMenus.Add(cameraBtn);
+        subMenu.Add(cameraBtn);
         var status = menuArea.Q<VisualElement>("status");
-        subMenus.Add(status);
+        subMenu.Add(status);
 
         
 
@@ -77,7 +78,7 @@ public class MenuController : MonoBehaviour
 
     private void OnDisable()
     {
-        subMenus.Clear();       // 因为启动时候调用OnEable数据会被重复加载
+        subMenu.Clear();       // 因为启动时候调用OnEable数据会被重复加载
     }
 
     // Update is called once per frame
@@ -100,7 +101,7 @@ public class MenuController : MonoBehaviour
     // 初始化所有按键的位置
     void InitialSubMenu()
     {
-        foreach (var subMenu in subMenus)
+        foreach (var subMenu in subMenu)
         {
             subMenu.style.left = mainMenu.resolvedStyle.left;
             subMenu.style.top = mainMenu.resolvedStyle.top;
@@ -121,7 +122,7 @@ public class MenuController : MonoBehaviour
         float angleDelta = 40f;
         float distance = 70f;
         //float showTimer = 3.0f;
-        foreach (var subMenu in subMenus)
+        foreach (var subMenu in subMenu)
         {
             subMenu.visible = true;
             var newPosition = CalcPosition(mainMenu.layout.position, curAngle, distance);
@@ -196,6 +197,7 @@ public class MenuController : MonoBehaviour
             }
         }
     }
+    #endregion
 
     void DogIconClick(ClickEvent e)
     {
@@ -209,22 +211,33 @@ public class MenuController : MonoBehaviour
             dogList.visible = false;
         }
 
-
-
     }
-    #endregion
+
 
     #region 左侧菜单控制
     // 点击狗的名字时候处理
     void DogNameClick(ClickEvent e, int index)
     {
         GameData.focusDog = index;
-        GameData.homeCamFocusDog = index;
-        dogNames[index].transform.scale = new Vector2(1.5f, 1.5f);
-        HomeController.dogCam.m_LookAt = HomeController.dogsInScene[index].gameObject.transform;
-        HomeController.dogCam.Priority = 10;
-        HomeController.playerCam.Priority = 1;
-        HomeController.lastCameraChange = DateTime.Now;
+        if (GameData.homeCamFocusDog == index)
+        {
+            // 重复点击狗的名字,恢复广角,所有狗的名字显示一样大小
+            HomeController.dogCam.Priority = 1;
+            HomeController.playerCam.Priority = 10;
+            GameData.homeCamFocusDog = 100;     // 100表示不聚焦
+            //dogNames[index].transform.scale = new Vector2(1f, 1f);
+
+        }
+        else
+        {
+            GameData.homeCamFocusDog = index;
+            //dogNames[index].transform.scale = new Vector2(1.2f, 1.2f);
+            HomeController.dogCam.m_LookAt = HomeController.dogsInScene[index].gameObject.transform;
+            HomeController.dogCam.Priority = 10;
+            HomeController.playerCam.Priority = 1;
+            HomeController.lastCameraChange = DateTime.Now;
+        }
+        
         if (dogList.visible == true) { dogList.visible = false; }   
     }
 
@@ -237,12 +250,12 @@ public class MenuController : MonoBehaviour
             dogNames.Add(child);
         }
 
-        // 注入狗的名字
-        for (int i = 0; i < UserProperty.dogs.Count; i++)
+        // 注入狗的名字,最多注入3只狗
+        for (int i = 0; i < Math.Min(UserProperty.dogs.Count, 3); i++)
         {
             int index = i;
             dogNames[i].style.display = DisplayStyle.Flex;
-            dogNames[i].text = UserProperty.dogs[i].name;
+            dogNames[i].text = UserProperty.dogs[i].dog_name;
             dogNames[i].RegisterCallback<ClickEvent>(e => DogNameClick(e, index));
         }
     }
@@ -253,7 +266,7 @@ public class MenuController : MonoBehaviour
 
         for (int i = 0; i < UserProperty.dogs.Count; i++)
         {
-            if (i == GameData.focusDog)
+            if (i == GameData.homeCamFocusDog)
             {
                 dogNames[i].transform.scale = new Vector2(1.2f, 1.2f);
             }

+ 8 - 0
Assets/Resources/VoiceAndManu/VoiceController.cs

@@ -5,6 +5,7 @@ using UnityEngine;
 using UnityEngine.UIElements;
 
 using System.Runtime.InteropServices;
+using Unity.VisualScripting;
 
 
 public class VoiceController : MonoBehaviour
@@ -63,6 +64,13 @@ public class VoiceController : MonoBehaviour
 
         Debug.Log("voice button pointer down.");
         HomeController.listenBreak = true;
+
+        // 隐藏Dog list
+        var root = GetComponent<UIDocument>().rootVisualElement;
+        var dogList = root.Q<VisualElement>("dogMenu").Q<VisualElement>("dogList");
+        dogList.visible = false;
+
+        // 狗动作变化注释镜头
         foreach (var dog in HomeController.dogsInScene)
         {
             dog.animator.SetTrigger("listen");

+ 122 - 19
Assets/Resources/Warehouse/ItemUseController.cs

@@ -1,39 +1,142 @@
-using UnityEngine;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net.NetworkInformation;
+using UnityEngine;
+using UnityEngine.SceneManagement;
 
 /* 具体使用哪个道具产生的效果,包括结束的效果回调函数
  */
 
-public class ItemUseController : MonoBehaviour
+public class ItemUseController : ScriptableObject
 {
-    // Start is called once before the first execution of Update after the MonoBehaviour is created
-    //void Start()
-    //{
-        
-    //}
-
-    // Update is called once per frame
-    //void Update()
-    //{
-        
-    //}
+    private static Vector3 bowlLocation;
+
+    private static List<string> foodBowlItems = new()
+    {
+        "food_00001",       // 狗粮
+        "food_00002",       // 狗罐头
+        "food_00003"        // 冻肉干
+    };
+    private static List<string> waterBowlItems = new()
+    {
+        "water_00001",      // 水
+        "water_00002"       // 牛奶
+    };
+
+
+
+    public static string _itemUseId = null;        // 暂存使用item数据,调用另外一个Monobehaviour Class来执行网络通讯
+
 
     public static void ItemUsed(string itemId)
     {
-        if (itemId == "water_00001")
+        // 消费食物类
+        if (foodBowlItems.Contains(itemId))
         {
             var bowls = GameObject.Find("Bowls");
-            var bowlWater = bowls.transform.Find("Bowl_water").gameObject;
-            bowlWater.transform.localPosition = Vector3.zero;
-            var water = bowlWater.transform.Find("Water").gameObject;
+            var targetBowl = bowls.transform.Find("Bowl_food").gameObject;
+            targetBowl.transform.localPosition = CalcBowlShowLoc();
+            var food = targetBowl.transform.Find("Food").gameObject;
+            food.SetActive(true);
+
+            foreach (var dogInScene in HomeController.dogsInScene)
+            {
+                dogInScene.StartItemConsume(ItemGroup.food);
+                dogInScene.SetMoveSpeed(UnityEngine.Random.Range(0.3f, 0.6f));
+            }
+            
+        }
+
+        // 消费水牛奶等
+        if (waterBowlItems.Contains(itemId))
+        {
+            var bowls = GameObject.Find("Bowls");
+            var targetBowl = bowls.transform.Find("Bowl_water").gameObject;
+            targetBowl.transform.localPosition = CalcBowlShowLoc();
+            var water = targetBowl.transform.Find("Water").gameObject;
             water.SetActive(true);
+
             foreach (var dogInScene in HomeController.dogsInScene)
             {
                 dogInScene.StartItemConsume(ItemGroup.water);
+                dogInScene.SetMoveSpeed(UnityEngine.Random.Range(0.3f, 0.6f));
             }
 
-          
+        }
+        // TODO 以后打开 网络通讯后刷新数据
+        //ItemUseController._itemUseId = itemId;
+    }
 
-            // TODO 网络通讯后刷新数据
+ 
+    // 计算出一个碗的位置,距离所有只狗都至少2米,夹角至少要45度
+    private static Vector3 CalcBowlShowLoc()
+    {
+        while (true)
+        {
+            float x = UnityEngine.Random.Range(-3f, 3f);
+            float z = UnityEngine.Random.Range(-3f, 3f);
+            bowlLocation = new Vector3(x, 0, z);
+            bool allowToPlace = true;
+            int dogQty = HomeController.dogsInScene.Count;
+            for (int i = 0; i < dogQty; i++) {
+                GameObject dog = HomeController.dogsInScene[i].gameObject;
+                GameObject dogNext;
+                if (i == dogQty - 1)
+                {
+                    dogNext = HomeController.dogsInScene[0].gameObject;      // 如果是最后一只狗,next dog就是第一值
+                }
+                else
+                {
+                    dogNext = HomeController.dogsInScene[i+1].gameObject;
+                }
+                if (Vector3.Distance(bowlLocation, dog.transform.position) < 2)     // 距离所有只狗都至少2米
+                {
+                    allowToPlace = false;
+                    continue;
+                }
+                //if (dogQty > 1)     // 需要计算狗与狗的角度
+                //{
+                //   if(CalcAngle(bowlLocation, dog.transform.position, dogNext.transform.position) < 45)
+                //    {
+                //        allowToPlace = false;
+                //        continue;
+                //    }
+                //}
+            }
+            if (allowToPlace)
+            {
+                return bowlLocation;
+            }
         }
     }
+
+   
+
+    // 废弃,待删除
+    private static float CalcAngle(Vector3 bowlLoc, Vector3 targetLoc1, Vector3 targetPoc2)
+    {
+        // 计算向量AB和向量AC
+        Vector3 vectorAB = bowlLoc - targetLoc1;
+        Vector3 vectorAC = bowlLoc - targetPoc2;
+
+        // 计算向量AB和向量AC的模长
+        float magnitudeAB = vectorAB.magnitude;
+        float magnitudeAC = vectorAC.magnitude;
+
+        // 计算点积
+        float dotProduct = Vector3.Dot(vectorAB, vectorAC);
+
+        // 计算夹角的余弦值
+        float cosTheta = dotProduct / (magnitudeAB * magnitudeAC);
+
+        // 计算夹角θ
+        float angleTheta = Mathf.Acos(cosTheta) * Mathf.Rad2Deg; // 将弧度转换为度数
+        Debug.Log("夹角θ: " + angleTheta + "度");
+
+        return angleTheta;
+    }
+
 }

+ 3 - 1
Assets/Resources/Warehouse/WarehouseController.cs

@@ -174,8 +174,10 @@ public class WarehouseController : MonoBehaviour
     {
         Debug.Log("msg yes clicked");
         msgRoot.visible = false;
+        //ItemUseController itemUseController = new ItemUseController();
         ItemUseController.ItemUsed(selectedItemId);
-        BackBtnClick();
+
+        BackBtnClick();     // 关闭菜单
     }
 
 }

+ 106 - 6
Assets/Scenes/Home.unity

@@ -407,7 +407,13 @@ PrefabInstance:
     m_RemovedComponents: []
     m_RemovedGameObjects: []
     m_AddedGameObjects: []
-    m_AddedComponents: []
+    m_AddedComponents:
+    - targetCorrespondingSourceObject: {fileID: 2417705292335416526, guid: 358eaf0dc05de8c4b925b8d7b41c3df9, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 2103838219}
+    - targetCorrespondingSourceObject: {fileID: 2417705292335416526, guid: 358eaf0dc05de8c4b925b8d7b41c3df9, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 2103838218}
   m_SourcePrefab: {fileID: 100100000, guid: 358eaf0dc05de8c4b925b8d7b41c3df9, type: 3}
 --- !u!1 &207127011
 GameObject:
@@ -798,6 +804,18 @@ PrefabInstance:
       propertyPath: m_StaticEditorFlags
       value: 0
       objectReference: {fileID: 0}
+    - target: {fileID: 6920918337413409961, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 6920918337413409961, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 6920918337413409961, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 2
+      objectReference: {fileID: 0}
     - target: {fileID: 6920918337413409961, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
       propertyPath: m_LocalPosition.x
       value: 0
@@ -838,6 +856,10 @@ PrefabInstance:
       propertyPath: m_LocalEulerAnglesHint.z
       value: 0
       objectReference: {fileID: 0}
+    - target: {fileID: 6920918337413409961, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
+      propertyPath: m_ConstrainProportionsScale
+      value: 1
+      objectReference: {fileID: 0}
     m_RemovedComponents:
     - {fileID: 6558069851603559208, guid: b23aa0f47b77fbc4c8e0a2a9adc0fb29, type: 3}
     m_RemovedGameObjects: []
@@ -882,7 +904,7 @@ BoxCollider:
   m_ProvidesContacts: 0
   m_Enabled: 1
   serializedVersion: 3
-  m_Size: {x: 0.2857564, y: 0.07002613, z: 0.28575647}
+  m_Size: {x: 0.2, y: 0.1, z: 0.2}
   m_Center: {x: -0.00000008940697, y: 0.035010584, z: -0.00000040978193}
 --- !u!54 &253370037
 Rigidbody:
@@ -906,7 +928,7 @@ Rigidbody:
     m_Bits: 0
   m_ImplicitCom: 1
   m_ImplicitTensor: 1
-  m_UseGravity: 0
+  m_UseGravity: 1
   m_IsKinematic: 1
   m_Interpolate: 0
   m_Constraints: 0
@@ -1047,6 +1069,7 @@ GameObject:
   - component: {fileID: 481637086}
   - component: {fileID: 481637087}
   - component: {fileID: 481637088}
+  - component: {fileID: 481637089}
   m_Layer: 0
   m_Name: Player
   m_TagString: Untagged
@@ -1098,6 +1121,18 @@ MonoBehaviour:
   scale: {x: 1, y: 1, z: 1}
   dogDisplayName: 
   loadAllDogs: 1
+--- !u!114 &481637089
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 481637084}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 94cdc4672f3e25147af758cb8b02650f, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
 --- !u!1001 &482970761
 PrefabInstance:
   m_ObjectHideFlags: 0
@@ -1172,6 +1207,18 @@ PrefabInstance:
     serializedVersion: 3
     m_TransformParent: {fileID: 1726968933}
     m_Modifications:
+    - target: {fileID: 25269467461883209, guid: cc1d130c0e7512a4cadff14050b422dc, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 25269467461883209, guid: cc1d130c0e7512a4cadff14050b422dc, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 25269467461883209, guid: cc1d130c0e7512a4cadff14050b422dc, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 2
+      objectReference: {fileID: 0}
     - target: {fileID: 25269467461883209, guid: cc1d130c0e7512a4cadff14050b422dc, type: 3}
       propertyPath: m_LocalPosition.x
       value: 1
@@ -1276,7 +1323,7 @@ BoxCollider:
   m_ProvidesContacts: 0
   m_Enabled: 1
   serializedVersion: 3
-  m_Size: {x: 0.19957918, y: 0.06981205, z: 0.19957921}
+  m_Size: {x: 0.15, y: 0.1, z: 0.15}
   m_Center: {x: -0.00000008568168, y: 0.03515504, z: -0.0000004246831}
 --- !u!54 &502898580
 Rigidbody:
@@ -2010,7 +2057,7 @@ MeshCollider:
   m_LayerOverridePriority: 0
   m_IsTrigger: 0
   m_ProvidesContacts: 0
-  m_Enabled: 1
+  m_Enabled: 0
   serializedVersion: 5
   m_Convex: 0
   m_CookingOptions: 30
@@ -2571,7 +2618,7 @@ MonoBehaviour:
   mainLight: {fileID: 921216527}
   targetCamera: {fileID: 1189983929}
   daySkybox: {fileID: 2100000, guid: 33ab377b49aa14f6fae6e5bac230a5d4, type: 2}
-  nightSkybox: {fileID: 2100000, guid: 80fa4f34db87aad4d93c45188b19bfd6, type: 2}
+  nightSkybox: {fileID: 2100000, guid: d3823126980dd98479f7761e6d47338a, type: 2}
 --- !u!114 &1189983934
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -4258,6 +4305,59 @@ RectTransform:
   m_CorrespondingSourceObject: {fileID: 3819734098196001969, guid: ce6d2f68a67743945825670e3de02e19, type: 3}
   m_PrefabInstance: {fileID: 2099867578}
   m_PrefabAsset: {fileID: 0}
+--- !u!1 &2103838217 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 2417705292335416526, guid: 358eaf0dc05de8c4b925b8d7b41c3df9, type: 3}
+  m_PrefabInstance: {fileID: 162026933}
+  m_PrefabAsset: {fileID: 0}
+--- !u!65 &2103838218
+BoxCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2103838217}
+  m_Material: {fileID: 0}
+  m_IncludeLayers:
+    serializedVersion: 2
+    m_Bits: 0
+  m_ExcludeLayers:
+    serializedVersion: 2
+    m_Bits: 0
+  m_LayerOverridePriority: 0
+  m_IsTrigger: 0
+  m_ProvidesContacts: 0
+  m_Enabled: 1
+  serializedVersion: 3
+  m_Size: {x: 0.2, y: 0.45, z: 0.54}
+  m_Center: {x: 0, y: 0.25, z: 0}
+--- !u!54 &2103838219
+Rigidbody:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2103838217}
+  serializedVersion: 4
+  m_Mass: 10
+  m_Drag: 0
+  m_AngularDrag: 0.05
+  m_CenterOfMass: {x: 0, y: 0, z: 0}
+  m_InertiaTensor: {x: 1, y: 1, z: 1}
+  m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_IncludeLayers:
+    serializedVersion: 2
+    m_Bits: 0
+  m_ExcludeLayers:
+    serializedVersion: 2
+    m_Bits: 0
+  m_ImplicitCom: 1
+  m_ImplicitTensor: 1
+  m_UseGravity: 1
+  m_IsKinematic: 0
+  m_Interpolate: 1
+  m_Constraints: 2
+  m_CollisionDetection: 2
 --- !u!1 &2130545348
 GameObject:
   m_ObjectHideFlags: 0

+ 17 - 5
Assets/Scenes/Login.unity

@@ -1249,11 +1249,11 @@ PrefabInstance:
     m_Modifications:
     - target: {fileID: 2423078848980761147, guid: fd44ee5e3fce2cc49bcb46188b301e97, type: 3}
       propertyPath: m_Name
-      value: Cartoon_ShibaInu_LowPoly_c1 (1)
+      value: createdDog
       objectReference: {fileID: 0}
     - target: {fileID: 2423078848980761147, guid: fd44ee5e3fce2cc49bcb46188b301e97, type: 3}
       propertyPath: m_IsActive
-      value: 1
+      value: 0
       objectReference: {fileID: 0}
     - target: {fileID: 3092655508200546433, guid: fd44ee5e3fce2cc49bcb46188b301e97, type: 3}
       propertyPath: m_LocalScale.x
@@ -1977,6 +1977,7 @@ GameObject:
   - component: {fileID: 963194230}
   - component: {fileID: 963194229}
   - component: {fileID: 963194233}
+  - component: {fileID: 963194234}
   m_Layer: 0
   m_Name: Camera
   m_TagString: MainCamera
@@ -2102,8 +2103,8 @@ MonoBehaviour:
   m_UpdateMethod: 2
   m_BlendUpdateMethod: 1
   m_DefaultBlend:
-    m_Style: 6
-    m_Time: 0.8
+    m_Style: 1
+    m_Time: 2
     m_CustomCurve:
       serializedVersion: 2
       m_Curve: []
@@ -2117,6 +2118,18 @@ MonoBehaviour:
   m_CameraActivatedEvent:
     m_PersistentCalls:
       m_Calls: []
+--- !u!114 &963194234
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 963194225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cf1c61d68f2a7842bebe048adbcbdfd, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
 --- !u!1 &972508926
 GameObject:
   m_ObjectHideFlags: 0
@@ -4297,7 +4310,6 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: b4721b03b149c5f4696e394f763e20e8, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  displayDogName: createdDog
 --- !u!1660057539 &9223372036854775807
 SceneRoots:
   m_ObjectHideFlags: 0

+ 3 - 2
Assets/Scenes/Playground.unity

@@ -344,8 +344,9 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   displayDogName: dog
   dogProperty:
-    id: 121212121
-    name: "\u5C0F\u6CE5\u9CC5"
+    d_id: 121212121
+    owner_id: 
+    dog_name: "\u5C0F\u6CE5\u9CC5"
     sex: 1
     breed: shibaInu
     skin: black

+ 32 - 9
Assets/Scripts/Develop Script/TestSetup.cs

@@ -1,19 +1,36 @@
 using System;
 using UnityEngine;
+using UnityEngine.SceneManagement;
 
 public class TestSetup : MonoBehaviour
 {
 
     void Awake()
     {
-        // 初始化狗数据用于测试
-        DogProperty puppy = new DogProperty();
-        UserProperty.dogs.Clear();
-        UserProperty.dogs.Add(puppy);
-        UserProperty.food.Add(new Item("food_00001", 10));
-        UserProperty.food.Add(new Item("food_00002", 20));
-        UserProperty.food.Add(new Item("food_00003", 30));
-        UserProperty.food.Add(new Item("water_00001", 999));
+        if (SceneManager.GetActiveScene().name == "Home")
+        {
+            // 初始化狗数据用于测试
+            //DogProperty puppy = new DogProperty();
+            //UserProperty.dogs.Clear();
+            //UserProperty.dogs.Add(puppy);
+            UserProperty.food.Add(new Item("food_00001", 10));
+            UserProperty.food.Add(new Item("food_00002", 20));
+            UserProperty.food.Add(new Item("food_00003", 30));
+            UserProperty.food.Add(new Item("water_00001", 999));
+        }
+
+        //if (SceneManager.GetActiveScene().name == "Playground")
+        //{
+        //    // 初始化狗数据用于测试
+        //    DogProperty puppy = new DogProperty();
+        //    UserProperty.dogs.Clear();
+        //    UserProperty.dogs.Add(puppy);
+        //    UserProperty.food.Add(new Item("food_00001", 10));
+        //    UserProperty.food.Add(new Item("food_00002", 20));
+        //    UserProperty.food.Add(new Item("food_00003", 30));
+        //    UserProperty.food.Add(new Item("water_00001", 999));
+        //}
+
 
         if (EnviromentSetting.languageData == null)
         {
@@ -24,16 +41,22 @@ public class TestSetup : MonoBehaviour
     // Start is called once before the first execution of Update after the MonoBehaviour is created
     void Start()
     {
+        if (SceneManager.GetActiveScene().name == "Login")
+        {
+            TestDataInjection();
+        }
         
     }
 
     // todo 删除。测试假数据注入
     void TestDataInjection()
     {
-        PlayerPrefs.SetString("LoginToken", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiSlRZTlpQOU8iLCJleHAiOjE3NDAxOTQ2Nzl9.081FF2AwxDTsN1gDWGZuzOxIDbM4M8Dw-mdwLfkxk4A");
+        PlayerPrefs.SetString("LoginToken", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiSlRZTlpQOU8iLCJleHAiOjE3NTY1NDUxNzd9.oQgjY_6ZHJVYaYxh2b_LMIkUaCJ9FX8UpxpHOt_yLg8");
         DateTime now = DateTime.Now;
         DateTime oneHourAgo = now.AddHours(-1);
         PlayerPrefs.SetString("LoginTokenTime", oneHourAgo.ToString());
+
+        //PlayerPrefs.DeleteAll();
     }
     // Update is called once per frame
     //    void Update()

+ 3 - 1
Assets/Scripts/EnviromentSetting.cs

@@ -38,7 +38,9 @@ public static class EnviromentSetting
     // 狗的数据库
     public static string dogDBFilePath = "Assets/Resources/Data/dogDB.json";
     public static DogBreed[] dogBreeds;
-    
+
+    // 最大狗的数量
+    public static int maxDogQty = 3;
     
 }
 

+ 6 - 0
Assets/Scripts/Functions/WebController.cs

@@ -79,6 +79,12 @@ public class WebController : MonoBehaviour {
             if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
             {
                 Debug.Log("上传失败: " + request.error);
+                if (request.error == "Cannot connect to destination host")
+                {
+                    string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "network_error", EnviromentSetting.languageCode });
+                    MessageBoxController.ShowMessage(msg, () => Application.Quit());
+                }
+                Debug.Log("上传失败信息: " + request.downloadHandler.text);
             }
             else
             {

+ 26 - 4
Assets/Scripts/GameControllers/DogInitialize.cs

@@ -4,6 +4,7 @@ using UnityEngine;
  * 初始化狗的基础模型和颜色
  * 场景中特殊的components 需要在场景单独的程序中加载
  * 狗的breed和skin大小写需要注意
+ * 本代码控制最大显示狗的数量,变量:maxDogQty
  */
 
 public class DogInitialize: MonoBehaviour {
@@ -16,7 +17,11 @@ public class DogInitialize: MonoBehaviour {
     // Start is called once before the first execution of Update after the MonoBehaviour is created
     void Start()
     {
-
+        int maxDogQty = 3;      // 限制最大狗的数量
+        while (UserProperty.dogs.Count > maxDogQty)
+        {
+            UserProperty.dogs.RemoveAt(UserProperty.dogs.Count - 1);
+        }
         if (loadAllDogs)
         {
             foreach (var dog in UserProperty.dogs)
@@ -44,21 +49,38 @@ public class DogInitialize: MonoBehaviour {
         if (this.dogProperty != null)
         {
             var puppy = this.dogProperty;
-            GameObject dog = Instantiate(Resources.Load<GameObject>("Dog/Breed/" + puppy.breed));
+            GameObject dogResource = Resources.Load<GameObject>("Dog/Breed/" + puppy.breed);
+            if (dogResource == null) {
+                dogResource = Resources.Load<GameObject>("Dog/Breed/shibaInu");        // 默认读取,防止后端传入数据错误
+            }
+            GameObject dog = Instantiate(dogResource);
             if (!string.IsNullOrWhiteSpace(dogDisplayName))
             {
                 dog.name = dogDisplayName;
             }
             else
             {
-                dog.name = puppy.name;
+                dog.name = puppy.dog_name;
             }
             if (dog != null)
             {
-                GameObject dogL2 = dog.transform.Find(puppy.breed).gameObject;
+                GameObject dogL2;
+                try
+                {
+                    dogL2 = dog.transform.Find(puppy.breed).gameObject;
+                }
+
+                catch
+                {
+                    dogL2 = dog.transform.Find("shibaInu").gameObject;
+                }
                 Renderer renderer = dogL2.GetComponent<Renderer>();
                 //Texture skin = Resources.Load<Texture>("Dog/Skin/" + puppy.breed + "/" + puppy.skin);
                 Material mat = Resources.Load<Material>("Dog/Skin/" + puppy.breed + "/" + puppy.skin);
+                if (mat == null) 
+                {
+                    mat = Resources.Load<Material>("Dog/Skin/shibaInu/amber");        // 默认读取,防止后端传入数据错误
+                }
                 if (mat != null && renderer != null)
                 {
                     //renderer.material.mainTexture = skin;

+ 4 - 2
Assets/Scripts/GameControllers/DogProperty.cs

@@ -13,8 +13,9 @@ using System.IO;
 public class DogProperty
 {
     // Start is called before the first frame update
-    public string id = "121212121";
-    public string name = "小泥鳅";
+    public string d_id = "121212121";
+    public string owner_id = string.Empty;
+    public string dog_name = "小泥鳅";
     public int sex = 1;
     public string breed = "shibaInu";       // 狗的默认模型
     public string skin = "black";     // 狗的默认贴图
@@ -46,6 +47,7 @@ public class DogProperty
     public int commandLieDown = 50;
     public int commandRotate = 50;
     
+    
 }
 
 public class DogBreed

+ 1 - 1
Assets/Scripts/GameControllers/GameData.cs

@@ -5,6 +5,6 @@ public static class GameData
 {
     public static string subScene;      // 用于指定子场景用
     public static int focusDog = 0;     // 游戏中目前玩家主要玩的狗
-    public static int homeCamFocusDog = 0;      // Home场景下,摄像机聚焦的狗
+    public static int homeCamFocusDog = 100;      // Home场景下,摄像机聚焦的狗。100表示不聚焦任何的狗
 
 }

+ 13 - 0
Assets/Scripts/GameControllers/UserProperty.cs

@@ -21,8 +21,21 @@ public static class UserProperty
     public static List<Item> toy = new();
     public static List<Item> other = new();       // 这里dict string对应的是物品大类food, toy, other
     public static List<DogProperty> dogs = new();
+
+    public static string dogNames()
+    {
+        // 获取狗名字列表
+        List<string> dogNameList = new List<string>();
+        foreach (var dog in UserProperty.dogs)
+        {
+            dogNameList.Add(dog.dog_name);
+        }
+        string dogNames = string.Join(", ", dogNameList);
+        return dogNames;
+    }
 }
 
+// 待删除代码,废弃
 // string id 表示具体的物品id,如food_00001
 // qty 表示数量
 public class Item

+ 8 - 2
Assets/Scripts/Home/BowlColliderController.cs

@@ -30,18 +30,24 @@ public class BowlColliderController : MonoBehaviour
         foreach (var dogInScene in HomeController.dogsInScene)
         {
             if (dogInScene.gameObject == other.gameObject) {        // 检测哪一只doginScene发生碰撞
+
                 if (thisObject.name == "Bowl_water")
                 {
+
                     dogInScene.isMovingToBowl = false;
                     dogInScene.drinkStartTime = DateTime.Now;
                     dogInScene.animator.SetTrigger("drink");
                     dogInScene.animator.SetBool("isDrinking", true);
                     StartCoroutine(dogInScene.DrinkAnimation());
                     //dogInScene.DrinkAnimation();
-                }else if (thisObject.name == "Bowl_food")
+                }
+                if (thisObject.name == "Bowl_food")
                 {
+                    dogInScene.isMovingToBowl = false;
                     dogInScene.eatStartTime = DateTime.Now;
-                    dogInScene.Eat();
+                    dogInScene.animator.SetTrigger("eat");
+                    dogInScene.animator.SetBool("isEating", true);
+                    StartCoroutine(dogInScene.EatAnimation());
                 }
             }
         }

+ 148 - 57
Assets/Scripts/Home/HomeController.cs

@@ -13,6 +13,7 @@ using UnityEngine.Rendering.PostProcessing;
  * 控制宠物在Home场景动画
  * !!!特别注意:Dog Initializer 必须挂载在同一个组件下,并且必须在本组价下方。确保比本组件先执行
  * 主要调节参数在FixedUpdate代码段里面
+ * 提示用户注册
  */
 
 public class HomeController : MonoBehaviour
@@ -26,6 +27,7 @@ public class HomeController : MonoBehaviour
     // Start is called once before the first execution of Update after the MonoBehaviour is created
     void Start()
     {
+
         lastCameraChange = DateTime.Now;
         playerCam = GameObject.Find("VCam Player").GetComponent<CinemachineVirtualCamera>();
         dogCam = GameObject.Find("VCam Dog").GetComponent<CinemachineVirtualCamera>();
@@ -41,7 +43,7 @@ public class HomeController : MonoBehaviour
             if (dateTime.Hour >= 22 || dateTime.Hour <= 5)      // 深夜模式,狗默认在睡觉状态
             {
                 dog.Sleep();
-            }
+            }else if(dog.dogProperty.stamina <= 10) { dog.Sleep(); }        // 狗体力太低了,进入睡觉模式
             else
             {
                 dog.StartAnimation();
@@ -53,10 +55,25 @@ public class HomeController : MonoBehaviour
     // Update is called once per frame
     void FixedUpdate()
     {
-        
+
         #region 场景动画主循环
-        // 生成一个数据数用于随机开启动画,如果和狗的randomFactor相同就开启动画
-        int randomCheck = UnityEngine.Random.Range(0, 51);
+        // 检测狗是否被撞翻,如果是,立刻翻回来
+        foreach (var dog in dogsInScene)
+        {
+            Quaternion curRotation = dog.gameObject.transform.rotation;
+            if (curRotation.x !=0)
+            {
+                curRotation.x = 0;
+            }
+            if (curRotation.z != 0)
+            {
+                curRotation.z = 0;
+            }
+            dog.gameObject.transform.rotation = curRotation;
+        }
+
+            // 生成一个数据数用于随机开启动画,如果和狗的randomFactor相同就开启动画
+            int randomCheck = UnityEngine.Random.Range(0, 51);
         foreach (var dog in dogsInScene)
         {
             // 如果在eat drink进程结束前不执行随机场景代码
@@ -93,6 +110,7 @@ public class HomeController : MonoBehaviour
                         else        // 狗狗开始步行移动
                         {
                             dog.SetMoveSpeed(0);
+                            dog.moveSpeed = 0;
                             dog.Move();
                         }
                     }
@@ -111,9 +129,9 @@ public class HomeController : MonoBehaviour
     //void InitialScene()
     IEnumerator InitialScene()
     {
-        // 
-        yield return null;      // 跳过第一帧
-        Debug.Log("Home InitialScene is called");
+        //yield return null;     
+        //yield return null;     
+        yield return null;      // 跳过三帧,初始化最多三只狗
         Debug.Log(isInitialDone);
         foreach (var dog in UserProperty.dogs)
         {
@@ -123,7 +141,11 @@ public class HomeController : MonoBehaviour
             float y = UnityEngine.Random.Range(0, 360f);
             var initPosition = new Vector3(x, 0, z);
             StartCoroutine(DogComponentAdd(dog));       // 加载狗的其他组件
-            var dogGameObject = GameObject.Find(dog.name);
+            var dogGameObject = GameObject.Find(dog.dog_name);
+            if (dogGameObject == null)
+            {
+                Debug.Log(dog.dog_name + "is not found in Home Controller");
+            }
             dogGameObject.transform.position = initPosition;
             dogGameObject.transform.rotation = Quaternion.Euler(0, y, 0);
             dogGameObject.transform.localScale = new Vector3(2, 2, 2);
@@ -139,7 +161,7 @@ public class HomeController : MonoBehaviour
         yield return null;
 
         // 第一帧以后开始执行
-        GameObject dog = GameObject.Find(dogProperty.name);
+        GameObject dog = GameObject.Find(dogProperty.dog_name);
 
         // 加载指定的Animator controller
         Animator animator = dog.GetComponent<Animator>();
@@ -148,12 +170,24 @@ public class HomeController : MonoBehaviour
 
         animator.runtimeAnimatorController = animatorController;
 
-        // 加载bbx collider
+        // 加载Rigidbody
+        Rigidbody rigidbody = dog.AddComponent<Rigidbody>();
+        //rigidbody.isKinematic = true;
+        rigidbody.mass = 10;
+        rigidbody.linearDamping = 10;
+        rigidbody.angularDamping = 10;
+        //rigidbody.freezeRotation = true;
+        rigidbody.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezeRotation;
+        rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
+        rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
+
+        // 加载box collider
         BoxCollider boxCollider = dog.AddComponent<BoxCollider>();
-        boxCollider.isTrigger = true;
-        boxCollider.center = new Vector3(0, 0.225f, 0);
-        boxCollider.size = new Vector3(0.2f, 0.45f, 0.6f);
+        boxCollider.isTrigger = false;
+        boxCollider.center = new Vector3(0, 0.25f, 0);
+        boxCollider.size = new Vector3(0.12f, 0.45f, 0.54f);
 
+        //yield return null;
     }
 
     // 场景随机切换镜头看向不同的狗
@@ -164,7 +198,6 @@ public class HomeController : MonoBehaviour
         if (ts.TotalSeconds < delay) {return;}
         int dogCount = dogsInScene.Count;
         int r = UnityEngine.Random.Range(0, dogCount+1);
-        Debug.Log("RandomCameraChange Start. R:" + r);
         if (r < dogCount)
         {
             dogCam.m_LookAt = dogsInScene[r].gameObject.transform;
@@ -188,19 +221,22 @@ public class DogInScene
     public GameObject gameObject { set; get; }
     public Animator animator;
     private Vector3 moveToLocation;
-    private float moveSpeed;     // 用来控制狗的移动速度 0 0.5跑,0.75快跑,1跳
+    public float moveSpeed;     // 用来控制狗的移动速度 0 0.5跑,0.75快跑,1跳
 
     // 喝水吃饭参数段
     public DateTime drinkStartTime, eatStartTime;      // 记录吃喝开始时间
     public bool itemConsumeProgress, eatProgress = false;     // 是否在吃和喝的进程中。如果是的话,跳过常规动画检测
     public bool isMovingToBowl;
 
+
     // 随机动作参数段
-    public int randomFactor = UnityEngine.Random.Range(0, 51);        // 生成一个随机整数(0 到 50 之间),用于时间校验
+    public int randomFactor;
     public DateTime animationStartTime;     // 记录上一个动画开始时间的,每个随机动作间隔至少30秒
     private int activeIndex;      // 动物的活动指数
     public bool isMoving;       // 动物正在移动,避免其他随机动作发生
 
+    // 固定参数
+    private float moveSpeedAdj = 0.022f;
 
 
     #region 通用函数段
@@ -208,7 +244,8 @@ public class DogInScene
     {
         this.gameObject = gameObject;
         this.animator = gameObject.GetComponent<Animator>();
-
+        this.randomFactor = UnityEngine.Random.Range(0, 51);        // 生成一个随机整数(0 到 50 之间),用于时间校验
+        Debug.Log(this.gameObject.name + "random factor is:"+randomFactor);
     }
     
 
@@ -225,10 +262,10 @@ public class DogInScene
     {
         this.animationStartTime = DateTime.Now;
         this.animator.SetInteger("activeIndex", activeIndex);
-        Debug.Log("activeIndex:" + this.activeIndex);
+        //Debug.Log("activeIndex:" + this.activeIndex);
         float randomIndex = UnityEngine.Random.Range(0, 1f);
         this.animator.SetFloat("randomIndex", randomIndex);
-        Debug.Log("randomIndex:" + randomIndex);
+        //Debug.Log("randomIndex:" + randomIndex);
     }
 
     public void SetMoveSpeed(float speed)
@@ -238,12 +275,20 @@ public class DogInScene
 
     public void Move()
     {
+
+        // 如果距离目标小于0.5米就把速度调整为零
+        if (Vector3.Distance(moveToLocation, this.gameObject.transform.position) < 0.5f)
+        {
+            //Debug.Log(this.gameObject.name + "current move speed:" + moveSpeed);
+            this.SetMoveSpeed(0);
+            //Debug.Log(this.gameObject.name + "reduce move speed:" + moveSpeed);
+        }
         
         if (isMoving == false)
         {
             animationStartTime = DateTime.Now;      // 设置动画开始时间
             float x = UnityEngine.Random.Range(-5f, 5f);
-            float z = UnityEngine.Random.Range(-5f, 5f);
+            float z = UnityEngine.Random.Range(0f, 5f);
             this.moveToLocation = new Vector3(x, 0, z);
             //Debug.Log("move to location:" + x + ", " + z);
             this.isMoving = true;
@@ -252,7 +297,8 @@ public class DogInScene
             this.animator.SetFloat("moveSpeed", this.moveSpeed);
         }
         this.gameObject.transform.LookAt(moveToLocation);
-        this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, dogProperty.runSpeed * 0.02f * 0.01f);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整
+        this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, dogProperty.runSpeed * (1 + moveSpeed) * 0.02f * moveSpeedAdj);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整,对应RM动画
+        //this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, (100 + dogProperty.runSpeed) * (1 + moveSpeed) * 0.02f * 0.015f);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整,对应IF动画
         //Debug.Log("current position:" + gameObject.transform.position.x + "z:" + gameObject.transform.position.z);
 
         // 如果狗距离到达重点就停止跑步动画
@@ -260,6 +306,7 @@ public class DogInScene
         if (distance  < 0.1)
         {
             this.animator.SetBool("isMoving", false);
+            //this.moveSpeed = 0.4f;
             this.isMoving = false;
             StartAnimation();
         }
@@ -290,7 +337,7 @@ public class DogInScene
     {
         if (result)
         {
-            // TODO 成功,狗狗跑过来
+            // TODO 语音信息识别成功,狗狗跑过来
         }
         else
         {
@@ -304,15 +351,18 @@ public class DogInScene
     // 开始整个使用道具的流程
     public void StartItemConsume(ItemGroup group)
     {
-        
 
-        GameObject bowl = new();
+        GameObject bowl = GameObject.Find("Bowl_water");        // 先指定一个碗,编译通过
+
+        this.itemConsumeProgress = true;        // 开启使用道具过程
         if (group == ItemGroup.water)
         {
-            this.itemConsumeProgress = true;      // 开启整个喝水的进程
-            bowl = GameObject.Find("Bowl_water");
+            bowl = GameObject.Find("Bowl_water");       // 开启整个喝水的进程
+        }
+        if (group == ItemGroup.food) 
+        {
+            bowl = GameObject.Find("Bowl_food");        // 开启整个吃食物的进程
         }
-        if (group == ItemGroup.food) { }        // 吃事物的过程
         this.moveToLocation = bowl.transform.position;
         this.isMovingToBowl = true;
         this.animator.SetTrigger("move");       // 切换为走路动画
@@ -322,16 +372,23 @@ public class DogInScene
 
     public void MovetoBowl()
     {
-        // 隐藏主菜单
-        //var uiPlaceholder = GameObject.Find("UI Placeholder");
-        //var vamUI = uiPlaceholder.transform.Find("VoiceAndMenu").gameObject;
+
+        // 如果距离目标小于0.5米就把速度调整为零
+        if (Vector3.Distance(moveToLocation, this.gameObject.transform.position) < 0.5f)
+        {
+            Debug.Log(this.gameObject.name + "current move speed:" + moveSpeed);
+            this.SetMoveSpeed(0);
+            Debug.Log(this.gameObject.name + "reduce move speed:" + moveSpeed);
+        }
+
         var vamUI = GameObject.Find("VoiceAndMenu");
         if (vamUI != null)
         {
             vamUI.SetActive(false);
         }
         this.gameObject.transform.LookAt(moveToLocation);
-        this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, dogProperty.runSpeed * 0.02f * 0.01f);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整
+        this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, dogProperty.runSpeed * (1 + moveSpeed) * 0.02f * moveSpeedAdj);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整,对应RM动画
+        //this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, (100+dogProperty.runSpeed) * (1 + moveSpeed) * 0.02f * 0.015f);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整,对应IF动画
         //Debug.Log("current position:" + gameObject.transform.position.x + "z:" + gameObject.transform.position.z);
 
         // 如果狗距离到达重点就停止跑步动画
@@ -342,30 +399,17 @@ public class DogInScene
         }
     }
 
-    //public IEnumerator MovetoBowl()
-    //{
-
-    //    this.gameObject.transform.LookAt(moveToLocation);
-    //    // 如果狗距离到达重点就停止跑步动画
-    //    float distance = 1000;
-    //    while (distance > 0.1)
-    //    {
-    //        distance = Vector3.Distance(gameObject.transform.position, moveToLocation);
-    //        this.gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, moveToLocation, dogProperty.runSpeed * 0.02f * 0.01f);  // 第一个0.02对应50帧fixupdate画面,后面一个数字对应速度调整
-    //    }
-    //    this.animator.SetBool("isMoving", false);
-    //}
-
-    //public void DrinkAnimation()
     public IEnumerator DrinkAnimation()
 
     {
         this.animator.SetBool("isMoving", false);       // 关闭移动动画
         TimeSpan ts = new TimeSpan();
-        var bowlWater = GameObject.Find("Bowl_water");
+        var targetBowl = GameObject.Find("Bowl_water");
+
+        
 
         // 摄像头看向水盆位置
-        HomeController.dogCam.m_LookAt = bowlWater.transform;
+        HomeController.dogCam.m_LookAt = targetBowl.transform;
         HomeController.dogCam.Priority = 10;
         HomeController.playerCam.Priority = 1;
 
@@ -373,10 +417,18 @@ public class DogInScene
         {
             yield return new WaitForSeconds(0.25f);
             ts = DateTime.Now - this.drinkStartTime;
-            Debug.Log("结束饮水过程:" + ts.TotalSeconds);
+            //Debug.Log("结束饮水过程:" + ts.TotalSeconds);
+
+            // 狗一致看向谁碰,确保就算被撞击后依然看向水盆
+            this.gameObject.transform.LookAt(targetBowl.transform.position);
         }
         // 播放10秒后结束饮水过程
         this.animator.SetBool("isDrinking", false);
+
+        // 摄像头恢复玩家视角
+        HomeController.dogCam.Priority = 1;
+        HomeController.playerCam.Priority = 10;
+
         //var water = GameObject.Find("Water");
         //water.SetActive(false);
 
@@ -385,19 +437,58 @@ public class DogInScene
         {
             yield return new WaitForSeconds(0.25f);
             ts = DateTime.Now - this.drinkStartTime;
-            Debug.Log("让水盆消失:" + ts.TotalSeconds);
+            //Debug.Log("让水盆消失:" + ts.TotalSeconds);
         }
         
-        bowlWater.transform.position = new Vector3(-1, -10, -1);       // 将喝水碗回归原位
+        targetBowl.transform.position = new Vector3(-1, -10, -1);       // 将喝水碗回归原位
         this.itemConsumeProgress = false;      // 关闭整个喝水的进程
 
         QuitItemConsume();
     }
 
-    public void Eat()
+    public IEnumerator EatAnimation()
     {
-        this.animator.SetBool("isEating", true);
-        this.animator.SetBool("isMoving", false);
+        this.animator.SetBool("isMoving", false);       // 关闭移动动画
+        TimeSpan ts = new TimeSpan();
+        var targetBowl = GameObject.Find("Bowl_food");
+
+
+        // 摄像头看向盆位置
+        HomeController.dogCam.m_LookAt = targetBowl.transform;
+        HomeController.dogCam.Priority = 10;
+        HomeController.playerCam.Priority = 1;
+
+        while (ts.TotalSeconds < 10)
+        {
+            yield return new WaitForSeconds(0.25f);
+            ts = DateTime.Now - this.eatStartTime;
+            //Debug.Log("结束饮水过程:" + ts.TotalSeconds);
+
+            // 狗一致看向谁碰,确保就算被撞击后依然看向水盆
+            this.gameObject.transform.LookAt(targetBowl.transform.position);
+        }
+        // 播放10秒后结束饮水过程
+        this.animator.SetBool("isEating", false);
+
+        // 摄像头恢复玩家视角
+        HomeController.dogCam.Priority = 1;
+        HomeController.playerCam.Priority = 10;
+
+        //var water = GameObject.Find("Water");
+        //water.SetActive(false);
+
+        // 再等待几秒后让水盆消失
+        while (ts.TotalSeconds < 15)
+        {
+            yield return new WaitForSeconds(0.25f);
+            ts = DateTime.Now - this.drinkStartTime;
+            //Debug.Log("让水盆消失:" + ts.TotalSeconds);
+        }
+
+        targetBowl.transform.position = new Vector3(-1, -10, -1);       // 将喝水碗回归原位
+        this.itemConsumeProgress = false;      // 关闭整个喝水的进程
+
+        QuitItemConsume();
     }
 
     private void QuitItemConsume()
@@ -405,10 +496,10 @@ public class DogInScene
         var uiPlaceholder = GameObject.Find("UI Placeholder");
         var vamUI = uiPlaceholder.transform.Find("VoiceAndMenu").gameObject;
         vamUI.SetActive(true);
+        this.moveSpeed = UnityEngine.Random.Range(0.3f,0.6f);
+        Move();
 
-        // 摄像头恢复玩家视角
-        HomeController.dogCam.Priority = 1;
-        HomeController.playerCam.Priority = 10;
+        
     }
 
     #endregion

+ 84 - 0
Assets/Scripts/Home/ItemUseWebCommController.cs

@@ -0,0 +1,84 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+/* 本代码主要是因为Unity限制Monobehavior不能new()。
+ * 因此在本类中监控ItemUseController._itemUseId 一旦不是null就触发网络通讯
+ */
+public class ItemUseWebCommController : MonoBehaviour
+{
+    // Start is called once before the first execution of Update after the MonoBehaviour is created
+    //void Start()
+    //{
+        
+    //}
+
+    // Update is called once per frame
+    void Update()
+    {
+        if (ItemUseController._itemUseId != null)
+        {
+            StartCoroutine(ItemUsePost(ItemUseController._itemUseId));
+            ItemUseController._itemUseId = null;
+        }
+    }
+
+    // Post道具使用时网络通讯 
+    IEnumerator ItemUsePost(string itemId)
+    {
+        Debug.Log("Item use Post request");
+
+        // 提交POST
+        string url = "/api/item/use/";
+
+        WWWForm form = new();
+        form.AddField("user_id", UserProperty.userId);
+        form.AddField("item_id", itemId);
+        form.AddField("dog_names", UserProperty.dogNames());
+        form.AddField("date_time", DateTime.Now.ToString());
+
+        StartCoroutine(WebController.PostRequest(url, form, callback: ItemUseCallback));
+        yield break;
+    }
+
+    // Post道具使用网络通讯后Callback
+    void ItemUseCallback(string json)
+    {
+        var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
+        if (data != null && data["status"].ToString() == "success")
+        {
+            var user_info = JsonConvert.DeserializeObject<Dictionary<string, string>>(data["user_info"].ToString());
+
+            UserProperty.name = user_info["user_name"];
+            UserProperty.coin = int.Parse(user_info["coin"]);
+            UserProperty.mobile = user_info["mobile"];
+            UserProperty.email = user_info["email"];
+            UserProperty.level = user_info["level"];
+            UserProperty.isRegUser = bool.Parse(user_info["isRegUser"]);
+
+            // 清空现有数据保存狗的数据
+            DogProperty[] dogProperties = JsonConvert.DeserializeObject<DogProperty[]>(data["dogs"].ToString());
+            UserProperty.dogs.Clear();
+            foreach (var dog in dogProperties)
+            {
+                UserProperty.dogs.Add(dog);
+            }
+
+            // 判断用户狗的数量,如果为0就跳转用户创建狗。
+            if (UserProperty.dogs.Count < 1)
+            {
+                GameData.subScene = "Login_InitDog";
+                SceneManager.LoadScene("Login");
+            }
+
+        }
+        else
+        {
+            Debug.Log(data["message"]);
+        }
+
+    }
+}

+ 2 - 0
Assets/Scripts/Home/ItemUseWebCommController.cs.meta

@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 94cdc4672f3e25147af758cb8b02650f

+ 48 - 10
Assets/Scripts/Login/InitDogUIController.cs

@@ -1,7 +1,9 @@
-using System.Collections;
+using Newtonsoft.Json;
+using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.Rendering.PostProcessing;
+using UnityEngine.SceneManagement;
 using UnityEngine.UIElements;
 
 /* 本controller用来控制创建宠物UI和相关通讯的代码
@@ -21,10 +23,17 @@ public class InitDogUIController : MonoBehaviour
     private int dogSkinIndex = 0;      // 显示狗的皮肤颜色
     private DogProperty dogProperty = new();        // 用于暂存生成狗的属性配置
 
-    public string displayDogName = "createdDog";
+    private string displayDogName = "createdDog";
     // Start is called once before the first execution of Update after the MonoBehaviour is created
     void Start()
     {
+        // 检测狗的数量如果达到最大数量就停止创建
+        if (UserProperty.dogs.Count >= EnviromentSetting.maxDogQty)
+        {
+            string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "cannot_add_dog", EnviromentSetting.languageCode });
+            MessageBoxController.ShowMessage(msg, () => SceneManager.LoadScene("Home"));
+        }
+
         var root = GetComponent<UIDocument>().rootVisualElement;
         dogNameTextField = root.Q<TextField>("name");
         breedDropdownField = root.Q<DropdownField>("breed");
@@ -53,6 +62,13 @@ public class InitDogUIController : MonoBehaviour
     // 绑定breed下拉框更新,读取相对应的狗的数据
     void OnBreedChanged(ChangeEvent<string> evt)
     {
+        // 清理已经显示的狗
+        GameObject existDog = GameObject.Find(displayDogName);
+        if (existDog != null)
+        {
+            Destroy(existDog);
+        }
+
         dogBreed = EnviromentSetting.dogBreeds[breedDropdownField.index];
         
         dogProperty.breed = dogBreed.breed;
@@ -128,21 +144,37 @@ public class InitDogUIController : MonoBehaviour
     // 绑定点击按键
     void ConfirmClick()
     {
-        dogProperty.name = dogNameTextField.text;
-        ConfirmClickPost();
+        dogProperty.dog_name = dogNameTextField.text;
+        bool dogNameAllowed = true;
+        foreach (var dog in UserProperty.dogs)
+        {
+            if (dogProperty.dog_name == dog.dog_name){
+                dogNameAllowed = false;
+            }
+        }
+        if (dogNameAllowed)
+        {
+            ConfirmClickPost();
+        }
+        else
+        {
+            string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "dog_name_duplicated", EnviromentSetting.languageCode });
+            msg.Replace("<<dog_name>>", dogProperty.dog_name);
+            MessageBoxController.ShowMessage(msg);
+        }
     }
 
     // ConfirmClick点击后第一步POST事件
     void ConfirmClickPost()
     {
-        string url = "/api/initial/puppy/";
+        string url = "/api/initial/dog/";
         Dictionary<string, string> formData = new Dictionary<string, string>();
         WWWForm wwwForm = new WWWForm();
         wwwForm.AddField("user_id", UserProperty.userId);
-        wwwForm.AddField("dog_name", dogProperty.name);
-        wwwForm.AddField("dog_sex", dogProperty.sex);
-        wwwForm.AddField("dog_breed", dogProperty.breed);
-        wwwForm.AddField("dog_skin", dogProperty.skin);
+        wwwForm.AddField("dog_name", dogProperty.dog_name);
+        wwwForm.AddField("sex", dogProperty.sex);
+        wwwForm.AddField("breed", dogProperty.breed);
+        wwwForm.AddField("skin", dogProperty.skin);
 
         StartCoroutine(WebController.PostRequest(url, wwwForm, callback: ConfirmClickCallback));
     }
@@ -150,7 +182,13 @@ public class InitDogUIController : MonoBehaviour
     // ConfirmClick点击后POST数据返回后Callback
     void ConfirmClickCallback(string json)
     {
-
+        var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
+        if (data != null && data["status"] == "success")
+        {
+            string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "dog_create_success", EnviromentSetting.languageCode });
+            msg.Replace("<<dog_name>>", dogProperty.dog_name);
+            MessageBoxController.ShowMessage(msg, ()=> SceneManager.LoadScene("Home"));
+        }
     }
 
     // 绑定取消按键

+ 19 - 7
Assets/Scripts/Login/LoginController.cs

@@ -12,6 +12,7 @@ using TMPro;
  * TestDataInjection 是测试用的假数据注入
  * LoginTokenCheck 验证login token是否有效,和服务器比对
  * 比较版本是否可以符合游戏可以允许最低版本
+ * 弹出用户注册窗口
  */
 public class LoginController : MonoBehaviour
 {
@@ -33,7 +34,7 @@ public class LoginController : MonoBehaviour
         else
         {
             //启动自动采用Login Token 登录。其他登录方式为手动登录。
-            StartCoroutine(LoginTokenPost());
+            StartCoroutine(LoginTokenRequest());
         }
     }
 
@@ -45,9 +46,9 @@ public class LoginController : MonoBehaviour
 
 
     // LoginToken登录方法
-    IEnumerator LoginTokenPost()
+    IEnumerator LoginTokenRequest()
     {
-        //yield return null;      // 跳过第一帧(可以考虑去掉,数据加载已经移到awake()了。
+        Debug.Log("LoginToken Request start");
         string UUID = SystemInfo.deviceUniqueIdentifier; // 这里需要考虑这段代码执行在Enviroment Controller之前
         string LoginToken = PlayerPrefs.GetString("LoginToken", null);
         string LoginTokenTime = PlayerPrefs.GetString("LoginTokenTime", null);
@@ -97,6 +98,7 @@ public class LoginController : MonoBehaviour
         var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
         if (data != null && data["status"] == "success")
         {
+            Debug.Log("Login Token sucess!");
             PlayerPrefs.SetString("LoginToken", data["login_token"]);
             PlayerPrefs.SetString("LoginTokenTime", DateTime.Now.ToString());
             EnviromentSetting.accessToken = data["access_token"];
@@ -150,6 +152,7 @@ public class LoginController : MonoBehaviour
 
     IEnumerator GetUserData()
     {
+        Debug.Log("GetUserData request");
         yield return null;      // 跳过第一帧
         // 提交POST
         string url = "/api/user/info/";
@@ -166,13 +169,13 @@ public class LoginController : MonoBehaviour
             var user_info = JsonConvert.DeserializeObject<Dictionary<string, string>>(data["user_info"].ToString());
 
             UserProperty.name = user_info["user_name"];
-            //UserProperty.coin = int.Parse(user_info["coin"]);
+            UserProperty.coin = int.Parse(user_info["coin"]);
             UserProperty.mobile = user_info["mobile"];
             UserProperty.email = user_info["email"];
             UserProperty.level = user_info["level"];
             UserProperty.isRegUser = bool.Parse(user_info["isRegUser"]);
 
-            // todo 保存狗的数据
+            // 保存狗的数据
             DogProperty[] dogProperties = JsonConvert.DeserializeObject<DogProperty[]>(data["dogs"].ToString());
             foreach (var dog in dogProperties)
             {
@@ -184,10 +187,17 @@ public class LoginController : MonoBehaviour
             {
                 SwitchToInitDogScene();
             }
+            else if (!UserProperty.isRegUser)
+            {
+
+                // 如果非注册用户,提示用户注册
+                string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "reg_reminder", EnviromentSetting.languageCode });
+                MessageBoxController.YorN_Message(msg, ()=> regCanvas.SetActive(true), ()=> SceneManager.LoadScene("Home"));
+
+            }
             else
             {
                 SceneManager.LoadScene("Home");
-
             }
         }else{
             Debug.Log(data["message"]);
@@ -195,9 +205,11 @@ public class LoginController : MonoBehaviour
         
     }
 
+
     // Quick Start 登录方式,用UUID换取Login Token
     public void QuickStart()
     {
+        Debug.Log("Quick start post request.");
         string url = "/api/game/quick_start/";
         Dictionary<string, string> formData = new();
         WWWForm form = new();
@@ -213,7 +225,7 @@ public class LoginController : MonoBehaviour
             PlayerPrefs.SetString("LoginToken", data["login_token"]);
             PlayerPrefs.SetString("LoginTokenTime", DateTime.Now.ToString());
             UserProperty.userId = data["user_id"];
-            StartCoroutine(LoginTokenPost());
+            StartCoroutine(LoginTokenRequest());
         }
         else
         {

+ 78 - 11
Assets/Scripts/Login/RegisterUIController.cs

@@ -1,7 +1,10 @@
-using System.Collections;
+using Newtonsoft.Json;
+using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Net.Mail;
 using UnityEngine;
+using UnityEngine.SceneManagement;
 using UnityEngine.UIElements;
 
 
@@ -21,6 +24,8 @@ public class RegisterUIController : MonoBehaviour
     private string errorText = null;      // 错误信息汇总
     private Dictionary<string, string> errorMessageDict = new();
     // Start is called once before the first execution of Update after the MonoBehaviour is created
+
+    private Dictionary<string, string> regTempInfo = new();     // 临时保存登录信息
     void Start()
     {
         var root = GetComponent<UIDocument>().rootVisualElement;
@@ -51,23 +56,84 @@ public class RegisterUIController : MonoBehaviour
         Debug.Log("confirm btn clicked.");
         if (ContentCheckBeforePost())
         {
-            StartCoroutine(Register());
+            // 清空注册暂存数据
+            regTempInfo.Clear();
+
+            // POST数据到服务器
+            string url = "/api/user/register/";
+            Dictionary<string, string> formData = new();
+            WWWForm form = new();
+            form.AddField("UUID", EnviromentSetting.UUID);
+            if (EnviromentSetting.languageCode == "zh-cn")
+            {
+                form.AddField("mobile_number", mobile.text);
+                regTempInfo.Add("mobile_number", mobile.text);
+            }
+            else
+            {
+                form.AddField("email", email.text);
+                regTempInfo.Add("email", email.text);
+            }
+            form.AddField("password", password.text);
+            form.AddField("user_name", userName.text);
+            regTempInfo.Add("user_name", userName.text);
+            form.AddField("user_id", UserProperty.userId);
+            form.AddField("client_language", EnviromentSetting.languageCode);
+            StartCoroutine(WebController.PostRequest(url, form, callback: ConfirmClickCallback));
+        }
+    }
+
+    void ConfirmClickCallback(string json) {
+        var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
+        if (data != null && data["status"] == "success")
+        {
+            UserProperty.isRegUser = true;
+            UserProperty.name = regTempInfo["user_name"];
+            if (regTempInfo.TryGetValue("mobile_number", out string mobile))
+            {
+                UserProperty.mobile = mobile;
+            }
+            if ((regTempInfo.TryGetValue("email", out string email)))
+            {
+                UserProperty.email = email;
+            }
+            string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "register_success", EnviromentSetting.languageCode });
+            MessageBoxController.ShowMessage(msg, () => SceneManager.LoadScene("Home"));
+        }
+        else if (data != null && data["status"] == "register fail")
+        {
+            // TODO 注册失败动作
+
+            errorText = string.Empty;       // 清空
+
+            if (data["message"] == "duplicated mobile phone")
+            {
+                errorText += errorMessageDict["duplicated_mobile"];
+                errorText += "<br>";
+            }
+            if (data["message"] == "duplicated mobile phone")
+            {
+                errorText += errorMessageDict["duplicated_mobile"];
+                errorText += "<br>";
+            }
+
+            errorMsgLabel.text = errorText;
         }
+       
     }
 
     // 绑定取消按键
     void CancelClick()
     {
-        var RegCanvas = GameObject.Find("Register Canvas");
-        RegCanvas.SetActive(false);
-    }
+        //var RegCanvas = GameObject.Find("Register Canvas");
+        //RegCanvas.SetActive(false);
 
-    // POST数据到服务器
-    IEnumerator Register()
-    {
-        yield return null;
+        SceneManager.LoadScene("Home");
     }
 
+    
+
+
     // 初始化语言和显示设定
     void InitSetting()
     {
@@ -84,8 +150,8 @@ public class RegisterUIController : MonoBehaviour
         mobile.label = textValue;
         textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "registerUI", "label", "email", EnviromentSetting.languageCode });
         email.label = textValue;
-        textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "registerUI", "error_msg", "duplicated_user_name", EnviromentSetting.languageCode });
-        errorMessageDict.Add("duplicated_user_name", textValue);
+        textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "registerUI", "error_msg", "duplicated_mobile", EnviromentSetting.languageCode });
+        errorMessageDict.Add("duplicated_mobile", textValue);
         textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "registerUI", "error_msg", "user_name_is_empty", EnviromentSetting.languageCode });
         errorMessageDict.Add("user_name_is_empty", textValue);
         textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "registerUI", "error_msg", "password_too_short", EnviromentSetting.languageCode });
@@ -123,6 +189,7 @@ public class RegisterUIController : MonoBehaviour
     // POST之前的输入内容检测
     private bool ContentCheckBeforePost()
     {
+        errorText = string.Empty;       // 清空
         if (string.IsNullOrWhiteSpace(userName.value))
         {
             errorText += errorMessageDict["user_name_is_empty"];

+ 3 - 3
Assets/Scripts/Playground/PlayToyController.cs

@@ -87,8 +87,8 @@ public class PlayToyController : MonoBehaviour
             float aspectRatio = screenWidth / screenHeight;
 
             Debug.Log("屏幕宽高比: " + aspectRatio);
-            xForce = (mouseEndPosition.x - mouseStartPosition.x)/throwTime/forceAdjust*aspectRatio;
-            yForce = (mouseEndPosition.y - mouseStartPosition.y)/throwTime/forceAdjust*aspectRatio;
+            xForce = (mouseEndPosition.x - mouseStartPosition.x) / throwTime / forceAdjust * aspectRatio;
+            yForce = (mouseEndPosition.y - mouseStartPosition.y) / throwTime / forceAdjust * aspectRatio;
             Debug.Log("xForce is: " + xForce);
             Debug.Log("yForce is: " + yForce);
             if (yForce > 1 && yForce > xForce*0.5f) // 确保是向前飞出飞盘
@@ -163,7 +163,7 @@ public class PlayToyController : MonoBehaviour
             // 平滑旋转到目标方向
             //dog.transform.rotation = Quaternion.RotateTowards(dog.transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
 
-            float dogSpeed = (100+dogProperty.runSpeed)/20;   // 狗向飞盘移动
+            float dogSpeed = (100 + dogProperty.runSpeed) / 10;   // 狗向飞盘移动
             dog.transform.position = Vector3.MoveTowards(dog.transform.position, targetPosition, dogSpeed * Time.deltaTime);
 
             // 狗切换到跑步状态