在这里依然强烈推荐大家可以去看一下傅老师的unity黑暗之魂复刻视频,讲得实在是太好了!!!
传送门:https://www.bilibili.com/video/av21513489
先来看一下最终实现的效果
动画系统用混合树,三种状态站立、行走、跑步的thresho值分别为0、1、2。
下边是代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerInput : MonoBehaviour { [Header("===== Keys 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; public string keyC; public string keyD; [Header("===== Output signals =====")] public float Dup; //上下信号 public float Dright; //左右信号 public float Dmag; //速度 public Vector3 Dvec; //旋转 public bool run; //跑步信号 [Header("===== Others =====")] public bool inputEnable = true; //输入开关 private float targetDup; private float targetDright; private float velocityDup; private float velocityDright; // Use this for initialization void Start () { } // Update is called once per frame void Update () { 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 (inputEnable == false) { 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(Dright, Dup)); float Dright2 = tempDAxis.x; float Dup2 = tempDAxis.y; Dmag = Mathf.Sqrt((Dup2 * Dup2) + (Dright2 * Dright2)); Dvec = Dright2 * transform.right + Dup2 * transform.forward; run = Input.GetKey(keyA); } /// <summary> /// 平面坐标转圆形坐标 /// </summary> /// <param name="input"></param> /// <returns></returns> 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; } } using System.Collections; using System.Collections.Generic; using UnityEngine; public class ActorController : MonoBehaviour { public GameObject model; public PlayerInput pi; public float walkSpeed = 1.5f; public float runMultiplier = 2.7f; [SerializeField] private Animator anim; private Rigidbody rigid; private Vector3 movingVec; // Use this for initialization void Awake () { pi = GetComponent<PlayerInput>(); anim = model.GetComponent<Animator>(); rigid = GetComponent<Rigidbody>(); } // Update is called once per frame void Update () { float targetRunMulti = (pi.run ? 2.0f : 1.0f); anim.SetFloat("forward", pi.Dmag * Mathf.Lerp(anim.GetFloat("forward"), targetRunMulti, 0.5f)); //动画控制 if (pi.Dmag > 0.1f) { Vector3 targetForward = Vector3.Slerp(model.transform.forward, pi.Dvec, 0.4f); //做差值,增加切换旋转动画时的平滑度 model.transform.forward = targetForward; //旋转 } movingVec = pi.Dmag * model.transform.forward * walkSpeed * (pi.run ? runMultiplier : 1.0f); } private void FixedUpdate() { //rigid.position += movingVec * Time.fixedDeltaTime; rigid.velocity = new Vector3(movingVec.x, rigid.velocity.y, movingVec.z); //用刚体来进行移动 } }代码的巧妙之处在于处理旋转的部分并没有直接采用rotate等方法,而是直接通过坐标的变化来实现了任务的旋转与速度控制,很值得思考的一种写法。