各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://blog.csdn.net/qinyuanpei。博主今天想和大家分享的是在Unity3D中使用Mecanim动画系统来控制2D动画。相信在大家的印象中,Mecanim动画系统主要运用在3D动画中,因为Mecanim动画系统提供了像动画重定向、人体骨骼动画等3D动画的特性,那么Unity3D的Mecanim动画系统能不能用来控制2D动画呢?如果在以前,博主和大家的理解是一样的,认为Mecanim只能运用到3D动画中,对于2D动画只能使用传统的逐帧动画和骨骼动画。可是前不久有位朋友问我,为什么不使用动画组件来控制2D动画呢?博主心想啊,这Mecanim动画系统真的能控制2D动画吗?经过博主查找大量资料和亲身实践,发现Mecanim是可以用来控制2D动画的,而且由于状态机的引入,我们对动画状态的控制会变得更为简单,从写代码的角度来看,这样可以减少我们的代码量便于维护。那么好了,今天我们就来一起学习下如何使用Mecanim动画系统来控制2D动画吧!

传统2D动画的实现方式

在Unity3D中传统2D动画的实现方式是基于逐帧动画的原理实现的,这种实现方式在Unity3D没有推出Unity2D前甚至在Unity2D推出后相当长的一段时间内,基本上我们最为常用的实现方式,博主在刚开始学习Unity3D的时候通常是以2D形式来展开的,因为博主认为2D和3D在原理上基本是相通的,如果我们掌握了2D游戏的基本原理,那么在实现3D游戏的时候就会相对容易些。我们来看看一个最简单的2D动画的脚本实现:

//精灵渲染器
private SpriteRenderer mRenderer;
//精灵集合
public Sprite[] Sprites;
//FPS,即每秒钟的画面帧数
public float FPS = 24;
//精灵索引
private int index = 0;
//当前时间
private float currentTime = 0;void Start ()
{mRenderer = GetComponent<SpriteRenderer>();
}void Update ()
{//获取当前时间currentTime += Time.deltaTime;//如果达到了更新画面的时间if(currentTime >= 1 / FPS){//使索引增加index += 1;//清除时间记录currentTime = 0;//当索引更新到最后一帧时,索引重置if(index >= Sprites.Length){index = 0;}}//更新画面mRenderer.sprite = Sprites[index];
}

通过分析,我们可以发现这段脚本存在以下问题: 
* 动画维护困难:每增加一个动画就需要添加一个数组,不仅增加了动画的维护难度,同时降低了脚本的效率。 
* 状态维护困难:因为在Update方法里实现的是一个动画,因此当我们需要在各个动画状态间进行切换的时候,我们需要使用更多的代码来维护相关逻辑。

使用Mecanim动画系统的实现方式

为了解决传统的2D动画实现方式中存在的动画维护困难、状态维护困难这两个问题,我们需要一种更好的方案来实现2D动画的控制,这种方案需要提供较为方便的动画维护功能,即各个动画是独立的,当改变了某一个动画时,其余的动画不会发生改变。其次,这种方案需要提供较为方便的状态维护功能,即各个动画状态切换是方便的,我们可以更好地从这一种状态切换到另一种状态。关于动画状态切换,大家可以去了解下有限状态机(FSM)的概念,这里我们不做深入的探究,这里我们选择Unity3D的Mecanim动画系统,因为Mecanim动画系统正好解决了这两个问题。好了,下面我们来一起学习一个2D动画的实例: 
首先我们在场景中创建一个名为PlayerController的空物体,然后在该物体的下面增加一个精灵组件(Sprite),并将其命名为PlayerSprite,这样做的好处是Unity3D将为我们自动创建较为规范的命名。好了,现在我们选择PlayerController这个物体,然后通过Window->Animation菜单打开Animation窗口: 

首先我们点击AddCurve按钮,此时将弹出一个对话框让我们保存动画文件,这里我们存储为Player@Idle.anim,并将其保存在项目目录下的Animations\Player目录下,这样可以方便我们维护和查找特定的动画文件。在保存完动画文件后,此时会弹出如下的界面,我们选择PlayerSprite节点下的SpriteRenderer,然后选择Sprite,因为这里我们的2D动画主要是通过改变SpriteRenderer的Sprite属性来实现的,最后我们点击Sprite节点后面的加号来完成对象的选取。此时会在动画窗口中显示时间轴和刻度线,我们将在这里完成动画的编辑。大家可以注意到默认情况下,动画面板添加了两帧,即第1帧和最后一帧,其总时间是1秒,同时我们注意到这里有一个采样率(Sample),其实这就是当前动画的FPS了。好了,现在我们开始制作第一个动画:

在资源文件夹中,我们可以找到当前动画的图片素材,注意到这个图片中总共有12帧画面,因此我们可以按照0.05s的间隔来分配整个时间轴,所以我们可以这样添加帧:

好了,现在我们就完成了一个Idle动画的制作,现在打开角色的动画控制器PlayerController,这是Unity3D为我们自动创建的一个动画控制器,因为我们现在只有一个Idle动画,所以在Animaotr窗口中我们可以看到只有一个Idle状态,现在我们将这个状态设为默认状态。好了,现在我们可以直接运行游戏,发现在场景中角色开始循环播放Idle动画了。好了,现在让我们重复刚才的步骤,来完成角色的其余动画。

经过一番努力,我们现在已经完成了角色所有动画的制作,现在我们来设计角色的动画状态机:

设计好角色的动画状态机后我们开始来编写脚本,以实现角色动画的控制:

using UnityEngine;
using System.Collections;public class PlayerController : MonoBehaviour {public enum PlayerState{Idle,Move,LightAttack,WeightAttack}public PlayerState State=PlayerState.Idle;//玩家移动速度public float WalkSpeed = 0.75f;public float RunSpeed = 1.5f;//玩家跳跃力的强度public float JumpForce = 200f;//位置限制public float MinX = -5.80f;public float MaxX =  5.80f;public float MinY = -1.80f;public float MaxY =  0.35f;//玩家朝向,默认朝右public bool isFaceRight = true;//动画组件private Animator mAnim;//2D刚体private Rigidbody2D mRig2D;void Start () {mAnim=GetComponent<Animator>();mRig2D=GetComponent<Rigidbody2D>();}void Update(){SpriteMove();SpriteAttack();SpriteJump();SpriteIdle();}/// <summary>/// 精灵Idle/// </summary>private void SpriteIdle(){//当玩家无任何操作时恢复到Idle状态if (!Input.anyKey){mAnim.SetBool("Jump", false);mAnim.SetBool("Attack", false);mAnim.SetBool("BigAttack", false);mAnim.SetBool("Skill", false);mAnim.SetBool("BigSkill", false);State=PlayerState.Idle;}}/// <summary>/// 精灵攻击/// </summary>private void SpriteAttack(){//轻击,键位Jif(Input.GetKey(KeyCode.J)){mAnim.SetBool("Attack", true);State=PlayerState.LightAttack;}//重击,键位Kif(Input.GetKey(KeyCode.K)){mAnim.SetBool("BigAttack", true);State=PlayerState.WeightAttack;}}/// <summary>/// 精灵跳跃/// </summary>private void SpriteJump(){if (Input.GetKey(KeyCode.I)){mAnim.SetBool("Jump", true);mRig2D.AddForce(new Vector2(0, Time.deltaTime * JumpForce), ForceMode2D.Impulse);}}private void SpriteMove(){float h = Input.GetAxis("Horizontal");float v = Input.GetAxis("Vertical");Vector2 mPos = mRig2D.position;mAnim.SetFloat("Speed", Mathf.Sqrt(h * h + v * v));float mPosX, mPosY;if (Mathf.Sqrt(h * h + v * v) > 0.5f){mPosX = mPos.x + h * Time.deltaTime * RunSpeed;mPosY = mPos.y + v * Time.deltaTime * RunSpeed;}else{mPosX = mPos.x + h * Time.deltaTime * WalkSpeed;mPosY = mPos.y + v * Time.deltaTime * WalkSpeed;}mRig2D.MovePosition(new Vector2(mPosX, mPosY));if (h > 0 && !isFaceRight){FlipSrite();}else if (h < 0 && isFaceRight){FlipSrite();}}void FlipSrite(){if(isFaceRight){transform.rotation=Quaternion.Euler(0,180,0);isFaceRight=false;}else{transform.rotation=Quaternion.Euler(0,0,0);isFaceRight=true;}}
}

好了,现在我们可以来看看最终的效果,博主这里是想利用这些素材来制作一个横板过关的游戏,可是因为文章篇幅有限,所以这部分内容只能留到以后再和大家分享了。

Mecanim动画系统应用扩展

好了,到现在为止,基于Mecanim动画系统的2D动画控制基本上讲解完了。下面我们说说Mecaanim动画系统应用扩展。通过前面的学习,我们知道Unity2D使用的Mecanim动画系统主要是通过改变游戏体的属性来实现某种特定的动画效果的,例如我们这里的动画是通过改变角色精灵附加的SpriteRenderer组件的Sprite属性来实现的,因此从本质上来说Unity2D的动画控制器是一种属性动画。总体来说,Unity2D可以实现以下类型的动画: 
* 位移动画:通过Transform组件的Position属性实现 
* 旋转动画:通过Transform组件的Rotation属性实现 
* 伸缩动画:通过Transform组件的Scale属性实现 
* 渐变动画:通过更改指定组件的颜色或材质实现 
* 脚本动画:通过更改指定脚本的变量或字段实现

好了,这就是今天这篇文章的全部内容了,希望大家喜欢!

Unity3D游戏开发之使用Mecanim动画系统控制2D动画相关推荐

  1. [Unity3D]Unity3D游戏开发之当仙剑奇侠传遇上Mecanim动画系统

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是 blog.csdn.net/qinyuanpei.博主总算赶在这个月底写出了这篇文章.这个月因为期末考试一直没时间研究太多关于技术方面的东西, ...

  2. Unity3D游戏开发之仿仙剑奇侠传一2D游戏 (一)

    今天要和大家分享的是基于Unity3D开发2D游戏,博主一直钟爱于国产武侠RPG,这个我在开始写Unity3D游戏开发系列文章的时候就已经说过了,所以我们今天要做的就是利用Unity3D来实现在2D游 ...

  3. Unity3D游戏开发-宣雨松读书摘要(2015-4-17 18:36)

    本书基于Unity3.5编写,通过丰富的游戏实例,以JavaScript与C#两种语言介绍Unity开发. Unity3D游戏开发-宣雨松 序 它支持JavaScript.C#.Boo三种脚本语言 ...

  4. Unity3D游戏开发之仿仙剑奇侠传角色控制效果

    在上一篇文章中,我们从Unity3D为我们提供的相机原型实现了非编码式的小地图,如果结合GUI在这个小地图下面绘制一些背景贴图,相信整体的效果会更好一些.博主希望这个问题大家能够自己去做更深入的研究, ...

  5. 2018年Unity3D游戏开发前景预测

    随着移动手机游戏盛行,游戏开发人才供不应求,如何成为一名优秀的开发者?掌握Unity3D开发技术是不可跳过的一环.随着移动互联网的发展,移动端游戏日益盛行,据了解,Unity全球开发者超过300万,1 ...

  6. 《学Unity的猫》——第十八集:Unity3D游戏开发工程师笔试刷题,皮皮收到面试邀请

    文章目录 18.1 皮皮收到面试邀请 18.2 面试题库相关网站 18.2.1 牛客网 18.2.2 领扣LintCode 18.2.3 力扣LeetCode 18.3 优质学习网站 18.3.1 菜 ...

  7. [Unity3D]Unity3D游戏开发之怪物AI

    大家好,欢迎大家关注由我为大家带来的Unity3D游戏开发系列文章,我的博客地址为:http://blog.csdn.net/qinyuanpei. 在上一篇文章中,我们基本上实现了一个小地图的功能, ...

  8. 2019年Unity3D游戏开发前景预测及总结

    由于现在随着互联网时代的到来,人们上网玩游戏的越来越多,导致游戏开发人才供不应求,如果你想成为一名优秀的开发者,那么掌握Unity3D开发技术是不可跳过的一环.随着移动互联网的发展,移动端游戏日益盛行 ...

  9. Unity设计模式之-Unity3d游戏开发设计模式之子类沙盒模式

    ** 请关注微信公众号获取最新消息 ** 原文链接:http://blog.csdn.net/u013108312/article/details/52208635 本篇文章我们来看下Unity3d游 ...

最新文章

  1. JQuery DOM基本操作
  2. 设计模式三大类及六大设计原则
  3. IP头,TCP头,UDP头,MAC帧头定义(转)
  4. 英特尔将推Nervana神经网络处理器,要让DL训练提速100倍
  5. idm下载工具 Win平台下最好的下载工具 无广告 免打扰 静默下载
  6. k8s数据持久化实验
  7. FileOutputStream输出流
  8. 逆天通用水印扩展篇~新增剪贴板系列的功能和手动配置,卸除原基础不常用的功能...
  9. 按头安利!好看又实用的电机 SolidWorks模型素材看这里
  10. 生活小常识,哪些药物不能混合用?
  11. idea导入myeclipse项目以后报错,配置文件灰色以及 com.alipay.demo.trade.Main test_trade_precreate 严重: 系统异常,预下单状态未知
  12. 主流量化交易策略:统计套利交易策略
  13. 老男孩教育运维班100台规模集群全网数据备份项目上机实战
  14. LostDungeon迷失地牢-壹
  15. 合工大路强java第四次作业第2题
  16. 精睿 ESS EAV 【中文商业特别版+纯净版-官方升级】【2.11更新3.0.685.0】
  17. maven通过mvn命令添加oracle依赖
  18. Java操作wkhtmltopdf实现Html转PDF
  19. Alpha-Beta 剪枝
  20. 代码: 0x80131500:应用商店崩溃了修复

热门文章

  1. 小白linux bash 学习前奏二 vi操作
  2. 【VBScript恶搞代码】关不掉的窗口
  3. 全国地级市面板Excel数据(1990-2019年)
  4. 图片放大不清晰怎么办?​无损放大可解决
  5. 用友携国资国企走进浙江龙游,共探区县国资智慧监管新样板
  6. 有关于采集 负电压的一二事,STM32测量电流
  7. DSPE-PEG-VAP/DCDX/LyP-1/M2pep/GLP-1/HP2/FNB/CPPs/CGKRKb 磷脂-聚乙二醇-多肽
  8. Android Studio第九期 - QQ计步器效果
  9. Android 四大组件 -- BroadcastReceiver(广播)
  10. 不用药物控制高血压的 10 种方法