This commit is contained in:
王建超 2026-04-30 15:50:03 +08:00
parent 01916c83f6
commit f54c64f3ad
37 changed files with 2753 additions and 502 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 03811c703638b5144b2933c5b9877777
folderAsset: yes
DefaultImporter:
guid: c48874f905c2eef4fa0c3c2f643f7d22
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 35f6739f33351504f8f108636f5bf69f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -66,15 +66,7 @@ public class ChatUI : MonoBehaviour
thinking = value;
}
}
//private bool typing;
//public bool Typing
//{
// get { return typing; }
// set
// {
// typing = value;
// }
//}
private bool closed;
Action action;
private void Awake()
@ -162,7 +154,7 @@ public class ChatUI : MonoBehaviour
if (!string.IsNullOrEmpty(str))
{
Thinking = true;
ChatAI.Instance.SendData(Regex.Replace(str, @"[\p{P}\p{S}]", ""), str =>
ChatAI.Instance.SendData(str, str =>
{
Thinking = false;
wakeUpCurrentTime = 0;
@ -174,11 +166,8 @@ public class ChatUI : MonoBehaviour
}
else
{
//coroutine = StartCoroutine(TypeText(0.18f * str.Length, str, str => GenChatTxt(str), () => Typing = false));
GenChatTxt(str);
//Typing = false;
OnAppendMsg(0, MsgTypeEnum.Str, str);
//Typing = true;
ChatAI.Instance.PlayVoice(str, clip => {
audioSource.clip = clip;
audioSource.Play();
@ -196,7 +185,7 @@ public class ChatUI : MonoBehaviour
if (!string.IsNullOrEmpty(str))
{
Thinking = true;
ChatAI.Instance.SendData(Regex.Replace(str, @"[\p{P}\p{S}]", ""), str =>
ChatAI.Instance.SendData(str, str =>
{
Thinking = false;
wakeUpCurrentTime = 0;
@ -208,11 +197,8 @@ public class ChatUI : MonoBehaviour
}
else
{
//coroutine = StartCoroutine(TypeText(0.18f * str.Length, str, str => GenChatTxt(str), () => Typing = false));
GenChatTxtNext(str);
//Typing = false;
OnAppendMsg(0, MsgTypeEnum.Str, str);
//Typing = true;
ChatAI.Instance.PlayVoice(str, clip => {
audioSource.clip = clip;
audioSource.Play();
@ -242,7 +228,6 @@ public class ChatUI : MonoBehaviour
private void ResponseCallBack(string _response)
{
_response = _response.Trim();
//VoiceBtnEnable();
m_SendBtn.interactable = true;
if (!string.IsNullOrEmpty(_response))
{

View File

@ -1,22 +1,23 @@
using System.Collections;
using System.Collections.Generic;
// Sensor.cs
using UnityEngine;
/// <summary>
/// 传感器基类
/// </summary>
public abstract class Sensor : MonoBehaviour
{
SensorManager sensorManager;
public void Init(SensorManager sm)
{
sensorManager = sm;
}
public void SendData(string data)
{
sensorManager.SendFunction(data);
}
public virtual void ReceiveData(string datas)
// 修改:增加 portName 参数,用于区分数据来源
public virtual void ReceiveData(string datas, string portName)
{
if (!gameObject.activeSelf) return;
}
}
}

View File

@ -1,15 +1,14 @@
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;
public class TZQ_Sensor : Sensor
{
[SerializeField]
Text txt;
public int positionValue = 0;
public override void ReceiveData(string datas)
public override void ReceiveData(string datas,string portName)
{
base.ReceiveData(datas);
base.ReceiveData(datas, portName);
Regex regex = new Regex(@"Position:(\d+)");
Match match = regex.Match(datas);
if (match.Success)
@ -20,4 +19,4 @@ public class TZQ_Sensor : Sensor
}
}
}
}
}

View File

@ -1,12 +1,4 @@
using NAudio.Wave;
using System;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
/// <summary>
/// 语音工具
/// </summary>
@ -14,9 +6,9 @@ public class ZXKWakeup : Sensor
{
//唤醒词:小智小智
public Action callBack;//唤醒回调
public override void ReceiveData(string datas)
public override void ReceiveData(string datas, string portName)
{
base.ReceiveData(datas);
base.ReceiveData(datas, portName);
if (datas.TrimEnd('\n', '\r') == "hello")
{
callBack?.Invoke();

View File

@ -1,25 +1,21 @@
// SensorManager.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO.Ports;
using System.Text;
using System.Threading;
//using UnityEditor.PackageManager.UI;
using UnityEngine;
using UnityThreadingUtils;
using ZXKFramework;
public class SensorManager : MonoBehaviour /*MonoSingleton<SensorManager>*/
public class SensorManager : MonoBehaviour
{
public enum DataType
{
,
,
}
#region ,
[Header("串口名")]
public string portName = "COM10";
#region
[Header("波特率")]
public int baudRate = 115200;
[Header("奇偶校验")]
@ -28,31 +24,162 @@ public class SensorManager : MonoBehaviour /*MonoSingleton<SensorManager>*/
private int dataBits = 8;
[Header("停止位")]
private StopBits stopBits = StopBits.One;
SerialPort sp = null;
Thread dataReceiveThread;
[Header("接收数据格式")]
public DataType dataType;
#endregion
// 1. 修改:使用列表存储多个串口及相关线程
private List<SerialPort> serialPorts = new List<SerialPort>();
private List<Thread> receiveThreads = new List<Thread>();
private Dictionary<string, Sensor> allSensor = new Dictionary<string, Sensor>();
StringBuilder sb = new StringBuilder();
public GameObject sensorView;
private void Start()
{
sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
// 1. 自动查找并连接所有可用端口
List<string> connectedPorts = AutoConnectAll();
if (connectedPorts.Count == 0)
{
Debug.LogError("没有找到可用的串口设备。");
return;
}
// 2. 初始化传感器
foreach (Sensor s in GetComponentsInChildren<Sensor>())
{
allSensor.TryAdd(s.GetType().Name, s);
s.Init(this); // 立即初始化
}
switch (dataType)
}
/// <summary>
/// 自动查找并连接所有可用的串口
/// </summary>
/// <returns>成功连接的端口名称列表</returns>
private List<string> AutoConnectAll()
{
List<string> connectedPorts = new List<string>();
string[] portNames = SerialPort.GetPortNames();
if (portNames.Length == 0)
{
case DataType.:
dataReceiveThread = new Thread(new ThreadStart(DataReceiveBytesThread));
break;
case DataType.:
dataReceiveThread = new Thread(new ThreadStart(DataReceiveStrThread));
break;
Debug.LogWarning("未检测到任何串口硬件。");
return connectedPorts;
}
foreach (string name in portNames)
{
try
{
SerialPort sp = new SerialPort(name, baudRate, parity, dataBits, stopBits);
sp.ReadTimeout = 1000;
sp.Open();
// 连接成功,加入列表
serialPorts.Add(sp);
connectedPorts.Add(name);
Debug.Log($"成功连接设备: {name}");
// 2. 为每一个端口启动独立的接收线程
Thread thread = new Thread(() => DataReceiveThread(sp));
thread.IsBackground = true;
thread.Start();
receiveThreads.Add(thread);
}
catch (Exception e)
{
Debug.LogWarning($"端口 {name} 连接失败: {e.Message}");
}
}
return connectedPorts;
}
/// <summary>
/// 通用的数据接收线程方法(每个串口一个)
/// </summary>
/// <param name="port">当前处理的串口对象</param>
private void DataReceiveThread(SerialPort port)
{
while (true)
{
// 检查端口是否还有效
if (port == null || !port.IsOpen) break;
try
{
if (port.BytesToRead > 0)
{
string receivedData = "";
// 根据格式解析数据
if (dataType == DataType.)
{
byte[] buffer = new byte[port.BytesToRead];
port.Read(buffer, 0, buffer.Length);
receivedData = Encoding.Default.GetString(buffer);
}
else // 字符串
{
receivedData = port.ReadExisting();
}
// 使用调度器将任务抛回主线程
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
// 3. 关键:将数据和端口名一起分发给所有传感器
// 你可以在这里写逻辑,比如只处理特定端口的数据,或者广播给所有
foreach (var sensor in allSensor.Values)
{
sensor.ReceiveData(receivedData, port.PortName);
}
});
}
}
catch (TimeoutException)
{
// 超时正常,继续循环
continue;
}
catch (Exception ex)
{
Debug.Log($"读取 {port.PortName} 时出错: {ex.Message}");
break; // 读取出错,退出线程循环
}
Thread.Sleep(20); // 防止CPU占用过高
}
}
/// <summary>
/// 发送数据(广播模式:向所有打开的端口发送)
/// </summary>
/// <param name="str"></param>
public void SendFunction(string str)
{
if (string.IsNullOrEmpty(str)) return;
byte[] dataSend = Encoding.ASCII.GetBytes(str);
// 遍历所有串口,向每一个发送数据
foreach (var sp in serialPorts)
{
try
{
if (sp != null && sp.IsOpen)
{
sp.Write(dataSend, 0, dataSend.Length);
Debug.Log($"向 {sp.PortName} 发送: {str}");
}
}
catch (Exception e)
{
Debug.LogError($"发送失败 {sp?.PortName}: {e.Message}");
}
}
OpenPort();
}
private void Update()
{
@ -68,160 +195,35 @@ public class SensorManager : MonoBehaviour /*MonoSingleton<SensorManager>*/
}
}
}
/// <summary>
/// 接收字节流
/// </summary>
private void DataReceiveBytesThread()
{
while (true)
{
if (sp != null && sp.IsOpen)
{
try
{
if (sp.BytesToRead > 0)
{
byte[] buffer = new byte[sp.BytesToRead];
sp.Read(buffer, 0, sp.BytesToRead);
string receivedData = Encoding.Default.GetString(buffer);
//Debug.Log(receivedData);
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
foreach (var s in allSensor)
{
s.Value.ReceiveData(receivedData);
}
});
}
}
catch (Exception e)
{
Debug.Log("消息接收失败:" + e);
}
}
Thread.Sleep(20);
}
}
/// <summary>
/// 接收字符串
/// </summary>
private void DataReceiveStrThread()
{
while (true)
{
if (sp != null && sp.IsOpen)
{
try
{
if (sp.BytesToRead > 0)
{
sb.Append(sp.ReadExisting());
//this.ColorLog(GDLog.LogColorState.Blue, sp.ReadLine());
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
foreach (var s in allSensor)
{
s.Value.ReceiveData(sb.ToString());
}
sb.Clear();
});
}
}
catch (Exception)
{
Debug.Log("消息接收失败");
}
}
Thread.Sleep(20);
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="dataSend"></param>
public void SendFunction(string str)
{
try
{
byte[] dataSend = Encoding.ASCII.GetBytes(str);
if (sp != null && sp.IsOpen)
{
if (dataSend != null && dataSend.Length > 0)
{
sp.Write(dataSend, 0, dataSend.Length);
Debug.Log("发送消息成功:" + str);
}
}
}
catch (Exception)
{
Debug.Log("发送消息失败:" + str);
}
}
//获取指定传感器
// 获取传感器逻辑保持不变
public T GetSensor<T>() where T : Sensor
{
try
string name = typeof(T).Name;
if (!allSensor.ContainsKey(name))
{
string name = typeof(T).Name;
if (!allSensor.ContainsKey(name))
T comp = GetComponentInChildren<T>();
if (comp != null)
{
allSensor.TryAdd(name, GetComponentInChildren<T>());
allSensor[name].Init(this);
}
//Debug.Log("传感器获取成功");
return allSensor[name] as T;
}
catch (Exception)
{
Debug.Log("传感器获取失败");
return null;
}
}
#region
//打开串口
public void OpenPort()
{
try
{
if (!sp.IsOpen)
{
sp.Open();
dataReceiveThread.Start();
Debug.Log("串口打开成功");
allSensor[name] = comp;
comp.Init(this);
}
}
catch (Exception e)
{
Debug.Log("串口打开失败" + e.ToString());
}
return allSensor[name] as T;
}
//关闭串口
public void ClosePort()
{
try
{
sp.Close();
dataReceiveThread.Abort();
Debug.Log("串口关闭");
}
catch (Exception)
{
Debug.Log("串口关闭失败");
}
}
#endregion
#region Unity 退
// 退出时关闭所有端口
private void OnApplicationQuit()
{
ClosePort();
foreach (var sp in serialPorts)
{
try
{
if (sp != null && sp.IsOpen) sp.Close();
sp?.Dispose();
}
catch (Exception e) { Debug.Log(e.Message); }
}
serialPorts.Clear();
receiveThreads.Clear();
}
private void OnDisable()
{
ClosePort();
}
#endregion
}

View File

@ -2662,7 +2662,7 @@ MonoBehaviour:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: 60ee95c36778d1e45be2c34febf3bae9, type: 3}
m_FontSize: 30
m_FontSize: 28
m_FontStyle: 1
m_BestFit: 0
m_MinSize: 2

View File

@ -13456,6 +13456,37 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 85679981}
m_CullTransparentMesh: 1
--- !u!1 &88074756
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 88074757}
m_Layer: 0
m_Name: Init
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &88074757
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 88074756}
serializedVersion: 2
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: 482236347}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &88731828
GameObject:
m_ObjectHideFlags: 0
@ -27887,7 +27918,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
rotationSpeed: 90
angleThreshold: 0.5
currentState: 0
--- !u!114 &164371420
MonoBehaviour:
m_ObjectHideFlags: 0
@ -50744,6 +50775,8 @@ Transform:
- {fileID: 1290841875}
- {fileID: 874457400}
- {fileID: 91711526}
- {fileID: 482236347}
- {fileID: 1529152633}
m_Father: {fileID: 1942301345}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &320283063
@ -50945,6 +50978,37 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 321170204}
m_CullTransparentMesh: 1
--- !u!1 &322000172
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 322000173}
m_Layer: 0
m_Name: Init
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &322000173
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 322000172}
serializedVersion: 2
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: 1529152633}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &322303626
GameObject:
m_ObjectHideFlags: 0
@ -77043,6 +77107,52 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 481938719}
m_CullTransparentMesh: 1
--- !u!1 &482236346
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 482236347}
- component: {fileID: 482236348}
m_Layer: 0
m_Name: 0-180
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &482236347
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 482236346}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 88074757}
- {fileID: 1763236867}
m_Father: {fileID: 320283062}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &482236348
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 482236346}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 73e6573c7793f244a81c07ddef440979, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &482404400
GameObject:
m_ObjectHideFlags: 0
@ -101088,6 +101198,63 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 638086546}
m_CullTransparentMesh: 1
--- !u!1 &638142533
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 638142534}
- component: {fileID: 638142535}
m_Layer: 0
m_Name: Play
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &638142534
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 638142533}
serializedVersion: 2
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: 1529152633}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!320 &638142535
PlayableDirector:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 638142533}
m_Enabled: 1
serializedVersion: 3
m_PlayableAsset: {fileID: 11400000, guid: 35f6739f33351504f8f108636f5bf69f, type: 2}
m_InitialState: 0
m_WrapMode: 2
m_DirectorUpdateMode: 1
m_InitialTime: 0
m_SceneBindings:
- key: {fileID: -3363750484671550300, guid: 35f6739f33351504f8f108636f5bf69f, type: 2}
value: {fileID: 1609040204495296083}
- key: {fileID: 1987304972953789498, guid: 35f6739f33351504f8f108636f5bf69f, type: 2}
value: {fileID: 1131973531}
- key: {fileID: 2914873767249624483, guid: 35f6739f33351504f8f108636f5bf69f, type: 2}
value: {fileID: 6845830716270844837}
- key: {fileID: 1828734976308347945, guid: 35f6739f33351504f8f108636f5bf69f, type: 2}
value: {fileID: 164371421}
m_ExposedReferences:
m_References: []
--- !u!1 &638762768
GameObject:
m_ObjectHideFlags: 0
@ -121547,7 +121714,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
AttentionList: []
duration: 20
duration: 90
countdownImage: {fileID: 438585181}
timeText: {fileID: 1592349207}
--- !u!1 &763628518
@ -181273,7 +181440,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
rotationSpeed: 90
angleThreshold: 0.5
currentState: 0
--- !u!114 &1131973533
MonoBehaviour:
m_ObjectHideFlags: 0
@ -240897,6 +241064,52 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
serializedGuid: f81ae0c0f0c7a743a5c5f63b788208e3
--- !u!1 &1529152632
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1529152633}
- component: {fileID: 1529152634}
m_Layer: 0
m_Name: 180-0
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1529152633
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1529152632}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 322000173}
- {fileID: 638142534}
m_Father: {fileID: 320283062}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1529152634
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1529152632}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 73e6573c7793f244a81c07ddef440979, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1529991838
GameObject:
m_ObjectHideFlags: 0
@ -277979,6 +278192,63 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1762772529}
m_CullTransparentMesh: 1
--- !u!1 &1763236866
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1763236867}
- component: {fileID: 1763236868}
m_Layer: 0
m_Name: Play
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1763236867
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763236866}
serializedVersion: 2
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: 482236347}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!320 &1763236868
PlayableDirector:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763236866}
m_Enabled: 1
serializedVersion: 3
m_PlayableAsset: {fileID: 11400000, guid: c48874f905c2eef4fa0c3c2f643f7d22, type: 2}
m_InitialState: 0
m_WrapMode: 2
m_DirectorUpdateMode: 1
m_InitialTime: 0
m_SceneBindings:
- key: {fileID: -8421437356586026945, guid: c48874f905c2eef4fa0c3c2f643f7d22, type: 2}
value: {fileID: 1609040204495296083}
- key: {fileID: -6786903364522282068, guid: c48874f905c2eef4fa0c3c2f643f7d22, type: 2}
value: {fileID: 1131973531}
- key: {fileID: 5642281781616806033, guid: c48874f905c2eef4fa0c3c2f643f7d22, type: 2}
value: {fileID: 6845830716270844837}
- key: {fileID: -7590656864639944084, guid: c48874f905c2eef4fa0c3c2f643f7d22, type: 2}
value: {fileID: 164371421}
m_ExposedReferences:
m_References: []
--- !u!1 &1763559331
GameObject:
m_ObjectHideFlags: 0
@ -303072,7 +303342,6 @@ MonoBehaviour:
virtualCameraManager: {fileID: 0}
test: 0
sceneDataHandler: {fileID: 0}
multiObjectController: {fileID: 693784968}
--- !u!114 &1942301347
MonoBehaviour:
m_ObjectHideFlags: 0
@ -350581,7 +350850,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
rotationSpeed: 90
angleThreshold: 0.5
currentState: 0
--- !u!114 &1609040204495296085
MonoBehaviour:
m_ObjectHideFlags: 0
@ -368632,7 +368901,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 6c58763dd2491d94c882310d382a6dfc, type: 3}
m_Name:
m_EditorClassIdentifier:
portName: COM4
baudRate: 115200
dataType: 1
sensorView: {fileID: 2871564559804087914}
@ -418546,7 +418814,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
rotationSpeed: 90
angleThreshold: 0.5
currentState: 0
--- !u!114 &6845830716270844836
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@ -36,6 +36,7 @@ namespace YiLiao.XinFeiTingZhen
GameManager.Instance.uiManager.CloseUI<AudioPanel>();
GameManager.Instance.uiManager.CloseUI<ConfirmPanel>();
GameManager.Instance.uiManager.CloseUI<SuccessPanel>();
GameManager.Instance.uiManager.CloseUI<CountdownPanel>();
GameManager.Instance.highLightManager.HideAllHighLight();
GameManager.Instance.sceneDataHandler.SaveSceneDataToJson(main_gameModel.mainData.folder + "/SaveData/" + stateName + ".json");
GameManager.Instance.uiManager.GetUI<TipPanel>().AddTip(gameModel.bData.txt);
@ -197,13 +198,13 @@ namespace YiLiao.XinFeiTingZhen
public void PlayClip(string value, Action callBack = null)
{
float t = GetClipLength(value);
if (t > 0.1f) GameManager.Instance.uiManager.GetUI<TreeViewPanel>().LockAllBtn();
if (t > 0.1f) GameManager.Instance.uiManager.CloseUI<TreeViewPanel>();
GameManager.Instance.timelineManager.PlayNormalClip(value);
if (Game.Instance)
{
if (coroutine != null) Game.Instance.IEnumeratorManager.Stop(coroutine);
coroutine = Game.Instance.IEnumeratorManager.Run(WaitExecute(t, () => {
GameManager.Instance.uiManager.GetUI<TreeViewPanel>().UnLockAllBtn();
GameManager.Instance.uiManager.ShowUI<TreeViewPanel>();
callBack?.Invoke();
}));
}

View File

@ -21,7 +21,7 @@ namespace YiLiao.XinFeiTingZhen
public override void OnStateEnter()
{
base.OnStateEnter();
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
GameManager.Instance.senSor.SendFunction("#ID:8,9;SONG:59,59;%");
fsm.PlayBgm(0);
fsm.ShowTip(0);

View File

@ -8,12 +8,10 @@ namespace YiLiao.XinFeiTingZhen
base.OnStateEnter();
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“椎骨棘突”", "椎骨棘突", 0, 999);
fsm.Light_EnableInteraction("椎骨棘突");
});
fsm.InteractionDown("椎骨棘突", obj => {
fsm.HideArrow();
fsm.InteractionDown("椎骨棘突", null);

View File

@ -8,13 +8,12 @@ namespace YiLiao.XinFeiTingZhen
base.OnStateEnter();
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“肩胛骨”", "肩胛骨左", 0, 999);
fsm.Light_EnableInteraction("肩胛骨左");
fsm.Light_EnableInteraction("肩胛骨右");
});
fsm.InteractionDown("肩胛骨左", args => {
fsm.AddScore(0, 0.5f);
fsm.Unlight_DisableInteraction("肩胛骨左");

View File

@ -16,12 +16,10 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“两肩胛骨内缘之间的区域”", "两肩胛骨内缘之间的区域", 0, 999);
fsm.Show_Light_EnableInteraction("两肩胛骨内缘之间的区域");
});
fsm.InteractionDown("两肩胛骨内缘之间的区域", obj => {
fsm.HideArrow();
fsm.InteractionDown("两肩胛骨内缘之间的区域", null);

View File

@ -16,10 +16,12 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“肩胛冈以上的区域”", "肩胛冈以上的区域", 0, 999);
fsm.Show_Light_EnableInteraction("肩胛冈以上的区域");
});
fsm.InteractionDown("肩胛冈以上的区域", obj => {
fsm.HideArrow();
fsm.InteractionDown("肩胛冈以上的区域", null);

View File

@ -8,12 +8,10 @@ namespace YiLiao.XinFeiTingZhen
base.OnStateEnter();
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“肩胛下角”", "肩胛下角", 0, 999);
fsm.Light_EnableInteraction("肩胛下角");
});
fsm.InteractionDown("肩胛下角", args => {
fsm.AddScore(0, 0.5f);
fsm.Unlight_DisableInteraction("肩胛下角");

View File

@ -16,10 +16,12 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“两肩胛下角的连线与第12胸椎水平线之间区域”", "两肩胛下角的连线与第12胸椎水平线之间区域", 0, 999);
fsm.Show_Light_EnableInteraction("两肩胛下角的连线与第12胸椎水平线之间区域");
});
fsm.InteractionDown("两肩胛下角的连线与第12胸椎水平线之间区域", obj => {
fsm.HideArrow();
fsm.InteractionDown("两肩胛下角的连线与第12胸椎水平线之间区域", null);

View File

@ -17,7 +17,7 @@ namespace YiLiao.XinFeiTingZhen
fsm.ShowTip(0);
fsm.PlayBgm(0);
fsm.PlayClip("肩胛线动画1", () => {
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“肩胛下角”", "肩胛下角", 0, 999);
fsm.Light_EnableInteraction("肩胛下角");
});

View File

@ -8,7 +8,7 @@ namespace YiLiao.XinFeiTingZhen
base.OnStateEnter();
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo180(() => {
fsm.PlayClip("0-180", () => {
fsm.ShowArrow("点击“11-12肋骨”", "肋骨11-12左", 0, 999);
fsm.Light_EnableInteraction("肋骨11-12左");
fsm.Light_EnableInteraction("肋骨11-12右");

View File

@ -8,7 +8,7 @@ namespace YiLiao.XinFeiTingZhen
base.OnStateEnter();
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.Show("肋间隙");
fsm.ShowArrow("点击“肋间隙”", "肋间隙", 0, 999);
});

View File

@ -34,7 +34,7 @@ namespace YiLiao.XinFeiTingZhen
}
if (fsm.main_gameModel.modeType == ZXKFramework.ModeType.ShiXun)
{
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.PlayBgm(0);
fsm.ShowTip(0);
fsm.Light("支气管肺泡听诊器位置3");

View File

@ -22,7 +22,7 @@ namespace YiLiao.XinFeiTingZhen
public override void OnStateEnter()
{
base.OnStateEnter();
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
GameManager.Instance.senSor.SendFunction("#ID:3;SONG:1;%");
fsm.PlayBgm(0);
fsm.ShowTip(0);

View File

@ -16,7 +16,7 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.ShowArrow("点击“胸骨柄上缘的中点”", "胸骨柄上缘的中点", 0, 999);
fsm.Show_Light_EnableInteraction("胸骨柄上缘的中点");
});

View File

@ -33,7 +33,7 @@ namespace YiLiao.XinFeiTingZhen
}
if (fsm.main_gameModel.modeType == ZXKFramework.ModeType.ShiXun)
{
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.PlayBgm(0);
fsm.ShowTip(0);
fsm.Light("左锁骨中线与第5肋间交点内0.5cm听诊器位置1");

View File

@ -16,7 +16,7 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.ShowArrow("点击“锁骨的肩峰端”", "锁骨的肩峰端", 0, 999);
fsm.Show_Light_EnableInteraction("锁骨的肩峰端");
});

View File

@ -16,11 +16,10 @@ namespace YiLiao.XinFeiTingZhen
{
fsm.ShowTip(0);
fsm.PlayBgm(0);
GameManager.Instance.multiObjectController.RotateAllTo0(() => {
fsm.PlayClip("180-0", () => {
fsm.ShowArrow("点击“胸骨边缘”", "胸骨边缘", 0, 999);
fsm.Show_Light_EnableInteraction("胸骨边缘");
});
fsm.InteractionDown("胸骨边缘", obj => {
fsm.HideArrow();
fsm.InteractionDown("胸骨边缘", null);

View File

@ -36,8 +36,6 @@ namespace YiLiao.XinFeiTingZhen
public bool test;
[HideInInspector]
public SceneDataHandler sceneDataHandler;
public MultiObjectController multiObjectController;
IEnumerator Start()
{

View File

@ -1,88 +0,0 @@
using UnityEngine;
using System;
public class MultiObjectController : MonoBehaviour
{
[Header("需要旋转的物体列表")]
// 在Inspector面板里把多个物体拖到这里
public YAxisRotator[] rotators;
/// <summary>
/// 让所有物体转到180度并在全部完成后打印日志
/// </summary>
public void RotateAllTo180(Action callBack = null)
{
int completedCount = 0;
int totalCount = rotators.Length;
foreach (var rotator in rotators)
{
if (rotator == null) continue;
// 为每个物体调用旋转
// 使用闭包捕获 completedCount 和 totalCount 有点麻烦,因为变量会变
// 更好的方式是定义一个局部函数或使用计数器类,这里用简单的局部函数写法
if (rotator.isActiveAndEnabled)
{
rotator.RotateTo180(() =>
{
completedCount++;
Debug.Log($"{rotator.gameObject.name} 完成旋转!当前完成数: {completedCount}/{totalCount}");
// 如果所有物体都完成了(包括那些原本就不需要转的)
if (completedCount == totalCount)
{
Debug.Log("=== 所有物体旋转任务全部完成! ===");
callBack?.Invoke();
}
});
}
else
{
completedCount++;
Debug.Log($"{rotator.gameObject.name} 完成旋转!当前完成数: {completedCount}/{totalCount}");
// 如果所有物体都完成了(包括那些原本就不需要转的)
if (completedCount == totalCount)
{
Debug.Log("=== 所有物体旋转任务全部完成! ===");
callBack?.Invoke();
}
}
}
}
/// <summary>
/// 让所有物体转到0度
/// </summary>
public void RotateAllTo0(Action callBack = null)
{
int completedCount = 0;
int totalCount = rotators.Length;
foreach (var rotator in rotators)
{
if (rotator == null) continue;
if (rotator.isActiveAndEnabled)
{
rotator.RotateTo0(() =>
{
completedCount++;
if (completedCount == totalCount)
{
Debug.Log("=== 所有物体已归零! ===");
callBack?.Invoke();
}
});
}
else
{
completedCount++;
if (completedCount == totalCount)
{
Debug.Log("=== 所有物体已归零! ===");
callBack?.Invoke();
}
}
}
}
}

View File

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

View File

@ -1,133 +0,0 @@
using UnityEngine;
using System; // 必须引入 System 命名空间以使用 Action
using System.Collections;
public class YAxisRotator : MonoBehaviour
{
[Header("旋转设置")]
[Tooltip("旋转速度,度数/秒")]
public float rotationSpeed = 90f;
[Tooltip("判断是否到达目标角度的误差范围 (度)")]
public float angleThreshold = 0.5f;
private Coroutine _currentRotationCoroutine = null;
private float _targetAngle = 0f;
void Start()
{
_targetAngle = transform.localEulerAngles.y;
}
/// <summary>
/// 方法1旋转到180度
/// </summary>
/// <param name="onComplete">旋转完成后(或无需旋转时)执行的回调函数</param>
public void RotateTo180(Action onComplete = null)
{
// 检查是否已经接近180度
if (IsAngleClose(180f))
{
Debug.Log($"[{gameObject.name}] 已经在180度附近跳过旋转直接触发回调。");
_targetAngle = 180f;
// 【修改点】即使无需旋转,也立即触发回调
onComplete?.Invoke();
return;
}
// 如果正在旋转,先打断之前的旋转
if (_currentRotationCoroutine != null)
{
StopCoroutine(_currentRotationCoroutine);
// 注意:被打断的旧旋转不会触发回调,只有最终完成的那个会触发
}
_targetAngle = 180f;
_currentRotationCoroutine = StartCoroutine(RotateRoutine(180f, onComplete));
}
/// <summary>
/// 方法2旋转到0度
/// </summary>
/// <param name="onComplete">旋转完成后(或无需旋转时)执行的回调函数</param>
public void RotateTo0(Action onComplete = null)
{
// 检查是否已经接近0度
if (IsAngleClose(0f))
{
Debug.Log($"[{gameObject.name}] 已经在0度附近跳过旋转直接触发回调。");
_targetAngle = 0f;
// 【修改点】即使无需旋转,也立即触发回调
onComplete?.Invoke();
return;
}
if (_currentRotationCoroutine != null)
{
StopCoroutine(_currentRotationCoroutine);
}
_targetAngle = 0f;
_currentRotationCoroutine = StartCoroutine(RotateRoutine(0f, onComplete));
}
/// <summary>
/// 核心协程:执行平滑旋转
/// </summary>
private IEnumerator RotateRoutine(float targetY, Action onComplete)
{
while (true)
{
Vector3 currentEuler = transform.localEulerAngles;
float currentY = currentEuler.y;
// 计算最短路径角度差
float delta = Mathf.DeltaAngle(currentY, targetY);
// 到达目标判断
if (Mathf.Abs(delta) <= angleThreshold)
{
transform.localRotation = Quaternion.Euler(0, targetY, 0);
// 旋转结束,触发回调
onComplete?.Invoke();
_currentRotationCoroutine = null;
yield break;
}
float step = rotationSpeed * Time.deltaTime;
// 最后一步修正
if (Mathf.Abs(delta) < step)
{
transform.localRotation = Quaternion.Euler(0, targetY, 0);
// 旋转结束,触发回调
onComplete?.Invoke();
_currentRotationCoroutine = null;
yield break;
}
// 执行旋转
float newY = currentY + Mathf.Sign(delta) * step;
transform.localRotation = Quaternion.Euler(0, newY, 0);
yield return null;
}
}
/// <summary>
/// 辅助判断角度是否接近
/// </summary>
private bool IsAngleClose(float target)
{
float currentY = transform.localEulerAngles.y;
float delta = Mathf.DeltaAngle(currentY, target);
Debug.Log(delta);
return Mathf.Abs(delta) <= angleThreshold;
}
}

View File

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

View File

@ -9,7 +9,7 @@ namespace YiLiao.XinFeiTingZhen
public class CountdownPanel : UIBase
{
[Tooltip("倒计时总时长(秒)")]
public float duration = 20f;
public float duration = 90f;
[Tooltip("绑定带有Filled属性的Image组件")]
public Image countdownImage;

View File

@ -80,14 +80,14 @@ namespace YiLiao.XinFeiTingZhen
new[] { "懃묘콘땡뺌", "XinGongNengDongHua" },
// --- 로꼬桂閭 ---
new[] { "肺部听诊", "正常呼吸音", "气管呼吸音", "QiGuanHuXiYin" },
//new[] { "肺部听诊", "正常呼吸音", "气管呼吸音", "QiGuanHuXiYin" },
new[] { "로꼬桂閭", "攣끽빌俱稜", "連폭밗빌俱稜", "ZhiQiGuanHuXiYin" },
new[] { "로꼬桂閭", "攣끽빌俱稜", "連폭밗로텟빌俱稜", "ZhiQiGuanFeiPaoHuXiYin" },
new[] { "로꼬桂閭", "攣끽빌俱稜", "로텟빌俱稜", "FeiPaoHuXiYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "嫩끽로텟빌俱稜", "로텟빌俱稜숑흽샀句呵", "FeiPaoHuXiYinJianRuoHuoXiaoShi" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "嫩끽로텟빌俱稜", "로텟빌俱稜藤퓻", "FeiPaoHuXiYinZengQiang" },
new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "呼吸音延长", "HuXiYinYanChang" },
//new[] { "肺部听诊", "异常呼吸音", "异常肺泡呼吸音", "呼吸音延长", "HuXiYinYanChang" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "嫩끽로텟빌俱稜", "뙤崎昑빌俱稜", "DuanXuXingHuXiYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "嫩끽로텟빌俱稜", "닛꾹昑빌俱稜", "CuCaoXingHuXiYin" },
@ -97,7 +97,7 @@ namespace YiLiao.XinFeiTingZhen
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "닛嫁넪稜(댕彊텟稜)", "CuShiLuoYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "櫓嫁넪稜(櫓彊텟稜)", "ZhongShiLuoYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "玖嫁넪稜(鬼彊텟稜)", "XiShiLuoYin" },
new[] { "肺部听诊", "异常呼吸音", "啰音", "Velcro啰音", "VelcroLuoYin" },
//new[] { "肺部听诊", "异常呼吸音", "啰音", "Velcro啰音", "VelcroLuoYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "쿠랙稜", "NianFaYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "멕딧맴넪稜<EFA596>둘稜", "GaoDiaoGanLuoYin" },
new[] { "로꼬桂閭", "嫩끽빌俱稜", "넪稜", "됴딧맴넪稜(辦稜)", "DiDiaoGanLuoYin" },
@ -111,21 +111,21 @@ namespace YiLiao.XinFeiTingZhen
new[] { "懃斗桂閭", "懃斗곌칟桂閭혐", "寮땡찧곌뒤랗桂閭혐", "ZhuDongMaiBanDiErTingZhenQu" },
new[] { "懃斗桂閭", "懃斗곌칟桂閭혐", "힛쇄곌혐", "SanJianBanQu" },
new[] { "心脏听诊", "心率", "XinLv" },
//new[] { "心脏听诊", "心率", "XinLv" },
new[] { "心脏听诊", "心音", "第一心音", "DiYiXinYin" },
new[] { "心脏听诊", "心音", "第二心音", "DiErXinYin" },
//new[] { "心脏听诊", "心音", "第一心音", "DiYiXinYin" },
//new[] { "心脏听诊", "心音", "第二心音", "DiErXinYin" },
new[] { "懃斗桂閭", "懃稜", "뒤힛懃稜", "DiSanXinYin" },
new[] { "心脏听诊", "心音", "第四心音", "DiSiXinYin" },
//new[] { "心脏听诊", "心音", "第四心音", "DiSiXinYin" },
new[] { "懃斗桂閭", "懃稜", "뒤寧懃稜藤퓻", "DiYiXinYinZengQiang" },
new[] { "懃斗桂閭", "懃稜", "뒤寧懃稜숑흽", "DiYiXinYinJianRuo" },
new[] { "心脏听诊", "心音", "第一心音强弱不等", "DiYiXinYinQiangRuoBuDeng" },
//new[] { "心脏听诊", "心音", "第一心音强弱不等", "DiYiXinYinQiangRuoBuDeng" },
//new[] { "懃斗桂閭", "懃稜", "뒤랗懃稜藤퓻", "DiErXinYinZengQiang" },
new[] { "心脏听诊", "心音", "第二心音减弱", "DiErXinYinJianRuo" },
new[] { "心脏听诊", "心音", "第一心音分裂", "DiYiXinYinFenLie" },
new[] { "心脏听诊", "心音", "第二心音通常分裂", "DiErXinYinTongChangFenLie" },
new[] { "心脏听诊", "心音", "第二心音固定分裂", "DiErXinYinGuDingFenLie" },
new[] { "心脏听诊", "心音", "第二心音反常分裂", "DiErXinYinFanChangFenLie" },
//new[] { "心脏听诊", "心音", "第二心音减弱", "DiErXinYinJianRuo" },
//new[] { "心脏听诊", "心音", "第一心音分裂", "DiYiXinYinFenLie" },
//new[] { "心脏听诊", "心音", "第二心音通常分裂", "DiErXinYinTongChangFenLie" },
//new[] { "心脏听诊", "心音", "第二心音固定分裂", "DiErXinYinGuDingFenLie" },
//new[] { "心脏听诊", "心音", "第二心音反常分裂", "DiErXinYinFanChangFenLie" },
new[] { "懃斗桂閭", "띨棍懃稜", "竭蠟퍅띨棍懃稜", "竭蠟豆퍅굴쯩쪼", "ShuZhangZaoQiBenMaLv" },
new[] { "懃斗桂閭", "띨棍懃稜", "竭蠟퍅띨棍懃稜", "竭蠟功퍅굴쯩쪼", "ShuZhangWanQiBenMaLv" },
@ -138,7 +138,7 @@ namespace YiLiao.XinFeiTingZhen
new[] { "懃斗桂閭", "懃斗憧稜", "澗鍵퍅憧稜", "힛쇄곌혐", "SanJianBanQu2" },
new[] { "懃斗桂閭", "懃斗憧稜", "竭蠟퍅憧稜", "랗쇄곌혐", "ErJianBanQu3" },
new[] { "懃斗桂閭", "懃斗憧稜", "竭蠟퍅憧稜", "寮땡찧곌혐", "ZhuDongMaiBanQu3" },
new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "肺动脉瓣区", "FeiDongMaiBanQu3" },
//new[] { "心脏听诊", "心脏杂音", "舒张期杂音", "肺动脉瓣区", "FeiDongMaiBanQu3" },
new[] { "懃斗桂閭", "懃斗憧稜", "竭蠟퍅憧稜", "힛쇄곌혐", "SanJianBanQu3" },
new[] { "懃斗桂閭", "懃斗憧稜", "젯崎昑憧稜", "LianXuXingZaYin" },
new[] { "懃斗桂閭", "懃斗憧稜", "懃관칡꼰稜", "XinBaoMoCaYin" }