Unity 2D Animation 动画案例

Unity 2D Animation 案例

Animator Controller

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

Animation制作

  1. Windows > Animation > Animation 打开动画编辑器,选中Player后点击Create创建.anim

  1. 将Sprites添加到帧动画中。可以依次添加crouch,idle,jump,run动画

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

动画控制脚本

run状态

  1. 建立player_idleplayer_run的联系

    Parameters面板添加float变量

    单击连线inspector面板的

    ①去除动画退出时间

    Conditions处添加条件变量

    player_idle → player_run

    player_run → player_idle

  2. 变量控制(脚本)

    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状态相似,这里仅给出思路,供读者参考。

  1. jump (判断条件)

    Any State → jump (isJumping = true)

    jump → idle (isJumping = false; move < 1)

    jump → run(isJumping = false; move > 0)

  2. 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

Gitee工程源码

posted @   他们讨厌我  阅读(894)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示