feat: MCP Unity 场景优化 — 完整交互体系搭建

- 删除重复 Ground
- 创建 [Managers] 空物体,挂载 GameManager + StepManager + ExperimentFlowCoordinator + AudioManager
- Main Camera 挂载 InteractionSystem
- 伤者 InjectedPerson 下创建 5 个交互子物体 (InjuryVisual/Swelling/Pain/VitalSigns/Neuro)
- 创建绑带位置、踝关节、衬垫、夹板位置等空物体
- 道具摆放到位:伤者(2,0.05,5) 施救者(3,0,5) 鞋(2.7,0.15,5.5) 绷带/夹板/急救箱在旁
- InjuryLeg Tag 修正,Ground Tag 修正
- 全部新脚本同步导入 (ExperimentTypes/StepData/ExperimentConfig/StepManager/GameManager/ExperimentFlowCoordinator/InteractionSystem/DraggableObject/HighlightEffect/UIManager/ExamPopup/ScoreDisplay/VideoController/AudioManager/CharacterAnimController/StepAnimationHandler)
- 旧脚本 (ExperimentController/ConfigLoader/AnimationController/HUDController/VideoPlayerController/PopupSystem/ModeSelectionUI) 全部兼容修复或 stub
- 编译通过,0 错误
- Canvas 挂载 UIManager
This commit is contained in:
yangbear
2026-06-24 02:33:48 +08:00
parent 23d3d282f8
commit f0a6b96da5
111 changed files with 11023 additions and 440 deletions
@@ -0,0 +1,3 @@
using UnityEngine;
/// <summary>Legacy — replaced by StepAnimationHandler.</summary>
public class AnimationController : MonoBehaviour { }
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05b8d5cbfd0e74474a937b3cc7ad120c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,87 @@
using UnityEngine;
/// <summary>
/// 角色动画控制器:管理伤者和施救者的动画状态切换。
/// 挂在角色根 GameObject 上,引用其 Animator 组件。
/// </summary>
public class CharacterAnimController : MonoBehaviour
{
public enum CharacterRole { Patient, Rescuer }
public CharacterRole Role = CharacterRole.Patient;
[Header("Animator 引用")]
[SerializeField] private Animator _animator;
private static readonly int ParamRun = Animator.StringToHash("IsRunning");
private static readonly int ParamJump = Animator.StringToHash("Jump");
private static readonly int ParamFall = Animator.StringToHash("Fall");
private static readonly int ParamLying = Animator.StringToHash("IsLying");
private static readonly int ParamCrouch = Animator.StringToHash("Crouch");
private static readonly int ParamCheck = Animator.StringToHash("Check");
private static readonly int ParamBandage = Animator.StringToHash("Bandage");
private static readonly int ParamRemoveShoe = Animator.StringToHash("RemoveShoe");
private void Awake()
{
if (_animator == null) _animator = GetComponent<Animator>();
}
public void PlayRun()
{
if (_animator == null) return;
_animator.SetBool(ParamRun, true);
}
public void StopRun()
{
if (_animator == null) return;
_animator.SetBool(ParamRun, false);
}
public void TriggerJump()
{
_animator?.SetTrigger(ParamJump);
}
public void TriggerFall()
{
_animator?.SetTrigger(ParamFall);
_animator?.SetBool(ParamLying, true);
}
public void SetLying(bool lying)
{
_animator?.SetBool(ParamLying, lying);
}
public void PlayCrouch()
{
_animator?.SetBool(ParamCrouch, true);
}
public void StopCrouch()
{
_animator?.SetBool(ParamCrouch, false);
}
public void TriggerCheck()
{
_animator?.SetTrigger(ParamCheck);
}
public void TriggerBandage()
{
_animator?.SetTrigger(ParamBandage);
}
public void TriggerRemoveShoe()
{
_animator?.SetTrigger(ParamRemoveShoe);
}
public void TriggerByName(string triggerName)
{
if (_animator == null || string.IsNullOrEmpty(triggerName)) return;
_animator.SetTrigger(Animator.StringToHash(triggerName));
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23fb87b6a5b9544d3aed3b307715504c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bbe25e570b15b41d98e77259d82a8f1d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: