系列目录

【Unity3D基础】让物体动起来①--基于UGUI的鼠标点击移动

【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动

时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现

时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画

时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率

原理

看过前篇的朋友,一定能猜到这篇的内容了,2D人物动画,这是一个老生常谈的话题,很多人都写过或者提供过类似的代码,本文还是遵守着重原理,代码次之的原则。下面是根据以前自己学习的时候学习“深蓝色右手”WPF游戏教程的“WPF/Silverlight动画及游戏系列教程”,先结合Unity3d技术改编的原理文字

动态实现2D人物角色动画目前有两种主流方法,下面我会分别进行介绍。
      第一种方法我称之为图片切换法,准备工作:首先通过3DMAX等工具3D渲染2D的方法制作出角色,然后将角色每个动作均导出8个方向每方向若干帧的系列图片(如果是有方向的魔法图片,很多2D-MMORPG往往会导出16个方向的系列帧图片以求更为逼真),即将每个人物每个动作的各方向的每帧均存成一张图片,如下图仅以从破天一剑游戏中提取的素材为例:

(特别申明:本系列教程所使用的如有注明归属权的图片素材均来源于网络,请勿用于商业用途,否则造成的一切后果均与本人无关。)

从上图可以看到,我将人物向右方跑步共8帧图片通过Photoshop分别将画布等比例扩大成150*150象素图片(因为是提取的素材,初始宽和高是不均衡值,所以必须扩大成自己的需求,这样人物会在图片中居中,并且为后期加入武器或坐骑留好余地。稍微的偏离也可以在后期进行微调),并将他们从开始到结束分别命名为0.png,1.png,2.png,3.png,4.png,5.png,6.png,7.png,然后将这8张图片保存到相关目录下,到此准备工作终于结束了

这里在WPF中有一个UI线程级别的定时器DispatcherTimer,而Unity中没有提供类似的机制(或许是我不知道),Unity主要是心跳来控制的也就是Update函数了,但是这里的原理就是帧动画,每个多少帧变化一下player的动作图片即可,但我们知道帧就是和时间相关的。

简单的说:就是定义一个图片数组,然后实现一个定时器,时间到了就获取数组里的一张图,替换精灵的背景图片。

实现

这里我们把问题分解主要是两个子问题,一、定时获取图片替换精灵背景,简称定时器;二、数组的图片循环获取,简称数组顺序遍历

先从软柿子开始,二比较简单,一个数组,加一个全局基数器变量 搞定

private int currentTexture = 0;
public Sprite[] textureArray;
private SpriteRenderer spriteRenderer;

//遍历数组 到数组未重新回到0索引

void NextTexture()
{
    currentTexture++;
    if (currentTexture >= textureArray.Length)
    {
        currentTexture = 0;
    }

spriteRenderer.sprite = textureArray[currentTexture];
}

一、定时器,稍微麻烦点,Unity3d并没有提供像样的UI定时器封装,这里为了验证 这种定帧动画的原理,我用几种Unity3d中定时器机制分别实现了动画功能,实际开发中用的A和D方法比较多,至少我查了不少教程基本是A和D

首先是变量

private float animationDeltaTime;
private float animationDelay = 5 / 60f;

A、Update 心跳延时定时器

void Update()
{
    animationDeltaTime += Time.deltaTime;
    // Debug.Log(animationDeltaTime);
    if (animationDeltaTime >= animationDelay)
    {
        animationDeltaTime = 0;

NextTexture();
    }
}

B、协程递归定时器

void Start()
{
    spriteRenderer = GetComponent<SpriteRenderer>() as SpriteRenderer;
    StartCoroutine(TextureChanger()); 
}

IEnumerator TextureChanger()
{
    yield return new WaitForSeconds(animationDelay);
    if (true)
    {
        //Debug.Log(animationDeltaTime);
        NextTexture();
        StartCoroutine(TextureChanger());
    }
}

C、InvokeRepeating定时器

void Start()
{
    spriteRenderer = GetComponent<SpriteRenderer>() as SpriteRenderer;
    InvokeRepeating("NextTexture", 1, 0.1f);//1秒后调用LaunchProjectile () 函数,之后每5秒调用一次     
}

D、时长求余法(我自己起的名字,比较巧妙可能也是用的比较多的方法)

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class PlayerAnimator : MonoBehaviour {
  5.  
  6. public Sprite[] sprites;
  7. public float framesPerSecond;
  8.  
  9. private SpriteRenderer spriteRenderer;
  10. // Use this for initialization
  11. void Start () {
  12. spriteRenderer = GetComponent<Renderer>() as SpriteRenderer;
  13. }
  14.  
  15. // Update is called once per frame
  16. void Update () {
  17. int timeIndex = (int)(Time.timeSinceLevelLoad * framesPerSecond);
  18. int index = timeIndex % sprites.Length;
  19. spriteRenderer.sprite = sprites[index];
  20.  
  21. }
  22. }

  

原理的代码分析和代码展示完毕,下面是自己在网上找的前人分享的一些代码,自测可以运行,主要的问题还是一句老话,“原理很简单,现实很残酷”,实际一个简单的2d动画涉及的东西很多,比如性能效率,状态控制,封装合理性等等吧。

A、Unity3d UGUI序列帧动画 实现 (原文地址:http://www.cnblogs.com/mrblue/p/5191183.html)

  1. using UnityEngine;
  2.  
  3. using System.Collections;
  4.  
  5. using System.Collections.Generic;
  6.  
  7. using UnityEngine.UI;
  8.  
  9. using System;
  10.  
  11. [RequireComponent(typeof(Image))]
  12.  
  13. public class UGUISpriteAnimation : MonoBehaviour
  14.  
  15. {
  16.  
  17. private Image ImageSource;
  18.  
  19. private int mCurFrame = 0;
  20.  
  21. private float mDelta = 0;
  22.  
  23. public float FPS = 5;
  24.  
  25. public List<Sprite> SpriteFrames;
  26.  
  27. public bool IsPlaying = false;
  28.  
  29. public bool Foward = true;
  30.  
  31. public bool AutoPlay = false;
  32.  
  33. public bool Loop = false;
  34.  
  35. public int FrameCount
  36.  
  37. {
  38.  
  39. get
  40.  
  41. {
  42.  
  43. return SpriteFrames.Count;
  44.  
  45. }
  46.  
  47. }
  48.  
  49. void Awake()
  50.  
  51. {
  52.  
  53. ImageSource = GetComponent<Image>();
  54.  
  55. }
  56.  
  57. void Start()
  58.  
  59. {
  60.  
  61. if (AutoPlay)
  62.  
  63. {
  64.  
  65. Play();
  66.  
  67. }
  68.  
  69. else
  70.  
  71. {
  72.  
  73. IsPlaying = false;
  74.  
  75. }
  76.  
  77. }
  78.  
  79. private void SetSprite(int idx)
  80.  
  81. {
  82.  
  83. ImageSource.sprite = SpriteFrames[idx];
  84.  
  85. ImageSource.SetNativeSize();
  86.  
  87. }
  88.  
  89. public void Play()
  90.  
  91. {
  92.  
  93. IsPlaying = true;
  94.  
  95. Foward = true;
  96.  
  97. }
  98.  
  99. public void PlayReverse()
  100.  
  101. {
  102.  
  103. IsPlaying = true;
  104.  
  105. Foward = false;
  106.  
  107. }
  108.  
  109. void Update()
  110.  
  111. {
  112.  
  113. if (!IsPlaying || 0 == FrameCount)
  114.  
  115. {
  116.  
  117. return;
  118.  
  119. }
  120.  
  121. mDelta += Time.deltaTime;
  122.  
  123. if (mDelta > 1 / FPS)
  124.  
  125. {
  126.  
  127. mDelta = 0;
  128.  
  129. if(Foward)
  130.  
  131. {
  132.  
  133. mCurFrame++;
  134.  
  135. }
  136.  
  137. else
  138.  
  139. {
  140.  
  141. mCurFrame--;
  142.  
  143. }
  144.  
  145. if (mCurFrame >= FrameCount)
  146.  
  147. {
  148.  
  149. if (Loop)
  150.  
  151. {
  152.  
  153. mCurFrame = 0;
  154.  
  155. }
  156.  
  157. else
  158.  
  159. {
  160.  
  161. IsPlaying = false;
  162.  
  163. return;
  164.  
  165. }
  166.  
  167. }
  168.  
  169. else if (mCurFrame<0)
  170.  
  171. {
  172.  
  173. if (Loop)
  174.  
  175. {
  176.  
  177. mCurFrame = FrameCount-1;
  178.  
  179. }
  180.  
  181. else
  182.  
  183. {
  184.  
  185. IsPlaying = false;
  186.  
  187. return;
  188.  
  189. }
  190.  
  191. }
  192.  
  193. SetSprite(mCurFrame);
  194.  
  195. }
  196.  
  197. }
  198.  
  199. public void Pause()
  200.  
  201. {
  202.  
  203. IsPlaying = false;
  204.  
  205. }
  206.  
  207. public void Resume()
  208.  
  209. {
  210.  
  211. if (!IsPlaying)
  212.  
  213. {
  214.  
  215. IsPlaying = true;
  216.  
  217. }
  218.  
  219. }
  220.  
  221. public void Stop()
  222.  
  223. {
  224.  
  225. mCurFrame = 0;
  226.  
  227. SetSprite(mCurFrame);
  228.  
  229. IsPlaying = false;
  230.  
  231. }
  232.  
  233. public void Rewind()
  234.  
  235. {
  236.  
  237. mCurFrame = 0;
  238.  
  239. SetSprite(mCurFrame);
  240.  
  241. Play();
  242.  
  243. }
  244.  
  245. }

  

B、Native2D 序列帧动画 实现

这部分代码已经在上文“D、时长求余法(我自己起的名字,比较巧妙可能也是用的比较多的方法)”中贴出,这里不再重复

总结

实际上“序列帧动画”的实现原理很简单,就是一个定时器,但是Unity3d偏偏没有封装定时器,所以就需要我们深刻了解其的特性,然后选最优的方式(虽然前人已经栽树了),万里长征第一步继续吧。

时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画的更多相关文章

  1. 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  2. 时光煮雨 Unity3D实现2D人物移动-总结篇

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  3. 时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现

    本文首发蛮牛,次发博客园.接系列 第一篇,第二篇,本文为第三篇,再次感谢“武装三藏”在前两篇无私且精彩的问题解答 写在最前,时光煮雨,为了怀念 以下引用曾今读过的一些教程文章 其实这3种动画都有它特定 ...

  4. 时光煮雨 Unity3d 序列目标点的移动①

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  5. Unity3d的序列帧动画

    马上这星期就要过去了,为了完成每星期写一篇博客的目标,熬夜也要写完. 最近项目中用到了很多序列帧动画,之前看教程也接触过序列帧动画,但当时没用到,就没仔细研究,这次就借着这个机会好好总结一下序列帧动画 ...

  6. Unity3D学习笔记(十八):动画内容补充

    动画系统: 旧动画系统(帧动画系统:关键帧驱动,关键帧记录的数据进行插值移动) 1.添加Animation,添加到父物体上 2.添加动画片段 3.添加关键帧(子物体的坐标是相对于父物体的坐标),帧之间 ...

  7. CSS3中2D/3D转换、过渡、动画

    转换.过渡.动画 2D 转换 1.translate() 方法 通过 translate() 方法,元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数: 实例 d ...

  8. 【Away3D代码解读】(五):动画模块及骨骼动画

    动画模块核心存放在away3d.animators包里: Away3D支持下面几种动画格式: VertexAnimator:顶点动画 SkeletonAnimator:骨骼动画 UVAnimator: ...

  9. Android动画总结#补间动画(Tween Animation/View Animation) #帧动画(Frame Animation/Drawable Animation)#属性动画(PropertyAnimation)

    1.共有三种动画,英文名字多种叫法如下 第一种动画:补间动画(Tween Animation/View Animation) 四个:RotateAnimation旋转. AlphaAnimation透 ...

随机推荐

  1. wamp环境下安装memcached最好的详解教程^.^:(只需要3个步骤 )

    win8.1 wampserver2.5 -Apache-2.4.9-Mysql-5.6.17-php5.5.12-64b 可以参考一下部分讲解有图,我就是看4-5个讲解,结合有一篇的截图最终才搞定的 ...

  2. Android -- ImageView通过Bitmap得到网上的图片资源

    1. 效果图

  3. org.openqa.selenium.StaleElementReferenceException

    org.openqa.selenium.StaleElementReferenceException如何解啊.什么原因造成的,貌似有时会出现,有时不会出现

  4. 如何打印出lua里table的内容

    不像开发as3时用fb有强大的断点调试功能,一般lua开发不用什么高级的ide,貌似也没有适合的,就直接用sublime.exvim等文本编辑器,直接编译运行看结果.所以不能很方便的知道变量值,特别是 ...

  5. [CareerCup] 15.1 Renting Apartment 租房

    Write a SQL query to get a list of tenants who are renting more than one apartment. -- TABLE Apartme ...

  6. AsyncTask的使用

    简单的AnsyTask的使用demo 1.定义一个模拟网络操作的类 package com.example.administrator.myapplication; /** * Created by ...

  7. Spring 定时器

    <!-- 对定时任务进行引用 --> <bean id="schedulerFactory" class="org.springframework.sc ...

  8. SubmitText 中配置lua 运行环境

    一 新建编译系统 二.使用新建的编译系统 三配置 { "cmd": ["lua", "$file"], "file_regex&q ...

  9. Layer弹窗组件

    layer是一款近年来备受青睐的web弹层组件,她具备全方位的解决方案,致力于服务各水平段的开发人员,您的页面会轻松地拥有丰富友好的操作体验. Layer的开发手册和下载地址 http://layer ...

  10. JavaScript入门篇 第一天

    使用<script>标签在HTML网页中插入JavaScript代码.注意, <script>标签要成对出现,并把JavaScript代码写在<script>< ...