/** [EasyMotionRecorder] Copyright (c) 2018 Duo.inc This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ using UnityEngine; using System; namespace Entum { /// /// モーションデータ再生クラス /// SpringBone, DynamicBone, BulletPhysicsImplなどの揺れ物アセットのScript Execution Orderを20000など /// 大きな値にしてください。 /// DefaultExecutionOrder(11000) はVRIK系より処理順を遅くする、という意図です /// [DefaultExecutionOrder(11000)] public class MotionDataPlayer : MonoBehaviour { [SerializeField] private KeyCode _playStartKey = KeyCode.S; [SerializeField] private KeyCode _playStopKey = KeyCode.T; [SerializeField] protected HumanoidPoses RecordedMotionData; [SerializeField] private Animator _animator; [SerializeField, Tooltip("再生開始フレームを指定します。0だとファイル先頭から開始です")] private int _startFrame; [SerializeField] private bool _playing; [SerializeField] private int _frameIndex; [SerializeField, Tooltip("普段はOBJECTROOTで問題ないです。特殊な機材の場合は変更してください")] private MotionDataSettings.Rootbonesystem _rootBoneSystem = MotionDataSettings.Rootbonesystem.Objectroot; [SerializeField, Tooltip("rootBoneSystemがOBJECTROOTの時は使われないパラメータです。")] private HumanBodyBones _targetRootBone = HumanBodyBones.Hips; [Header("인스턴스 설정")] [SerializeField] private string instanceID = ""; [SerializeField] private bool useDontDestroyOnLoad = false; private HumanPoseHandler _poseHandler; private Action _onPlayFinish; private float _playingTime; private void Awake() { if (_animator == null) { Debug.LogError("MotionDataPlayerにanimatorがセットされていません。MotionDataPlayerを削除します。"); Destroy(this); return; } // 인스턴스 ID가 비어있으면 자동 생성 if (string.IsNullOrEmpty(instanceID)) { instanceID = System.Guid.NewGuid().ToString().Substring(0, 8); } // DontDestroyOnLoad 설정 (선택적) if (useDontDestroyOnLoad) { DontDestroyOnLoad(gameObject); } _poseHandler = new HumanPoseHandler(_animator.avatar, _animator.transform); _onPlayFinish += StopMotion; } // Update is called once per frame private void Update() { if (Input.GetKeyDown(_playStartKey)) { PlayMotion(); } if (Input.GetKeyDown(_playStopKey)) { StopMotion(); } } private void LateUpdate() { if (!_playing) { return; } _playingTime += Time.deltaTime; SetHumanPose(); } /// /// モーションデータ再生開始 /// private void PlayMotion() { if (_playing) { return; } if (RecordedMotionData == null) { Debug.LogError("재생할 모션 데이터가 없습니다."); return; } _playing = true; _frameIndex = _startFrame; _playingTime = 0f; Debug.Log($"모션 재생 시작 - 인스턴스: {instanceID}, 시작 프레임: {_startFrame}"); } private void StopMotion() { if (!_playing) { return; } _playing = false; Debug.Log($"모션 재생 중지 - 인스턴스: {instanceID}, 재생된 프레임: {_frameIndex}"); } private void SetHumanPose() { if (RecordedMotionData == null || RecordedMotionData.Poses == null || RecordedMotionData.Poses.Count == 0) { StopMotion(); return; } if (_frameIndex >= RecordedMotionData.Poses.Count) { StopMotion(); _onPlayFinish?.Invoke(); return; } var pose = RecordedMotionData.Poses[_frameIndex]; var humanPose = new HumanPose(); // 본 데이터 설정 if (pose.HumanoidBones != null) { foreach (var bone in pose.HumanoidBones) { // HumanBodyBones enum으로 변환 HumanBodyBones bodyBone; if (System.Enum.TryParse(bone.Name, out bodyBone)) { var boneTransform = _animator.GetBoneTransform(bodyBone); if (boneTransform != null) { boneTransform.localPosition = bone.LocalPosition; boneTransform.localRotation = bone.LocalRotation; } } } } // 근육 데이터 설정 if (pose.Muscles != null && pose.Muscles.Length > 0) { humanPose.muscles = pose.Muscles; } // 루트 본 설정 switch (_rootBoneSystem) { case MotionDataSettings.Rootbonesystem.Objectroot: _animator.transform.localPosition = pose.BodyRootPosition; _animator.transform.localRotation = pose.BodyRootRotation; break; case MotionDataSettings.Rootbonesystem.Hipbone: var hipBone = _animator.GetBoneTransform(_targetRootBone); if (hipBone != null) { hipBone.position = pose.BodyRootPosition; hipBone.rotation = pose.BodyRootRotation; } break; } // HumanPose 적용 _poseHandler.SetHumanPose(ref humanPose); _frameIndex++; } public void SetInstanceID(string id) { instanceID = id; } public void SetUseDontDestroyOnLoad(bool use) { useDontDestroyOnLoad = use; } public string GetInstanceID() { return instanceID; } } }