feat: VFS 虚拟仿真实验核心框架 v2
- 加权评分系统:每步独立 ScoreWeight,满分 100,SequenceClick 按子项比例计分 - StepData 新增 DetailedContent(学习模式详细操作说明)和 SubStepCount - 伤情检查步骤扩展为 5 子项序列(视觉检查→肿胀→疼痛→生命体征→神经评估) - 夹板固定模式完整评分(选择夹板→放置衬垫→夹板固定→固定后检查) - Doc/ 文件夹归档三份文档:项目大纲、文案、评分标准 - README 更新评分权重表和夹板固定流程
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// 按步骤触发对应动画:开场动画、脱鞋、绑带、夹板放置等。
|
||||
/// 挂在场景中有动画关联物体的 GameObject 上。
|
||||
/// 由 ExperimentFlowCoordinator 绑定到 StepManager.OnStepChanged。
|
||||
/// </summary>
|
||||
public class StepAnimationHandler : MonoBehaviour
|
||||
{
|
||||
[Header("角色引用")]
|
||||
[SerializeField] private CharacterAnimController _patient;
|
||||
[SerializeField] private CharacterAnimController _rescuer;
|
||||
|
||||
[Header("道具引用")]
|
||||
[SerializeField] private GameObject _shoeLeft; // 伤者左脚鞋
|
||||
[SerializeField] private GameObject _shoeRight; // 伤者右脚鞋
|
||||
[SerializeField] private GameObject[] _bandages; // 绑带物件列表
|
||||
[SerializeField] private GameObject[] _splints; // 夹板物件列表
|
||||
[SerializeField] private GameObject _padding; // 衬垫
|
||||
|
||||
[Header("夹板固定专用道具")]
|
||||
[SerializeField] private GameObject _splintLeft;
|
||||
[SerializeField] private GameObject _splintRight;
|
||||
|
||||
[Header("伤口高亮")]
|
||||
[SerializeField] private GameObject _woundHighlight;
|
||||
|
||||
[Header("动画时长")]
|
||||
[SerializeField] private float _shoeRemoveDuration = 1.5f;
|
||||
[SerializeField] private float _bandageAppearDuration = 0.5f;
|
||||
|
||||
/// <summary>由 StepManager.OnStepChanged 调用</summary>
|
||||
public void PlayStepAnimation(int stepIndex)
|
||||
{
|
||||
var sm = FindObjectOfType<StepManager>();
|
||||
if (sm == null) return;
|
||||
|
||||
var step = sm.GetCurrentStep();
|
||||
if (step == null) return;
|
||||
|
||||
StopAllCoroutines();
|
||||
|
||||
// 根据步骤名称匹配动画
|
||||
switch (step.StepName)
|
||||
{
|
||||
case "OpeningScene":
|
||||
StartCoroutine(PlayOpeningScene());
|
||||
break;
|
||||
case "RemoveShoes":
|
||||
StartCoroutine(PlayRemoveShoes());
|
||||
break;
|
||||
case "PlaceBandage":
|
||||
StartCoroutine(PlayPlaceBandage());
|
||||
break;
|
||||
case "LimbFixation":
|
||||
StartCoroutine(PlayLimbFixation());
|
||||
break;
|
||||
case "SplintFixation":
|
||||
StartCoroutine(PlaySplintFixation());
|
||||
break;
|
||||
case "AnkleFixation":
|
||||
StartCoroutine(PlayAnkleFixation());
|
||||
break;
|
||||
case "FinalCheck":
|
||||
break;
|
||||
default:
|
||||
Debug.Log($"StepAnimationHandler: 步骤 {step.StepName} 无专属动画");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region 动画协程
|
||||
|
||||
private IEnumerator PlayOpeningScene()
|
||||
{
|
||||
// 伤者跑步 → 跳高 → 摔倒
|
||||
_patient?.PlayRun();
|
||||
yield return new WaitForSeconds(4f);
|
||||
_patient?.TriggerJump();
|
||||
yield return new WaitForSeconds(1f);
|
||||
_patient?.TriggerFall();
|
||||
yield return new WaitForSeconds(1.5f);
|
||||
_patient?.StopRun();
|
||||
}
|
||||
|
||||
private IEnumerator PlayRemoveShoes()
|
||||
{
|
||||
// 鞋子弹开/移出
|
||||
if (_shoeLeft != null)
|
||||
{
|
||||
Vector3 target = _shoeLeft.transform.position + Vector3.right * 0.5f + Vector3.up * 0.2f;
|
||||
yield return StartCoroutine(MoveToPosition(_shoeLeft, target, _shoeRemoveDuration));
|
||||
_shoeLeft.SetActive(false);
|
||||
}
|
||||
if (_shoeRight != null)
|
||||
{
|
||||
Vector3 target = _shoeRight.transform.position + Vector3.right * 0.5f + Vector3.up * 0.2f;
|
||||
yield return StartCoroutine(MoveToPosition(_shoeRight, target, _shoeRemoveDuration));
|
||||
_shoeRight.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlayPlaceBandage()
|
||||
{
|
||||
// 显示绑带
|
||||
foreach (var b in _bandages)
|
||||
{
|
||||
if (b != null) b.SetActive(true);
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private IEnumerator PlayLimbFixation()
|
||||
{
|
||||
// 显示衬垫 + 激活绑带
|
||||
if (_padding != null) _padding.SetActive(true);
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
|
||||
// 依次显示绑带
|
||||
for (int i = 0; i < _bandages.Length; i++)
|
||||
{
|
||||
if (_bandages[i] != null)
|
||||
{
|
||||
_bandages[i].SetActive(true);
|
||||
yield return new WaitForSeconds(_bandageAppearDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlaySplintFixation()
|
||||
{
|
||||
// 显示夹板
|
||||
if (_splintLeft != null) _splintLeft.SetActive(true);
|
||||
if (_splintRight != null) _splintRight.SetActive(true);
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
|
||||
foreach (var s in _splints)
|
||||
{
|
||||
if (s != null) s.SetActive(true);
|
||||
yield return new WaitForSeconds(_bandageAppearDuration);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlayAnkleFixation()
|
||||
{
|
||||
// 8 字绑带动画 - 激活脚踝处绑带
|
||||
if (_bandages.Length > 0 && _bandages[_bandages.Length - 1] != null)
|
||||
{
|
||||
_bandages[_bandages.Length - 1].SetActive(true);
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 工具方法
|
||||
|
||||
private IEnumerator MoveToPosition(GameObject obj, Vector3 target, float duration)
|
||||
{
|
||||
if (obj == null) yield break;
|
||||
|
||||
Vector3 start = obj.transform.position;
|
||||
float elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
obj.transform.position = Vector3.Lerp(start, target, elapsed / duration);
|
||||
yield return null;
|
||||
}
|
||||
obj.transform.position = target;
|
||||
}
|
||||
|
||||
/// <summary>显示伤口高亮</summary>
|
||||
public void ShowWoundHighlight(bool show)
|
||||
{
|
||||
if (_woundHighlight != null) _woundHighlight.SetActive(show);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user