maltadirk 发表于 2023-3-14 09:31

Unity非运行时角色跑场景

前言

美术地编在编辑场景的时候,需要边跑场景边修改场景物件。一般跑场景工具是在运行时启动,但是运行时编辑场景物件一般是没法保存的,所以有了这个工具的需求。这个工具可以在非运行时跑角色,因为在非运行时,所以可以边跑场景,边编辑场景物件。


https://www.zhihu.com/video/1609530758191616000
实现

非运行时的角色动画处理

unity的动画支持在非运行状态播放动画,首先使用StartAnimationMode函数启动动画
AnimationMode.StartAnimationMode();
文档 : AnimationMode.StartAnimationMode
然后使用SampleAnimationClip播放指定的片段,这样就能在非运行时播放动画
AnimationMode.SampleAnimationClip(m_Anim.gameObject, m_IdleClip, m_AnimPlayTime);
文档 :AnimationMode.SampleAnimationClip
SceneView中的摄像机处理

SceneView可以控制参数的变量是pivot和rotation,顾名思义,pivot是设置的摄像机的中心点,rotation是设置的摄像机的旋转。
Unity - Scripting API: SceneView.pivot
SceneView.rotation
Demo中pivot设置角色的位置 + 偏移,rotation设置为摄像机当前的旋转量
// 场景视图的旋转和中心点
Quaternion animRotation = Quaternion.Euler(-m_AngleV, m_AngleH, 0.0f);
m_SceneView.rotation = animRotation;
m_SceneView.pivot = m_Player.position + lookatPosOffset;
那么如何控制摄像机的远近距离在一个范围内,可以通过控制SceneView.size来近似的模拟这个范围。通过源码获知,SceneView.size值的大小可以影响camDistance的大小
Unity - Scripting API: SceneView.size
// 模拟设置摄像机距离的最小最大值
m_SceneView.size = Mathf.Clamp(m_SceneView.size, camDisRange.x, camDisRange.y);
通过设置了pivot,rotation和size参数,SceneView类内部会根据这些变量计算摄像机的Transform, 伪代码如下
camera.rotation = SceneView.rotation;
camera.position = SceneView.pivit + SceneView.rotation *new Vector3(0, 0, -cameraDistance);
输入事件的逻辑控制

通过监听SceneView.duringSceneGui的回调可以得到键盘输入和鼠标输入事件,这里主要讲下键盘事件的处理
首先注册WADS的键盘事件
m_DirKeyBindings.Clear();
m_DirKeyBindings.Add(KeyCode.W, WalkForward);
m_DirKeyBindings.Add(KeyCode.S, WalkBackward);
m_DirKeyBindings.Add(KeyCode.A, WalkLeft);
m_DirKeyBindings.Add(KeyCode.D, WalkRight);
看下某个键盘事件的函数,当按下按键的时候,会赋值,当松开按键的时候,值清0
      void WalkForward(ShortcutStage stage)
      {
            m_CurrentInputVector.y =
(stage == ShortcutStage.Begin) ? 0.5f : ((m_CurrentInputVector.y > 0f) ? 0f : m_CurrentInputVector.y);

            if (m_SceneView != null)
            {
                m_SceneView.Repaint();
            }
      }
当按住多个按键的时候,比如按住了WA按键,会往斜方向跑,这时候松开一个按键,只会把一个移动值设置为0,只有当所有的按键都放开的时候,才会停止运动。这样才能达到平滑的运动的效果。
                case EventType.KeyDown:
                  {
                        KeyCode keyCode = evt.keyCode;

                        if (m_DirKeyBindings.TryGetValue(keyCode, out action))
                        {
                            action(ShortcutStage.Begin);
                            m_Anim.Run();
                            m_Move.SetMoveParam(m_CurrentInputVector.x, m_CurrentInputVector.y, isSpeedUp);
                            m_DirKeysDown.Add(keyCode);
                            evt.Use();
                        }
                  }
                  break;
                case EventType.KeyUp:
                  {
                        KeyCode keyCode = evt.keyCode;

                        if (m_DirKeyBindings.TryGetValue(keyCode, out action))
                        {
                            action(ShortcutStage.End);
                            m_Move.SetMoveParam(m_CurrentInputVector.x, m_CurrentInputVector.y, isSpeedUp);

                            m_DirKeysDown.Remove(keyCode);

                            if (m_DirKeysDown.Count == 0)
                            {
                              m_CurrentInputVector = Vector3.zero;
                              m_Anim.Idle();
                              m_Move.SetMoveParam(0, 0, false);
                            }

                            evt.Use();
                        }
                  }
                  break;
其他问题

在OnDrawGizmos函数刷新SceneView界面
      private void OnDrawGizmos()
      {
            EditorApplication.QueuePlayerLoopUpdate();
      }
这时候转动镜头,镜头会晃动,如下图所示


https://www.zhihu.com/video/1609543320451198976
正确做法是监听EditorApplication.update事件,在里面刷新SceneView
EditorApplication.update += OnEditorAppUpdate;

void OnEditorAppUpdate()
{
   EditorApplication.QueuePlayerLoopUpdate();
   //SceneView.RepaintAll();
}
项目地址

GitHub - xieliujian/UnityDemo_ScenePlayerRoam: Unity非运行时角色跑场景
参考文章

Unity非运行模式下实现动画播放/回退工具 - chiguozi - 博客园
Unity3D研究院之同步Scene与Game视图摄像机 | 雨松MOMO程序研究院
UnityCsReference/CameraFlyModeContext.cs at master · Unity-Technologies/UnityCsReference
Unity在Editor下获取键盘等设备Input事件 - 小宝笔记
UnityCsReference/SceneView.cs at master · Unity-Technologies/UnityCsReference

NoiseFloor 发表于 2023-3-14 09:32

闲的

RhinoFreak 发表于 2023-3-14 09:41

mmo有的项目有这个需求
页: [1]
查看完整版本: Unity非运行时角色跑场景