目录
1、新建项目
2、导入资源
复习一下前两篇笔记:
3、搭建场景
4、控制角色移动
5、制作角色动画
发现问题:
解决问题:
1、新建项目
2、导入资源
Sunny Land | 2D Characters | Unity Asset Store
复习一下前两篇笔记:
3、搭建场景
4、控制角色移动
5、制作角色动画
打开animation组件
新建动画文件
选择idle连帧图片批量拖拽进动画编译器中
调节适当的频率
接下来,点击动画组件创建更多动画
如下:
打开动画控制器
如下,可以看到我们所创建的所有动画
目前可以看到动画控制器中,进入动画默认指向Player_idle,打开进入游戏,发现无论如何移动角色,都只执行,play_idle动画,因此,我们需要动画控制器设置不同动画之间的转换。
右键选择make Transition添加转换箭头
点击箭头可以查看转换条件
点击左侧栏Parameter添加可控制动画转换的变量:
这里添加float类型的speed变量,通过速度来控制idle和run动画之间的转换。
点击箭头右侧栏设置转换条件:速度大于0.01时为run状态
取消动画的过渡时间,实现迅速转换
反过来设置run到idle的转换和条件
执行游戏,当参数变化时,动画也会变化
接下来,我们通过脚本,用代码实现如何控制动画的speed变量。
我们知道实现角色移动的两个脚本中
第一个是实现角色移动的基础,也就是常用的套路代码。有这个脚本才能实现角色移动。
第二个是我们自己写的角色移动逻辑,通过这个脚本调用基础脚本中的方法,实现角色移动。
接下来,我们要修改第二个脚本中的代码实现动画转换的逻辑。
添加动画控制器组件:
将动画器组件拖入栏中
将玩家当前速度传给动画器中的速度,从而进行动画转换的判断
为了保证动画任何位置都能工作,我们要给移动速度加上绝对值
animator.SetFloat("Speed", Mathf.Abs(move));
设置跳跃动画
无论是跑还是站立,角色都可以转换成跳跃动画
也就是任何状态都可以跳跃, 那么unity的Animator提供了一个很好的状态,就是any state
再设置转换条件
设置布尔类型的jumping参数,当jumping为真时,开始播放跳跃动画
但是这样还不行,因为播放完跳跃后无法回到其他状态,所以还要增加两个转换
jump->idle
jump->run
然后修改代码:
普通写法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D cc;//角色控制器组件
public Animator animator;//动画控制器组件
public float speed = 5f;//速度
float move;//水平移动方向
bool jump;//是否跳跃
// Update is called once per frame
void Update()
{
move = Input.GetAxis("Horizontal")*speed;//获取角色水平移动速度
animator.SetFloat("Speed", Mathf.Abs(move));//将玩家当前速度传给动画器的speed参数
jump = Input.GetButton("Jump");
animator.SetBool("Jumping", jump);
}
void FixedUpdate()
{
cc.Move(move, jump);
}
}
高级写法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D cc;//角色控制器组件
public Animator animator;//动画控制器组件
public float speed = 5f;//速度
float move;//水平移动方向
bool jump;//是否跳跃
// Update is called once per frame
void Update()
{
move = Input.GetAxis("Horizontal")*speed;//获取角色水平移动速度
animator.SetFloat("Speed", Mathf.Abs(move));//将玩家当前速度传给动画器的speed参数
if (Input.GetButtonDown("Jump"))//判断什么时候播放跳跃动画
{
jump = true;
animator.SetBool("Jumping", true);
}
}
//结合CharacterController2D脚本,检测是否在地面
public void OnLanding()
{
jump = false;
animator.SetBool("Jumping", false);//判断何时停止跳跃
}
void FixedUpdate()
{
cc.Move(move, jump);
}
}
结合CharacterController2D组件写一个Onlanding函数判断停止跳跃动画
发现问题:
动画只能播放一半
解决问题:
取消下面勾选,播放完整跳跃动画
同理添加Crouch动画
注意:
在crouch动画转回run或者idle时,不能取消时间的勾选,因为crouch时间太短了,需要勾选并自己手动增加动画时间。
角色爬行代码:
if (Input.GetKey(KeyCode.S))//判断什么时候播放爬行动画
{
crouch = true;
}else
{
crouch = false;
}
animator.SetBool("Crouching", crouch);
最后放上完整的代码:
CharacterController2D :
using UnityEngine;
using UnityEngine.Events;
public class CharacterController2D : MonoBehaviour
{
public float jumpForce = 400f; // 弹跳力
public bool canAirControl = false; // 在空中时,是否能控制
public LayerMask groundMask; // 定义哪一个Layer是地面
public Transform m_GroundCheck; // 用于判定地面的空物体
const float k_GroundedRadius = .1f; // 用于检测地面的小圆形的半径
private bool m_Grounded; // 当前是否在地面上
private bool m_FacingRight = true; // 玩家是否面朝右边
private Vector3 m_Velocity = Vector3.zero;
const float m_NextGroundCheckLag = 0.1f; // 起跳后的一小段时间,不能再次起跳。防止连跳的一种解决方案
float m_NextGroundCheckTime; // 过了这个时间才可能落地、才能再次起跳
// 这个角色控制器,是依靠刚体驱动的
private Rigidbody2D m_Rigidbody2D;
[Header("Events")]
[Space]
public UnityEvent OnLandEvent;
public UnityEvent OnAirEvent;
[System.Serializable]
public class BoolEvent : UnityEvent<bool> { }
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
if (OnLandEvent == null)
OnLandEvent = new UnityEvent();
if (OnAirEvent == null)
OnAirEvent = new UnityEvent();
}
private void FixedUpdate()
{
bool wasGrounded = m_Grounded;
m_Grounded = false;
// 检测与地面的碰撞
if (Time.time > m_NextGroundCheckTime)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, groundMask);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
m_Grounded = true;
if (!wasGrounded)
OnLandEvent.Invoke();
}
}
}
if (wasGrounded && !m_Grounded)
{
OnAirEvent.Invoke();
}
}
public void Move(float move, bool jump)
{
// 玩家在地面时,或者可以空中控制时,才能移动
if (m_Grounded || canAirControl)
{
// 输入变量move决定横向速度
m_Rigidbody2D.velocity = new Vector2(move, m_Rigidbody2D.velocity.y);
// 面朝右时按左键,或面朝左时按右键,都会让角色水平翻转
if (move > 0 && !m_FacingRight)
{
Flip();
}
else if (move < 0 && m_FacingRight)
{
Flip();
}
}
// 在地面时按下跳跃键,就会跳跃
if (m_Grounded && jump)
{
OnAirEvent.Invoke();
m_Grounded = false;
// 施加弹跳力
m_Rigidbody2D.AddForce(new Vector2(0f, jumpForce));
m_NextGroundCheckTime = Time.time + m_NextGroundCheckLag;
}
}
private void Flip()
{
// true变false,false变true
m_FacingRight = !m_FacingRight;
// 缩放的x轴乘以-1,图片就水平翻转了
transform.localScale = Vector3.Scale(transform.localScale, new Vector3(-1, 1, 1));
}
}
PlayerMovement :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D cc;//角色控制器组件
public Animator animator;//动画控制器组件
public float speed = 5f;//速度
float move;//水平移动方向
bool jump;//是否跳跃
bool crouch;//是否爬行
// Update is called once per frame
void Update()
{
move = Input.GetAxis("Horizontal")*speed;//获取角色水平移动速度
animator.SetFloat("Speed", Mathf.Abs(move));//将玩家当前速度传给动画器的speed参数
if (Input.GetButtonDown("Jump"))//判断什么时候播放跳跃动画
{
jump = true;
animator.SetBool("Jumping", true);
}
if (Input.GetKey(KeyCode.S))//判断什么时候播放爬行动画
{
crouch = true;
}else
{
crouch = false;
}
animator.SetBool("Crouching", crouch);
}
//结合CharacterController2D脚本,检测是否在地面
public void OnLanding()
{
jump = false;
animator.SetBool("Jumping", false);//判断何时停止跳跃
}
void FixedUpdate()
{
cc.Move(move, jump);
}
}
参考视频链接: