在project面板中 右键 > create > Animator Controller 创建动画控制器并将动画控制器绑定到Player上。



注:原素材的Pixels Per Unit的值为100,可以修改为16

建立player_idle与player_run的联系

在Parameters面板添加float变量

单击连线在inspector面板的
①去除动画退出时间

②Conditions处添加条件变量
player_idle  → player_run

player_run → player_idle

变量控制(脚本)
using UnityEngine;
public class PlayerMoveController : MonoBehaviour {
	private CharacterController2D cc;
	private Animator animator;
	[SerializeField]
	private float runSpeed = 40;
	private float move = 0f;
	private bool jump = false;
	private bool crouch = false;
	private void Awake() {
		cc = GetComponent<CharacterController2D>();
		animator = GetComponent<Animator>();
	}
	// Update is called once per frame
	void Update() {
		move = Input.GetAxisRaw("Horizontal");
		//取move的绝对值(即只存在1与0两个值),再结合Conditions判断即可切换idle与run之间的状态
		animator.SetFloat("move", Mathf.Abs(move));
		if (Input.GetButtonDown("Jump")) {
			jump = true;
		}
		if (Input.GetButtonDown("Crouch")) {
			crouch = true;
		} else if (Input.GetButtonUp("Crouch")) {
			crouch = false;
		}
	}
	private void FixedUpdate() {
			cc.Move(move * runSpeed * Time.fixedDeltaTime, crouch, jump);
			jump = false;
	}
}
其他状态与run状态相似,这里仅给出思路,供读者参考。
jump (判断条件)
Any State → jump (isJumping = true)
jump → idle (isJumping = false; move < 1)
jump → run(isJumping = false; move > 0)
crouch (判断条件)
crouch→ idle (isCrouching = true)
crouch→ run(isCrouching = true)
idle → crouch(isCrouching = false)
run→ crouch(isCrouching = false)
完整代码如下:
CharacterController2D.cs
using UnityEngine;
using UnityEngine.Events;
public class CharacterController2D : MonoBehaviour {
	[SerializeField] private float m_JumpForce = 400f;                          // Amount of force added when the player jumps.
	[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f;          // Amount of maxSpeed applied to crouching movement. 1 = 100%
	[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f;  // How much to smooth out the movement
	[SerializeField] private bool m_AirControl = false;                         // Whether or not a player can steer while jumping;
	[SerializeField] private LayerMask m_WhatIsGround;                          // A mask determining what is ground to the character
	[SerializeField] private Transform m_GroundCheck;                           // A position marking where to check if the player is grounded.
	[SerializeField] private Transform m_CeilingCheck;                          // A position marking where to check for ceilings
	[SerializeField] private Collider2D m_CrouchDisableCollider;                // A collider that will be disabled when crouching
	const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
	private bool m_Grounded;            // Whether or not the player is grounded.
	const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
	private Rigidbody2D m_Rigidbody2D;
	private bool m_FacingRight = true;  // For determining which way the player is currently facing.
	private Vector3 velocity = Vector3.zero;
	public bool m_wasCrouching = false;
	private PlayerMoveController mPlayerMoveController;
	private void Awake() {
		m_Rigidbody2D = GetComponent<Rigidbody2D>();
		mPlayerMoveController = GetComponent<PlayerMoveController>();
	}
	private void FixedUpdate() {
		bool wasGrounded = m_Grounded;
		m_Grounded = false;
		
		//ground检测
		Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
		for (int i = 0; i < colliders.Length; i++) {
			if (colliders[i].gameObject != gameObject) {
				m_Grounded = true;
				if (!wasGrounded)
					//OnLandEvent.Invoke();
					mPlayerMoveController.OnLanding();
			}
		}
	}
	public void Move(float move, bool crouch, bool jump) {
		//对Crouch行为的检测,如果Crouch键未触发却处于必须Crouch的环境中,那么需要保持Crouch=true;
		if (!crouch) {
			if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround)) {
				crouch = true;
				Debug.Log(m_wasCrouching);
			}
		}
		if (m_Grounded || m_AirControl) {
			if (crouch) {
				if (!m_wasCrouching) {
					m_wasCrouching = true;
					mPlayerMoveController.OnCrouching(true);
				}
				// 减速
				move *= m_CrouchSpeed;
				if (m_CrouchDisableCollider != null)
					m_CrouchDisableCollider.enabled = false;
			} else {
				if (m_CrouchDisableCollider != null)
					m_CrouchDisableCollider.enabled = true;
				if (m_wasCrouching) {
					m_wasCrouching = false;
					mPlayerMoveController.OnCrouching(false);
				}
			}
			// Move the character by finding the target velocity
			Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
			m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref velocity, m_MovementSmoothing);
			// 转向
			if (move > 0 && !m_FacingRight) {
				Flip();
			}
			else if (move < 0 && m_FacingRight) {
				Flip();
			}
		}
		//跳跃
		if (m_Grounded && jump) {
			m_Grounded = false;
			m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
		}
	}
	private void Flip() {
		m_FacingRight = !m_FacingRight;
		Vector3 theScale = transform.localScale;
		theScale.x *= -1;
		transform.localScale = theScale;
	}
	private void OnDrawGizmos() {
		Gizmos.DrawWireSphere(m_GroundCheck.position, k_GroundedRadius);
	}
}
PlayerMoveController.cs
using UnityEngine;
public class PlayerMoveController : MonoBehaviour {
	private CharacterController2D cc;
	private Animator animator;
	[SerializeField]
	private float runSpeed = 40;
	private float move = 0f;
	private bool jump = false;
	private bool crouch = false;
	private Rigidbody2D rb2;
	private void Awake() {
		cc = GetComponent<CharacterController2D>();
		animator = GetComponent<Animator>();
		rb2 = GetComponent<Rigidbody2D>();
	}
	// Update is called once per frame
	void Update() {
		move = Input.GetAxisRaw("Horizontal");
		animator.SetFloat("move", Mathf.Abs(move));
		if (Input.GetButtonDown("Jump")) {
			jump = true;
			animator.SetBool("isJump", true);
		}
		if (Input.GetButtonDown("Crouch")) {
			crouch = true;
		} else if (Input.GetButtonUp("Crouch")) {
			crouch = false;
		}
	}
	private void FixedUpdate() {
			cc.Move(move * runSpeed * Time.fixedDeltaTime, crouch, jump);
			jump = false;
	}
	public void OnLanding() {
		animator.SetBool("isJump", false);
	}
	public void OnCrouching(bool wasCrouching) {
		Debug.Log(wasCrouching);
		animator.SetBool("isCrouching", wasCrouching);
	}
}

有可能你的人物会遇到卡在碰撞盒边缘的问题

可能是因为Tile Collider的多个碰撞盒拼接,如果锁住人物z轴,由于unity的浮点计算问题,导致collider之间并不是绝对水平的。
解决办法:为Tile map添加Composite Collider 2D同时将Rigidbody.BodyType设为Static,
TileCollider2D.UsedByComposite设为true
原文:https://www.cnblogs.com/tamentaoyanwo/p/12833304.html