Browse Source

5/5 更新

2025/5/2 添加用户反馈功能,待后台开发完成后验证
增加login home场景退出游戏按键
2025/5/5 增加长按狗的名字后直接进入交互模式。为将来手势控制准备
修改用户反馈页面
初步完成Gesture基础类的设计
Jees 1 month ago
parent
commit
2717047f5d

BIN
Assets/Pictures/quit.png


+ 166 - 0
Assets/Pictures/quit.png.meta

@@ -0,0 +1,166 @@
+fileFormatVersion: 2
+guid: cd0b7f033ffb46346b2c4d0d11593000
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 13
+  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
+    flipGreenChannel: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  ignoreMipmapLimit: 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: 2
+  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
+  swizzle: 50462976
+  cookieLightType: 0
+  platformSettings:
+  - serializedVersion: 4
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    ignorePlatformSupport: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 4
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    ignorePlatformSupport: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 4
+    buildTarget: Android
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    ignorePlatformSupport: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 4
+    buildTarget: iOS
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    ignorePlatformSupport: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites:
+    - serializedVersion: 2
+      name: quit_0
+      rect:
+        serializedVersion: 2
+        x: 0
+        y: 0
+        width: 64
+        height: 64
+      alignment: 0
+      pivot: {x: 0, y: 0}
+      border: {x: 0, y: 0, z: 0, w: 0}
+      customData: 
+      outline: []
+      physicsShape: []
+      tessellationDetail: 0
+      bones: []
+      spriteID: 8b93c991907e0f344aa723e5ad4f6fcd
+      internalID: -619603777
+      vertices: []
+      indices: 
+      edges: []
+      weights: []
+    outline: []
+    customData: 
+    physicsShape: []
+    bones: []
+    spriteID: 85eb26b40b602e94480c1dbb14882976
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    spriteCustomMetadata:
+      entries: []
+    nameFileIdTable:
+      quit_0: -619603777
+  mipmapLimitGroupName: 
+  pSDRemoveMatte: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 5 - 1
Assets/Resources/Data/languages.json

@@ -386,6 +386,10 @@
             "en": "Try to touch the dog. He will be very happy.",
             "zh-cn": "尝试抚摸一下狗狗吧。他会很开心。"
         },
+        "quit_game": {
+            "en": "Are you sure to quit the game?",
+            "zh-cn": "确定要退出游戏吗?"
+        },
 
 
 
@@ -927,7 +931,7 @@
             }
         },
         "message":{
-            "thanks for feedback":{
+            "success":{
                 "en": "Thanks for your feedback. We will response as soon as possible.",
                 "zh-cn": "感谢你的反馈,我们会尽快处理。"
             }

+ 1 - 1
Assets/Resources/Dog/AnimatorController/shibaInu/HomeDogInteractController.controller

@@ -607,7 +607,7 @@ AnimatorController:
     m_DefaultInt: 0
     m_DefaultBool: 0
     m_Controller: {fileID: 9100000}
-  - m_Name: isListening
+  - m_Name: Listen_status
     m_Type: 4
     m_DefaultFloat: 0
     m_DefaultInt: 0

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

@@ -27,7 +27,7 @@ RectTransform:
   m_GameObject: {fileID: 284393600326528666}
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
-  m_LocalScale: {x: 2.2, y: 2.2, z: 2.2}
+  m_LocalScale: {x: 1.8, y: 1.8, z: 1.8}
   m_ConstrainProportionsScale: 1
   m_Children: []
   m_Father: {fileID: 4128633789988152547}
@@ -58,14 +58,14 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_Material: {fileID: 0}
-  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_Color: {r: 0.9254902, g: 0.2627451, b: 0.14509803, a: 0.78431374}
   m_RaycastTarget: 1
   m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
   m_Maskable: 1
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_Sprite: {fileID: 21300000, guid: 02d7eecdf152b2648ae5f0410cbb46c4, type: 3}
+  m_Sprite: {fileID: 21300120, guid: 1eaee135ce037439d925cee5e41ce026, type: 3}
   m_Type: 0
   m_PreserveAspect: 0
   m_FillCenter: 1
@@ -347,14 +347,14 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_Material: {fileID: 0}
-  m_Color: {r: 0.053106308, g: 1, b: 0, a: 0.78431374}
+  m_Color: {r: 1, g: 1, b: 1, a: 0}
   m_RaycastTarget: 1
   m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
   m_Maskable: 1
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
+  m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
   m_Type: 1
   m_PreserveAspect: 0
   m_FillCenter: 1
@@ -853,7 +853,7 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_Material: {fileID: 0}
-  m_Color: {r: 1, g: 0.08880368, b: 0, a: 0.78431374}
+  m_Color: {r: 1, g: 1, b: 1, a: 0}
   m_RaycastTarget: 1
   m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
   m_Maskable: 1
@@ -1304,7 +1304,7 @@ RectTransform:
   m_GameObject: {fileID: 8936560037696320555}
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
-  m_LocalScale: {x: 2.2, y: 2.2, z: 2.2}
+  m_LocalScale: {x: 1.8, y: 1.8, z: 1.8}
   m_ConstrainProportionsScale: 1
   m_Children: []
   m_Father: {fileID: 2137355296810040006}
@@ -1335,14 +1335,14 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   m_Material: {fileID: 0}
-  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_Color: {r: 0.053106308, g: 1, b: 0, a: 0.78431374}
   m_RaycastTarget: 1
   m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
   m_Maskable: 1
   m_OnCullStateChanged:
     m_PersistentCalls:
       m_Calls: []
-  m_Sprite: {fileID: 21300000, guid: 52c5e15b626e53e43a2a3e8d9919cfa5, type: 3}
+  m_Sprite: {fileID: 21300118, guid: 1eaee135ce037439d925cee5e41ce026, type: 3}
   m_Type: 0
   m_PreserveAspect: 0
   m_FillCenter: 1

+ 78 - 26
Assets/Resources/VoiceAndManu/MenuController.cs

@@ -13,7 +13,7 @@ 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 VisualElement mainMenu, dogIcon, dogList, quit;
     private List<VisualElement> subMenu = new();
     //private bool isSubMenuShow = false;
     private GameObject uiPlaceholder;       // Manu会控制其他子菜单显示和隐藏,因此所有子菜单都必须挂载在UI Placeholder下
@@ -24,6 +24,8 @@ public class MenuController : MonoBehaviour
     private static bool isMenuShowed = false;        // 右侧子菜单是否展开
     private static DateTime menuShowTime;        // 菜单展开时间
 
+    private float longPressTime = 1.0f; // 长按时间阈值
+    private float dogNamePressStartTime;
     void OnEnable()
     {
         // 找到需要控制的其他子菜单
@@ -67,16 +69,18 @@ public class MenuController : MonoBehaviour
         //var root = GetComponent<UIDocument>().rootVisualElement;
         dogIcon = root.Q<VisualElement>("dogMenu").Q<VisualElement>("dogIcon");
         dogList = root.Q<VisualElement>("dogMenu").Q<VisualElement>("dogList");
+        quit = root.Q<VisualElement>("quit");
+        quit.RegisterCallback<ClickEvent>(e => QuitClick());       // 退出游戏按钮
 
         DogNameInit();      // 初始化狗的名字,这里当菜单重新激活后再次加载
 
         dogIcon.RegisterCallback<ClickEvent>(e => DogIconClick(e));
 
-        // 根据配置隐藏一些菜单
-        if (UserProperty.dogs.Count == 1)
-        {
-            dogIcon.visible = false;
-        }
+        // 如果狗的数量小于2只,隐藏狗的图标
+        //if (UserProperty.dogs.Count == 1)
+        //{
+        //    dogIcon.visible = false;
+        //}
         if (UserProperty.isRegUser == false)
         {
             // home.style.display = DisplayStyle.None;
@@ -137,7 +141,7 @@ public class MenuController : MonoBehaviour
         // curAngle 初始角度,angleDelta 2个子菜单之间角度,distance 弹出距离,showTimer 显示时间
         float curAngle = 100f;
         // float angleDelta = 40f;
-        float angleDelta = 200/subMenu.Count;
+        float angleDelta = 200 / subMenu.Count;
         float distance = 70f;
         //float showTimer = 3.0f;
         foreach (var menu in subMenu)
@@ -218,6 +222,16 @@ public class MenuController : MonoBehaviour
     }
     #endregion
 
+
+
+    private void QuitClick()
+    {
+        string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "quit_game", EnviromentSetting.languageCode });
+        MessageBoxController.YorN_Message(msg, () => Application.Quit());
+    }
+
+
+    #region 左侧菜单控制
     void DogIconClick(ClickEvent e)
     {
         Debug.Log("DogIconClick");
@@ -232,32 +246,69 @@ public class MenuController : MonoBehaviour
 
     }
 
-
-    #region 左侧菜单控制
     // 点击狗的名字时候处理
-    void DogNameClick(ClickEvent e, int index)
+    void DogNamePointDown(PointerDownEvent e, int index)
+    {
+        dogNamePressStartTime = Time.unscaledTime; // 记录按下时间
+    }
+    void DogNamePressUP(PointerUpEvent e, int index)
     {
         GameData.focusDog = index;
-        if (GameData.homeCamFocusDog == index)
+        //Debug.Log("e delta time=" + e.);
+        float deltaTime = Time.unscaledTime - dogNamePressStartTime;
+        Debug.Log("delta time is:" + deltaTime.ToString());
+        if (deltaTime < longPressTime)
         {
-            // 重复点击狗的名字,恢复广角,所有狗的名字显示一样大小
-            HomeController.dogCam.Priority = 1;
-            HomeController.playerCam.Priority = 10;
-            GameData.homeCamFocusDog = 100;     // 100表示不聚焦
-            //dogNames[index].transform.scale = new Vector2(1f, 1f);
-
+            // 短按效果,切换狗的名字
+            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;
+            }
         }
         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;
+            // 长按效果,进入互动模式
+            HomeController.Instance.SetSceneMode(SceneMode.INACTIVE);
+            HomeController.Instance.VoiceButtonOnlySwitch(true);
+            string focusDogId = UserProperty.GetDogIdByIndex(index);
+            foreach (var dog in HomeController.dogsInScene)
+            {
+                if (dog.dogProperty.d_id == focusDogId)
+                {
+                    // if (GameTool.Random100Check(dog.dogProperty.voiceCall))
+                    // {
+                    // dog.SetupInteract();
+                    HomeController.Instance.SetInteractDog(dog.gameObject);
+                    // focusdog 开启互动模式
+                    // HomeController.dogsInScene[GameData.focusDog].dogState = DogState.INTERACT;
+                    HomeController.dogsInScene[GameData.focusDog].SetupInteract();
+                    // 其他狗进入隐藏模式
+                    foreach (var otherDog in HomeController.dogsInScene)
+                    {
+                        if (otherDog.dogProperty.d_id != focusDogId)
+                        {
+                            otherDog.gameObject.SetActive(false);
+                        }
+                    }
+                }
+            }
+            HomeSoundEffectController.Instance.PlaySoundEffect(5);
         }
-        
-        if (dogList.visible == true) { dogList.visible = false; }   
+
+        if (dogList.visible == true) { dogList.visible = false; }
     }
 
     // 初始化狗的名字
@@ -275,7 +326,8 @@ public class MenuController : MonoBehaviour
             int index = i;
             dogNames[i].style.display = DisplayStyle.Flex;
             dogNames[i].text = UserProperty.dogs[i].dog_name;
-            dogNames[i].RegisterCallback<ClickEvent>(e => DogNameClick(e, index));
+            dogNames[i].RegisterCallback<PointerUpEvent>(e => DogNamePressUP(e, index));
+            dogNames[i].RegisterCallback<PointerDownEvent>(e => DogNamePointDown(e, index));
         }
     }
 

+ 1 - 0
Assets/Resources/VoiceAndManu/VoiceAndMenu.uxml

@@ -1,6 +1,7 @@
 <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
     <Style src="project://database/Assets/Resources/VoiceAndManu/VoiceAndMenu.uss?fileID=7433441132597879392&amp;guid=ce67c533d6e849b47862283007c81f9a&amp;type=3#VoiceAndMenu" />
     <ui:VisualElement style="flex-grow: 1; background-size: 300% 100%;">
+        <ui:VisualElement name="quit" style="flex-grow: 1; position: absolute; top: 20px; right: 20px; background-image: url(&quot;project://database/Assets/Pictures/quit.png?fileID=2800000&amp;guid=cd0b7f033ffb46346b2c4d0d11593000&amp;type=3#quit&quot;); width: 30px; height: 30px; -unity-background-image-tint-color: rgb(24, 24, 24);" />
         <ui:VisualElement name="menuArea" style="flex-grow: 1; position: absolute; top: 360px; right: 0; width: 150px; height: 150px; visibility: visible;">
             <ui:VisualElement name="shop" class="subMenu" style="background-image: url(&quot;project://database/Assets/Pictures/menu%20icons/shop.png?fileID=2800000&amp;guid=6866a7131c552244286e086c0f3c0d71&amp;type=3#shop&quot;); top: 103px; left: 38px; display: flex;" />
             <ui:VisualElement name="warehouse" class="subMenu" style="background-image: url(&quot;project://database/Assets/Pictures/menu%20icons/box.png?fileID=2800000&amp;guid=e023858a18ba6044aac5f01454022545&amp;type=3#box&quot;); top: 71px; left: 29px;" />

+ 4 - 1
Assets/Resources/VoiceAndManu/VoiceController.cs

@@ -42,20 +42,23 @@ public class VoiceController : MonoBehaviour
     }
 
     // 只显示语音菜单
-    public void VoiceOnlyCheck()
+    private void VoiceOnlyCheck()
     {
         var root = GetComponent<UIDocument>().rootVisualElement;
         var menuArea = root.Q<VisualElement>("menuArea");
         var dogMenu = root.Q<VisualElement>("dogMenu");
+        var quit = root.Q<VisualElement>("quit");
         if (isCommandMode)
         {
             menuArea.style.display = DisplayStyle.None;
             dogMenu.style.display = DisplayStyle.None;
+            quit.style.display = DisplayStyle.None;
         }
         else
         {
             menuArea.style.display = DisplayStyle.Flex;
             dogMenu.style.display = DisplayStyle.Flex;
+            quit.style.display = DisplayStyle.Flex;
         }
     }
 

+ 1 - 1
Assets/Scenes/Home.unity

@@ -910,7 +910,7 @@ GameObject:
   m_Icon: {fileID: 0}
   m_NavMeshLayer: 0
   m_StaticEditorFlags: 0
-  m_IsActive: 1
+  m_IsActive: 0
 --- !u!224 &325322583
 RectTransform:
   m_ObjectHideFlags: 0

+ 2 - 2
Assets/Scenes/Home_Profiles/User Feedback UI/User Feedback.uxml

@@ -1,8 +1,8 @@
 <ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
     <Style src="project://database/Assets/UI%20Toolkit/Style/rootStyle.uss?fileID=7433441132597879392&amp;guid=b30eb17a0ca8bf64087af4e59d565fdd&amp;type=3#rootStyle" />
-    <ui:VisualElement class="rootStyle" style="flex-grow: 1;">
+    <ui:VisualElement class="rootStyle" style="flex-grow: 1; background-image: url(&quot;project://database/Assets/Pictures/Login/mailbox.png?fileID=2800000&amp;guid=2a15d5247bbd45e4c8ad28ecec71f99e&amp;type=3#mailbox&quot;);">
         <ui:DropdownField label="&lt;type&gt;" name="type" class="dropdownField" />
-        <ui:TextField label="&lt;feedback&gt;" name="feedback" class="textField__multiline" />
+        <ui:TextField label="&lt;feedback&gt;" name="feedback" multiline="true" max-length="140" class="textField__multiline" style="white-space: normal;" />
         <ui:VisualElement style="flex-grow: initial; flex-direction: row; flex-shrink: initial; justify-content: space-evenly;">
             <ui:Button text="&lt;submit&gt;" name="submit" class="button" style="align-self: center; background-color: rgba(0, 0, 255, 0.78); color: rgb(255, 255, 255);" />
             <ui:Button text="&lt;cancel&gt;" name="cancel" class="button" style="align-self: center; background-color: rgba(255, 255, 255, 0.78);" />

+ 133 - 0
Assets/Scenes/Login.unity

@@ -3838,6 +3838,7 @@ RectTransform:
   - {fileID: 1139328082}
   - {fileID: 952681667}
   - {fileID: 497859296}
+  - {fileID: 1430539167}
   m_Father: {fileID: 1751824541}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 0}
@@ -4048,6 +4049,138 @@ Canvas:
   m_SortingLayerID: 0
   m_SortingOrder: 0
   m_TargetDisplay: 0
+--- !u!1 &1430539166
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1430539167}
+  - component: {fileID: 1430539170}
+  - component: {fileID: 1430539169}
+  - component: {fileID: 1430539168}
+  m_Layer: 5
+  m_Name: Quit
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1430539167
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1430539166}
+  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: 1349309768}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 111, y: 271}
+  m_SizeDelta: {x: 30, y: 30}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1430539168
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1430539166}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 1430539169}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 1349309770}
+        m_TargetAssemblyTypeName: LoginController, Assembly-CSharp
+        m_MethodName: ShutDown
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!114 &1430539169
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1430539166}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: -619603777, guid: cd0b7f033ffb46346b2c4d0d11593000, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1430539170
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1430539166}
+  m_CullTransparentMesh: 1
 --- !u!1001 &1589749813
 PrefabInstance:
   m_ObjectHideFlags: 0

+ 1 - 1
Assets/Scenes/Home.meta → Assets/Scripts/Functions/Gesture.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 9df56ba27e6c3734e9989e978dc856a3
+guid: d349ce5452407994db317afa7ff4b718
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}

+ 96 - 0
Assets/Scripts/Functions/Gesture/GestureController.cs

@@ -0,0 +1,96 @@
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Net.Sockets;
+using UnityEngine;
+
+/* 本文件用于控制手势的采集和比对
+ * 也包含导出和导入手势的功能
+*/
+public class GestureController
+{
+    // Start is called once before the first execution of Update after the MonoBehaviour is created
+    private List<GesturePointOffset> gesturePointOffsetList = new List<GesturePointOffset>();
+    public int sampleRate { private set; get; } = 10;        // 采样率
+    private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点
+    private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点
+
+    public string ExportToJson()
+    {
+        string json = string.Empty;
+        if (gesturePointOffsetList.Count / 2 <= sampleRate) { return json; }
+        json = JsonConvert.SerializeObject(this);
+        return json;
+    }
+
+    public void ImportFromJson(string json)
+    {
+        var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
+        this.sampleRate = int.Parse(data["sample_rate"]);
+        gesturePointOffsetList.Clear();
+        GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject<GesturePointOffset[]>(data["points"]);
+        foreach (var point in pointOffsets)
+        {
+            gesturePointOffsetList.Add(point);
+        }
+    }
+
+    // 添加一个运动轨迹
+    public void AddGesturePoint(Vector2 pointLoc)
+    {
+        if (gesturePointOffsetList.Count == 0)
+        {
+            prePointLoc = pointLoc;
+            curPointLoc = pointLoc;
+            GesturePointOffset gesturePointMovement = new GesturePointOffset(0, 0);
+            gesturePointOffsetList.Add(gesturePointMovement);
+            return;
+        }
+        else
+        {
+            curPointLoc = pointLoc;
+            float distance = Vector2.Distance(prePointLoc, curPointLoc);
+            float angle = Vector2.Angle(prePointLoc, curPointLoc);
+            GesturePointOffset gesturePointMovement = new GesturePointOffset(distance, angle);
+            gesturePointOffsetList.Add(gesturePointMovement);
+            prePointLoc = curPointLoc;
+        }
+    }
+
+    public float CompareGesture(GestureController anotherGesture)
+    {
+        float score = 0f;
+        if (this.sampleRate != anotherGesture.sampleRate)
+        {
+            Debug.Log("Sample rate not match");
+            return -1f;
+        }
+
+        int maxGesturePoints = Mathf.Max(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
+        int minGesturePoints = Mathf.Min(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
+        for (int i = 0; i < minGesturePoints; i++)
+        {
+
+            float ditanceMin = Mathf.Min(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
+            float ditanceMax = Mathf.Max(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
+            float distanceScore = ditanceMin / ditanceMax;
+
+            float angleMin = Mathf.Min(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
+            float angleMax = Mathf.Max(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
+            float angleDitance1 = angleMax - angleMin;
+            float angleDitance2 = 360 - angleDitance1;
+            float angleScore = 1 - (Mathf.Min(angleDitance1, angleDitance2) / 180);
+
+            score = score * (i / (i + 1)) + (distanceScore + angleScore) / 2 * (1f / (i + 1));
+        }
+
+        // 如果长度超过20%,就要考虑调整score
+        if ((maxGesturePoints / minGesturePoints) > 1.2f)
+        {
+            int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * 1.2f);
+            score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints));
+        }
+
+        return score;
+    }
+}

+ 2 - 0
Assets/Scripts/Functions/Gesture/GestureController.cs.meta

@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 98e40fd99e2fdfb4e91b78f7291ad5e0

+ 35 - 0
Assets/Scripts/Functions/Gesture/GesturePointOffset.cs

@@ -0,0 +1,35 @@
+using UnityEngine;
+using Newtonsoft.Json;
+
+/* GesturePointOffset 每一个定位点相对于上一个定位点的偏移量
+ */
+public class GesturePointOffset
+
+{
+    public float distance { set; get; } = 0f; // 两个点之间的距离
+    public float angle { set; get; } = 0f;// 两个点之间的角度
+
+
+    public GesturePointOffset(float distance, float angle)
+    {
+        this.distance = distance;
+        this.angle = angle;
+    }
+    public string ExportToJson()
+    {
+        string json = JsonConvert.SerializeObject(this);
+        return json;
+    }
+
+    public void ImportFromJson(string json)
+    {
+        var deserializedObject = JsonConvert.DeserializeObject<GesturePointOffset>(json);
+        if (deserializedObject != null)
+        {
+            // 手动将反序列化后的对象的属性值复制到当前实例
+            this.distance = deserializedObject.distance;
+            this.angle = deserializedObject.angle;
+        }
+    }
+}
+

+ 2 - 0
Assets/Scripts/Functions/Gesture/GesturePointOffset.cs.meta

@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: dafa5ad9cdfc96549a4c01418ec5fc2c

+ 2 - 2
Assets/Scripts/GameControllers/GameTool.cs

@@ -85,12 +85,12 @@ public static class GameTool
     public static void ResumeGameTime()
     {
         Time.timeScale = 1;
-        Time.fixedDeltaTime = 0.02f * Time.timeScale;
+        //Time.fixedDeltaTime = 0.02f * Time.timeScale;
     }
     // 暂停游戏时间运行
     public static void PauseGameTime()
     {
         Time.timeScale = 0;
-        Time.fixedDeltaTime = 0.02f * Time.timeScale;
+        //Time.fixedDeltaTime = 0.02f * Time.timeScale;
     }
 }

+ 11 - 1
Assets/Scripts/Home/HomeController.cs

@@ -850,6 +850,10 @@ public class HomeController : MonoBehaviour
         interactTime = 0;
     }
 
+    public void SetInteractDog(GameObject dog)
+    {
+        interactDog = dog;
+    }
     #endregion
 
     #region 场景环境控制
@@ -886,6 +890,12 @@ public class HomeController : MonoBehaviour
         }
     }
 
+    // 设置场景模式
+    public void SetSceneMode(SceneMode mode)
+    {
+        this.sceneMode = mode;
+    }
+
     // 刷新dogInScene的狗数据
     public void RefreshDogInScene()
     {
@@ -903,7 +913,7 @@ public enum ItemGroup
     water
 }
 
-enum SceneMode
+public enum SceneMode
 {
     TRAINING,
     INACTIVE,

+ 36 - 4
Assets/Scripts/Home/UserFeedbackController.cs

@@ -1,3 +1,5 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UIElements;
 
@@ -22,12 +24,13 @@ public class UserFeedbackController : MonoBehaviour
         InitSetting();
 
         cancel.RegisterCallback<ClickEvent>(ev => CancelClick());
+        submit.RegisterCallback<ClickEvent>(ev => SubmitRequest());
     }
 
     // Update is called once per frame
     void Update()
     {
-        if(feedback.text.Trim() == "")
+        if (feedback.text.Trim() == "")
         {
             submit.SetEnabled(false);
         }
@@ -37,7 +40,8 @@ public class UserFeedbackController : MonoBehaviour
         }
     }
 
-    void InitSetting(){
+    void InitSetting()
+    {
         string textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "FeedbackUI", "button", "submit", EnviromentSetting.languageCode });
         submit.text = textValue;
         textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "FeedbackUI", "button", "cancel", EnviromentSetting.languageCode });
@@ -56,9 +60,9 @@ public class UserFeedbackController : MonoBehaviour
         type.value = typeOption0;
     }
 
-     void CancelClick()
+    void CancelClick()
     {
-         HomeSoundEffectController.Instance.PlaySoundEffect(2);
+        HomeSoundEffectController.Instance.PlaySoundEffect(2);
 
         var uiPlaceholder = GameObject.Find("UI Placeholder");
         if (uiPlaceholder != null)
@@ -69,4 +73,32 @@ public class UserFeedbackController : MonoBehaviour
             UserInfoUI.SetActive(false);
         }
     }
+
+    void SubmitRequest()
+    {
+        Debug.Log("Feedback Submit request");
+
+        string url = "/api/user/feedback/";
+        WWWForm form = new();
+        form.AddField("user_id", UserProperty.userId);
+        form.AddField("type", type.value);
+        form.AddField("feedback", feedback.text);
+
+        StartCoroutine(WebController.PostRequest(url, form, callback: SubmitCallback));
+    }
+
+    void SubmitCallback(string json)
+    {
+        var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
+        if (data != null && data["status"] == "success")
+        {
+            string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "FeedbackUI", "message", "success", EnviromentSetting.languageCode });
+            MessageBoxController.ShowMessage(msg, () => CancelClick());
+        }
+        else
+        {
+            Debug.Log("Login Token fail!");
+            Debug.Log(json);
+        }
+    }
 }

+ 44 - 22
Assets/Scripts/Login/LoginController.cs

@@ -26,7 +26,7 @@ public class LoginController : MonoBehaviour
         createAdoptCanvas = canvasPlaceholder.transform.Find("Create Or Adopt Canvas").gameObject;
         loginCanvas = canvasPlaceholder.transform.Find("Login Canvas").gameObject;
         // 判断是否要切换到注册狗的子场景
-        if ( GameData.subScene == "Login_InitDog")
+        if (GameData.subScene == "Login_InitDog")
         {
             SwitchToInitDogScene();
             GameData.subScene = null;
@@ -41,7 +41,7 @@ public class LoginController : MonoBehaviour
     // Update is called once per frame
     //void Update()
     //{
-        
+
     //}
 
 
@@ -54,14 +54,16 @@ public class LoginController : MonoBehaviour
         string LoginTokenTime = PlayerPrefs.GetString("LoginTokenTime", null);
 
         // 比较LoginTokenTime 如果超时直接放弃后面代码。比较UUID是否是null如果是直接放弃后面代码
-        if (LoginToken == null) { yield break; };
-        if (LoginTokenTime == null) { yield break; };
+        if (LoginToken == null) { yield break; }
+        ;
+        if (LoginTokenTime == null) { yield break; }
+        ;
         DateTime tokenTime;
         DateTime now = DateTime.Now;
         if (DateTime.TryParse(LoginTokenTime, out tokenTime))
         {
             TimeSpan span = now - tokenTime;
-            if (span.TotalHours > 7 * 24)       
+            if (span.TotalHours > 7 * 24)
             {
                 yield break;
             }
@@ -74,7 +76,7 @@ public class LoginController : MonoBehaviour
         form.AddField("login_token", LoginToken);
         form.AddField("UUID", UUID);
 
-        StartCoroutine(WebController.PostRequest(url, form, callback:LoginTokenCallback));
+        StartCoroutine(WebController.PostRequest(url, form, callback: LoginTokenCallback));
     }
 
     // Post之后callback的函数
@@ -113,7 +115,8 @@ public class LoginController : MonoBehaviour
             Version curVer = new Version(current_ver);
             Version allowVer = new Version(allowed_client_ver);
             int verCompare = curVer.CompareTo(allowVer);
-            if (verCompare < 0) {
+            if (verCompare < 0)
+            {
                 // 弹窗,然后退出
                 string err_msg;
                 if (EnviromentSetting.platform == "IPhonePlayer")
@@ -141,13 +144,17 @@ public class LoginController : MonoBehaviour
                 MessageBoxController.ShowMessage(err_msg, ShutDown);
             }
         }
-
-        // 当版本检查不符合游戏时退出游戏
-        void ShutDown()
+        else
         {
-            Application.Quit();
+            Debug.Log("Login Token fail!");
+            Debug.Log(json);
         }
     }
+    // 当版本检查不符合游戏时退出游戏
+    public void ShutDown()
+    {
+        Application.Quit();
+    }
 
     IEnumerator GetUserData()
     {
@@ -188,19 +195,22 @@ public class LoginController : MonoBehaviour
                 loginCanvas.SetActive(false);
                 string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "reg_reminder", EnviromentSetting.languageCode });
                 //MessageBoxController.YorN_Message(msg, ()=> regCanvas.SetActive(true), ()=> SceneManager.LoadScene("Home"));
-                MessageBoxController.YorN_Message(msg, () => regCanvas.SetActive(true), ()=> MaskTransitions.TransitionManager.Instance.LoadLevel("Home"));
+                MessageBoxController.YorN_Message(msg, () => regCanvas.SetActive(true), () => MaskTransitions.TransitionManager.Instance.LoadLevel("Home"));
 
             }
             else
             {
                 ShowStartGameUI();
             }
-        }else{
+        }
+        else
+        {
             Debug.Log(data["message"]);
         }
     }
 
-    void ShowStartGameUI(){
+    void ShowStartGameUI()
+    {
         var uiPlaceholder = GameObject.Find("Canvas Placeholder");
         if (uiPlaceholder != null)
         {
@@ -275,27 +285,39 @@ public class LoginController : MonoBehaviour
         form.AddField("client_language", EnviromentSetting.languageCode);
         if (EnviromentSetting.languageCode == "zh-cn")
         {
-            form.AddField("mobile_number", account);
+            form.AddField("mobile_number", account.Trim());
         }
         else
         {
-            form.AddField("email", account);
+            form.AddField("email", account.Trim());
         }
-        form.AddField("password", password);
+        form.AddField("password", password.Trim());
         StartCoroutine(WebController.PostRequest(url, form, callback: LoginCallback));
     }
 
     void LoginCallback(string json)
     {
-        LoginSucessHandler(json);
-        if (UserProperty.userId != null && EnviromentSetting.accessToken != null)
+        var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
+        if (data != null && data["status"].ToString() == "success")
         {
-            // 启动获取用户信息请求
-            StartCoroutine(GetUserData());
+            LoginSucessHandler(json);
+            if (UserProperty.userId != null && EnviromentSetting.accessToken != null)
+            {
+                // 启动获取用户信息请求
+                StartCoroutine(GetUserData());
+            }
+            else
+            {
+                Debug.Log("LoginTokenCallback 登陆失败");
+                Debug.Log(json);
+            }
         }
         else
         {
-           // 处理登录失败
+            string errMsg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "game_message", "login_fail", EnviromentSetting.languageCode });
+            MessageBoxController.ShowMessage(errMsg);
         }
+
     }
+
 }

+ 12 - 7
Assets/UI Toolkit/Style/rootStyle.uss

@@ -38,7 +38,7 @@
     margin-bottom: 10px;
     margin-left: 10px;
     max-width: 100%;
-    text-valign: middle;
+    -unity-text-align: upper-left;
 }
 
 .textField {
@@ -73,16 +73,21 @@
     padding-right: 1px;
     padding-bottom: 1px;
     padding-left: 1px;
-    margin-top: -5px;
-    margin-right: 10px;
-    margin-bottom: 10px;
+    margin-top: 1px;
+    margin-right: 1px;
+    margin-bottom: 1px;
     margin-left: 0;
     max-width: 100%;
-    justify-content: flex-end;
-    min-width: 100%;
+    justify-content: flex-start;
+    /* min-width: 100%; */
     position: relative;
     min-height: 40px;
-    -unity-text-align: middle-left;
+    -unity-text-align: upper-left;
+}
+.textField__multiline > .unity-base-field__input >.unity-base-text-field__multiline-container{
+    /* margin-top: -15px; */
+    /* height: auto; */
+    /* height: 100px; */
 }
 
 .err_msg {