学习日志2022.10.08 Unity人物运动(移动+转身)Character Controller射线检测动画融合

Posted EndlessDaydream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习日志2022.10.08 Unity人物运动(移动+转身)Character Controller射线检测动画融合相关的知识,希望对你有一定的参考价值。

 Angelyatou/Endless_Unity_Projects: Unity Projects of Endlessdaydram (github.com)https://github.com/Angelyatou/Endless_Unity_Projects

最简单的人物运动(移动+转身)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha1 : MonoBehaviour

    public float speed = 3;
    Vector3 move;
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Move(h, 0, v);
    

    void Move(float x,float y,float z)
    
        //世界坐标
        move = new Vector3(x, y, z);

        //要看向的位置
        Vector3 to = transform.position + move;
        transform.LookAt(to);
        transform.position += move * speed * Time.deltaTime;
    

FBX文件(包含模型、骨骼、动画、材质)

动画状态机

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha1 : MonoBehaviour

    Animator animator;

    public float speed = 3;
    Vector3 move;

    private void Start()
    
        animator = GetComponent<Animator>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Move(h, 0, v);
        //更新动画
        UpdateAnim();
    

    void Move(float x,float y,float z)
    
        //世界坐标
        move = new Vector3(x, y, z);
        //要看向的位置
        Vector3 to = transform.position + move;
        transform.LookAt(to);
        transform.position += move * speed * Time.deltaTime;
    

    void UpdateAnim()
    
        float forward = move.magnitude;
        animator.SetFloat("Forward", forward);
    

把FBX里的动画文件拖到Animator窗口,设置动画状态机 

 

添加刚体、碰撞体并冻结刚体旋转

 然后发现在撞东西的时候会抖,像这样

 于是我们修改一下代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha2 : MonoBehaviour

    Animator animator;
    Rigidbody rigid;

    public float speed = 3;
    Vector3 move;

    private void Start()
    
        animator = GetComponent<Animator>();
        rigid = GetComponent<Rigidbody>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Move(h, 0, v);
        //更新动画
        UpdateAnim();
    

    void Move(float x, float y, float z)
    
        //世界坐标
        move = new Vector3(x, y, z);
    
    //刚体移动,要在FixedUpdate里写
    public void FixedUpdate()
    
        //根据move,直接改变刚体速度
        Vector3 v = move * speed;
        v.y = rigid.velocity.y;
        rigid.velocity = new Vector3(move.x,rigid.velocity.y,move.z)* speed;

        //让刚体朝向目标
        Quaternion q = Quaternion.LookRotation(move);  //向量 转成 朝向
        rigid.MoveRotation(q);
    

    void UpdateAnim()
    
        float forward = move.magnitude;
        animator.SetFloat("Forward", forward);
    

 就变成这样了

 如果想让他碰到东西停下动作,也可以把UpdateAnim改成这样

    void UpdateAnim()
    
        //float forward = move.magnitude;
        //animator.SetFloat("Forward", forward);

        //基于刚体速度播放动画
        animator.SetFloat("Forward", rigid.velocity.magnitude / speed);
    

就变成这样 


使用Character Controller控制角色运动(移动+转身)

角色控制器

Step Offset:上楼梯的台阶高度最大值

Skin Width:皮肤(柔软物质厚度)(避免卡死)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha3 : MonoBehaviour

    Animator animator;
    CharacterController cc;

    public float speed = 3;
    Vector3 move;

    private void Start()
    
        animator = GetComponent<Animator>();
        cc = GetComponent<CharacterController>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Move(h, 0, v);

        //更新动画
        UpdateAnim();
    

    void Move(float x, float y, float z)
    
        move = new Vector3(x, 0, z);
        //这一帧移动的向量,很小
        Vector3 m = move * speed * Time.deltaTime;

        //朝向移动方向
        transform.LookAt(transform.position + m);

        //通过cc去移动
        cc.Move(m);
    

    void UpdateAnim()
    
        //基于刚体速度播放动画
        animator.SetFloat("Forward",cc.velocity.magnitude / speed);
    


运行unity发现能爬楼梯爬坡但不下落

使用射线检测改进(使人物能下落)

Test Raycast: 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha3Fall : MonoBehaviour

    Animator animator;
    CharacterController cc;

    public float speed = 3;
    Vector3 move;

    bool isGround = true;
    private void Start()
    
        animator = GetComponent<Animator>();
        cc = GetComponent<CharacterController>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Move(h, 0, v);

        //更新动画
        UpdateAnim();
    

    void Move(float x, float y, float z)
    
        move = new Vector3(x, 0, z);
        //这一帧移动的向量,很小
        Vector3 m = move * speed * Time.deltaTime;

        //朝向移动方向
        transform.LookAt(transform.position + m);

        //通过cc去移动
        cc.Move(m);
    

    private void FixedUpdate()
    
        Ray ray = new Ray(transform.position + new Vector3(0, 0.2f, 0), Vector3.down);

        RaycastHit hit;
        Color c = Color.red;

        isGround = false;
        if(Physics.Raycast(ray,out hit, 0.35f))
        
            c = Color.green;
            isGround = true;
        
        //调式
        Debug.DrawLine(transform.position + new Vector3(0, 0.2f, 0),transform.position - new Vector3(0,0.15f,0),c);
    
    void UpdateAnim()
    
        //基于刚体速度播放动画
        animator.SetFloat("Forward", cc.velocity.magnitude / speed);
    


下落:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha3Fall : MonoBehaviour

    Animator animator;
    CharacterController cc;

    public float speed = 3;
    Vector3 move;

    bool isGround = true;
    private void Start()
    
        animator = GetComponent<Animator>();
        cc = GetComponent<CharacterController>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Move(h, 0, v);

        //更新动画
        UpdateAnim();
    

    //纵向速度
    float vy = 0;
    void Move(float x, float y, float z)
    
        move = new Vector3(x, 0, z);
        //这一帧移动的向量,很小
        Vector3 m = move * speed * Time.deltaTime;

        if (isGround)
        
            vy = 0;
        
        else
        
            //物理公式:v = v0 + gt   (v0=0)
            vy += Physics.gravity.y * Time.deltaTime;
        

        //Δy = v * Δt
        m.y = vy * Time.deltaTime;

        //朝向移动方向
        transform.LookAt(transform.position + m);

        //通过cc去移动
        cc.Move(m);
    

    private void FixedUpdate()
    
        Ray ray = new Ray(transform.position + new Vector3(0, 0.2f, 0), Vector3.down);

        RaycastHit hit;
        Color c = Color.red;

        isGround = false;
        if(Physics.Raycast(ray,out hit, 0.35f))
        
            c = Color.green;
            isGround = true;
        
        //调式
        Debug.DrawLine(transform.position + new Vector3(0, 0.2f, 0),transform.position - new Vector3(0,0.15f,0),c);
    
    void UpdateAnim()
    
        //基于刚体速度播放动画
        animator.SetFloat("Forward", cc.velocity.magnitude / speed);
    



动画融合

 

加个Test Speed进行调试

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cha3Fall : MonoBehaviour

    Animator animator;
    CharacterController cc;

    public float speed = 3;
    [Range(0.0f, 1.0f)]
    public float testSpeed = 1;


    Vector3 move;

    bool isGround = true;
    private void Start()
    
        animator = GetComponent<Animator>();
        cc = GetComponent<CharacterController>();
    
    void Update()
    
        //获取输入
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Move(h, 0, v);

        //更新动画
        UpdateAnim();
    

    //纵向速度
    float vy = 0;
    void Move(float x, float y, float z)
    
        move = new Vector3(x, 0, z);
        //这一帧移动的向量,很小
        Vector3 m = move * speed * Time.deltaTime;

        if (isGround)
        
            vy = 0;
        
        else
        
            //物理公式:v = v0 + gt   (v0=0)
            vy += Physics.gravity.y * Time.deltaTime;
        

        //Δy = v * Δt
        m.y = vy * Time.deltaTime;

        //朝向移动方向
        transform.LookAt(transform.position + move);

        //通过cc去移动
        cc.Move(m);
    

    private void FixedUpdate()
    
        Ray ray = new Ray(transform.position + new Vector3(0, 0.2f, 0), Vector3.down);

        RaycastHit hit;
        Color c = Color.red;

        isGround = false;
        if(Physics.Raycast(ray,out hit, 0.35f))
        
            c = Color.green;
            isGround = true;
        
        //调式
        Debug.DrawLine(transform.position + new Vector3(0, 0.2f, 0),transform.position - new Vector3(0,0.15f,0),c);
    
    void UpdateAnim()
    
        //基于刚体速度播放动画
        animator.SetFloat("Forward", cc.velocity.magnitude / speed * testSpeed);
    


unity3d控制模型的运动

这里就不多做解释了,直接上代码,只为了备忘。

public class HeroMove : MonoBehaviour {

    private float speed;//人物行动速度
    private Animation ani;

    // Use this for initialization
    void Start () {
        speed = 1f;
        ani = GetComponent<Animation> ();
    }
    
    // Update is called once per frame
    void Update () {
        /*向前走/跑*/
        if (Input.GetKey (KeyCode.W)) {
            transform.Translate (Vector3.forward * Time.deltaTime * speed);
            if (Input.GetKey (KeyCode.LeftShift)) {
                speed = 3f;
                ani.Play ("Run");
            } else {
                speed = 1f;
                ani ["Walk"].speed = 1;
                ani.Play ("Walk");
            }
        } else if (Input.GetKey (KeyCode.S)) {
            //向后退
            transform.Translate (Vector3.back * Time.deltaTime * speed);
            ani ["Walk"].speed = -1;
            ani.Play ("Walk");
        } else {
            //停止
            ani.Play ("Idle");
        }
    }
}

 

以上是关于学习日志2022.10.08 Unity人物运动(移动+转身)Character Controller射线检测动画融合的主要内容,如果未能解决你的问题,请参考以下文章

怎么通过程序控制unity3d人物动作

unity2d像素游戏镜头运动就糊

unity3d控制模型的运动

Unity3D之Mecanim动画系统学习笔记:IK(反向动力学)动画

unity修改动画节点所在时间点

Unity 中EasyTouch和播放动画的结合