Unity3D设置摄像机旋转,保存执行后回到原始状态怎么解决?

unity3D,已经将3DSMAX场景导入,想要添加摄像头移动功能,正常添加脚本后运行发现刚刚设置的消失,是怎么回事?毕业设计内容,请求回答!

img

img

img

运行之后刚刚添加的空对象以及UI事件系统都不见了,并且也没办法移动摄像头

  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/7685588
  • 除此之外, 这篇博客: Unity3D项目七:动画制作过程中的 动画器 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 准备工作

      在Assert中创建新文件夹Animator->创建动画控制器,命名为PlayerController,

      将所使用的动画都拖入人物动画器的Base Layer中。

      最后动画器长这个样子:

    在这里插入图片描述

    实现的效果是,按下WASD进行行走和转向,站立不动时按下空格后跳一小步,行走时按下空格向前翻滚,按住SHIFT奔跑,奔跑时按下空格向前跳跃,在空中跳跃完成后下落,下落到地面时翻滚。

    然后开始一步一步制作。

    • ground动画混合树

      ground是一个Blend Tree,动画混合树,一个动画混合树其实也是一个状态,不过可以由多个动画所组成。

      官网动画混合树教程

      在BaseLayer右键->创建状态->从新的混合树,创建新的动画混合树。

      ground由站立,走路,奔跑三个动画组成,将这三个动画拖进来。

    在这里插入图片描述

    修改混合树名字和参数名字,在Motion中新增三个状态,并拖入如图所示的三个动画,并调整阈值。拖动红色标尺能看到动画的渐变。

    在这里插入图片描述

    • 创建过渡与参数控制

      右键->创建过渡,将所有状态都连接起来。状态之间的过渡通过参数来控制。

      使用的所有参数如下:

    在这里插入图片描述

    forward为Float,用于控制ground混合树中行走奔跑的过渡;

    OnGround为Bool,表示模型是否在地面上;

    jump为Trigger,用于控制跳跃和后跳;

    roll为Trigger,用于控制翻滚;

    jabVelocity为Float,表示后跳的速度;

    rollVelocity为Float,表示翻滚的速度。

    下面是一个从ground到jump的过渡例子:

    在这里插入图片描述

    使用参数来过渡需要不勾选退出时间,两个动画的长短以及过渡的区间都可以调整,在预览中看到自己满意的效果即可。

    然后是另一个例子:

    从jump到fall会有一个问题,如果跳起来还没有播放下落动画就着地了,此时会接着播放fall再播放ground,我们就需要将这条路中断。在状态的Setting中选取中断源为Current State,CurrentState就是过渡箭头的起始状态,在这里就是强行中断fall返回jump再回到ground。

    在这里插入图片描述

    其他过渡不再赘述。

    • 通过脚本控制参数

      创建ActorController.cs,一些实现的细节在代码与注释中:

      public GameObject model;    		//人物模型
      public PlayerInput pi;				//用户输入
      public float walkSpeed = 1.5f;		//行走速度
      public float runMultiplier = 2.7f;	//奔跑速度
      public float jumpVelocity = 4f;		//跳跃速度
      public float rollVelocity = 1f;		//翻滚速度
      
      [SerializeField]
      private Animator anim;				//动画控制器
      private Rigidbody rigid;			//刚体组件
      private Vector3 planarVec; 			//平面移动向量
      private Vector3 thrustVec;			//跳跃冲量
      
      private bool lockPlanar = false;    //跳跃时锁死平面移动向量
      
      void Awake() {
          pi = GetComponent<PlayerInput>();
          anim = model.GetComponent<Animator>();
          rigid = GetComponent<Rigidbody>();
      }
      

      Update()

      //刷新每秒60次
      private void Update() {
          //修改动画混合树
          /*1.从走路到跑步没有过渡*/
          /*anim.SetFloat("forward", pi.Dmag * (pi.run ? 2.0f : 1.0f));*/
          /*2.使用Lerp加权平均解决*/
          float targetRunMulti = pi.run ? 2.0f : 1.0f;
          anim.SetFloat("forward", pi.Dmag * Mathf.Lerp(anim.GetFloat("forward"), targetRunMulti, 0.3f));
      
          //播放翻滚动画
          if (rigid.velocity.magnitude > 1.0f) {
              anim.SetTrigger("roll");
          }
          //播放跳跃动画
          if (pi.jump) {
              anim.SetTrigger("jump");
          }
      
          //转向
          if(pi.Dmag > 0.01f) {
              /*1.旋转太快没有补帧*/
              /*model.transform.forward = pi.Dvec;*/
              /*2.使用Slerp内插值解决*/
              Vector3 targetForward = Vector3.Slerp(model.transform.forward, pi.Dvec, 0.2f);
              model.transform.forward = targetForward;
          }
      
          if(!lockPlanar) {
              //保存供物理引擎使用
              planarVec = pi.Dmag * model.transform.forward * walkSpeed * (pi.run ? runMultiplier : 1.0f);
          }
      }
      

      FixedUpdate()

      //物理引擎每秒50次
      private void FixedUpdate() {
          //Time.fixedDeltaTime 50/s
          //1.修改位置
          //rigid.position += movingVec * Time.fixedDeltaTime;
          //2.修改速度
          rigid.velocity = new Vector3(planarVec.x, rigid.velocity.y, planarVec.z) + thrustVec;
          //仅一帧,跳跃冲量
          thrustVec = Vector3.zero;
      }
      
    • 获取玩家输入

      创建PlayerInput.cs,平滑地控制角色的行走与转向,在空中不允许用户输入,锁死移动向量,同时还需要解决同时按下W和A时移动速度会与只按下W不同的问题,即将矩形坐标转为圆坐标。在ActorController.cs中使用获取的输入。

      public class PlayerInput : MonoBehaviour {
          [Header("---- KeyCode Settings ----")]
          /*方向键*/
          public string keyUp = "w";
          public string keyDown = "s";
          public string keyLeft = "a";
          public string keyRight = "d";
      	/*功能键*/
          public string keyA = "left shift";
          public string keyB = "space";
          public string keyC = "k";
          public string keyD;
      	/*镜头控制*/
          public string keyJUp = "up";
          public string keyJDown = "down";
          public string keyJLeft = "left";
          public string keyJRight = "right";
      
          [Header("---- Output Settings ----")]
          /*角色方向*/
          public float Dup;		
          public float Dright;
          public float Dmag;
          /*角色速度*/
          public Vector3 Dvec;
          /*镜头方向*/
          public float Jup;		
          public float Jright;
          /*奔跑跳跃参数*/
          public bool run;		
          public bool jump;
          private bool lastJump;
      
          [Header("---- Other Settings ----")]
          public bool inputEnabled = true;		//是否允许输入  	
          private float targetDup;
          private float targetDright;
          private float velocityDup;
          private float velocityDright;
      
          void Start() {}
      
          void Update() {
              Jup = (Input.GetKey(keyJUp)) ? 1.0f : 0 - (Input.GetKey(keyJDown) ? 1.0f : 0);
              Jright = (Input.GetKey(keyJRight)) ? 1.0f : 0 - (Input.GetKey(keyJLeft) ? 1.0f : 0);
      
              targetDup = (Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0);
              targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);
      
              if(!inputEnabled) {
                  targetDup = 0;
                  targetDright = 0;
              }
              /*平滑变动*/
              Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 0.1f);
              Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 0.1f);
      
              /*矩形坐标转圆坐标*/
              Vector2 tempDAxis = SquareToCircle(new Vector2(Dup, Dright));
              float Dup2 = tempDAxis.x;
              float Dright2 = tempDAxis.y;
      
              Dmag = Mathf.Sqrt((Dup2 * Dup2) + (Dright2 * Dright2));
              Dvec = Dright * transform.right + Dup * transform.forward;
              run = Input.GetKey(keyA);
      
              /*跳跃*/
              bool newJump = Input.GetKey(keyB);
              lastJump = jump;
              if(lastJump == false && newJump == true) {
                  jump = true;
              }
              else {
                  jump = false;
              }
          }
      
          /*矩形坐标转圆坐标*/
          private Vector2 SquareToCircle(Vector2 input) {
              Vector2 output = Vector2.zero;
              output.x = input.x * Mathf.Sqrt(1 - (input.y * input.y) / 2.0f);
              output.y = input.y * Mathf.Sqrt(1 - (input.x * input.x) / 2.0f);
              return output;
          }
      }
      
    • FSM

      接下来创建一些用于发送消息的脚本。

      在这里插入图片描述

      以FSMOnEnter.cs为例,进入状态时向父级发送消息。

      public class FSMOnEnter : StateMachineBehaviour {
          public string[] onEnterMessages;
      
          override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
              foreach (var msg in onEnterMessages) {
                  animator.gameObject.SendMessageUpwards(msg);
              }
          }
      }
      

      还是以jump为例,在jump状态中添加行为->FSMOnEnter,然后将size设为1,手动输入OnJumpEnter,当进入jump状态时动画器会向父级发出OnJumpEnter信息。

      然后在ActorController中加上如下函数来接受消息。

      public void OnJumpEnter() {
          pi.inputEnabled = false;
          lockPlanar = true;
          thrustVec = new Vector3(0, jumpVelocity, 0);
      }
      

      接受进入跳跃的消息,锁定跳跃时平面移动向量,并且给人物模型一个冲量来跳跃。

      FSMOnExit在状态退出时发出消息;

      FSMOnUpdate在状态刷新时发出消息,用来实现翻滚和跳跃;

      FSMClearSignals比较特殊,在状态进入和退出时清除多余的Trigger,否则按一下空格会给jump参数储存多个Trigger,跳跃多次。

    • 实现后跳和翻滚的速度匹配

      后跳和翻滚时,人物模型的速度需要进行调整,以匹配动画的播放速度。

      public void OnJabUpdate() {
          thrustVec = model.transform.forward * anim.GetFloat("jabVelocity") * 1.4f;
      }
      
      public void OnRollUpdate() {
          thrustVec = model.transform.forward * anim.GetFloat("rollVelocity") * 1.0f;
      }
      

      选中jump2->Edit:

      在这里插入图片描述

      后跳动画需要勾选上根变换位置(Y),这样跳的时候模型才会有Y轴上的位置变化。

      然后在曲线中,增加新的曲线,与jabVelocity参数同名,双击进入增加新的Key,设置为-3,最后记得一定要点应用。这样在后跳的时候jabVelocity参数会随该曲线变化,然后在OnJabUpdate中调用即可。

      翻滚动作也是同样的操作。

  • 您还可以看一下 姜雪伟老师的Unity3D移动端实战经验分享课程中的 影响游戏运行效率的因素小节, 巩固相关知识点