原理

看过前篇的朋友,一定能猜到这篇的内容了,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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using System.Collections;
public class PlayerAnimator : MonoBehaviour {
    public Sprite[] sprites;
    public float framesPerSecond;
    private SpriteRenderer spriteRenderer;
    // Use this for initialization
    void Start () {
        spriteRenderer = GetComponent<Renderer>() as SpriteRenderer;
    }
     
    // Update is called once per frame
    void Update () {
        int timeIndex = (int)(Time.timeSinceLevelLoad * framesPerSecond);
        int index = timeIndex % sprites.Length;
        spriteRenderer.sprite = sprites[index];
    }
}

  

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

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

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

  

B、Native2D 序列帧动画 实现

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

总结

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

转载地址:http://www.cnblogs.com/IlidanStormRage/p/6043642.html

Unity3D实现2D人物动画① UGUINative2D序列帧动画相关推荐

  1. 时光煮雨 Unity3D实现2D人物动画① UGUINative2D序列帧动画

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

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

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

  3. Canvas动画:精灵动画(序列帧动画)

    精灵动画(序列帧动画) 播放精灵动画用到的绘图方法是drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh); 精灵动画原理:每次只分割出其中一副图像并绘制出来,每隔一段时间便 ...

  4. unity3d中水草海草摇动效果顶点动画材质

    因为最近要尝试在untiy3d做写实海底的效果,上图为版本5.5里面实现的效果 为了让画面更加逼真,海底植物必不可少 然而海底的海藻海草之类需要加上动画就比较麻烦了 一般的骨骼动画加起来比较麻烦,而且 ...

  5. unity ParticleSystem 实现序列帧动画效果(一)

    用粒子系统实现序列帧动画优势: 先附上一个 介绍序列帧实现方式比较的链接 点击打开链接 在该链接里说较为倾向于使用该方式俩实现序列帧动画,那么具体的好处又有哪些呢? 此处再贴一个链接,这里介绍了下粒子 ...

  6. 对于基本的捕鱼游戏设计思路(四)——序列帧动画

    今天,我带领大家学习一下Cocos2d-x 2.0的序列帧动画.在Cocos2d-x中,提供了相应的一些类和方法,可以方便的生成序列帧动画,这样我们就可以制做各种人物动作以及动画效果.这就是鱼在水里游 ...

  7. 【游戏动画】游戏动画总结

    动画的概念 为什么通过这种方式能产生动画的效果呢? 动画的形成过程是由于一张一张的图片快速在人眼识别后,并在大脑里形成短暂影像,因为人眼的视觉暂留,从而每一张图片的动作和场景形成连贯性而形成的.视觉暂 ...

  8. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四)实现2D人物动画①

    通过前面的学习,我们掌握了如何动态创建物体移动动画,那么接下来我将介绍WPF中如何将物体换成2D游戏角色,并通过使用前面所讲的DispatcherTimer计时器来实现2D人物角色的各种动作动画. 动 ...

  9. unity3d序列帧动画无法显示坑

    序列帧动画不能放在canvas2d节点的子节点下,否则不能显示.就算改了sprite 的(pixel unit)属性改变大小等,也只是在编辑环境下看得见,且还有透明度,实际运行中完全看不见. 序列帧动 ...

最新文章

  1. crt 运行时库dll跨模块传递crt对象,出现的崩溃问题
  2. Nature综述:微生物构成的氮循环网络
  3. 34场报告,ICLR 2021 中国预讲会节后举办,抓紧报名
  4. 二值神经网络(Binary Neural Networks)最新综述
  5. 技术创作101训练营:从0到1教你搭建自己的技术品牌
  6. 报表没完没了怎么办? | 润乾集算器提效报表开发
  7. php网页生命周期函数,PHP的生命周期
  8. 【交互】【随机】Lost Root(CF1061F)
  9. 第一次“2016第三届科学数据大会”新闻发布会在上海举行
  10. 软件漏洞-泛微OA-汇总
  11. 实用的Portraiture滤镜磨皮教程
  12. 即时获取最新全国省市区县地图json数据(亲测可用)以及echarts中使用中国地图
  13. Android聊天软件开发(基于网易云IM即时通讯)——发送图片消息(五)
  14. 分布式定时任务解决方案
  15. 腾讯云cdn设置 php,腾讯云免费CDN开通及接入教程
  16. 苹果手机文件夹中服务器连接在哪,如何访问苹果手机上的共享文件夹?
  17. 面试时如何做好5分钟自我介绍?
  18. web端微信二维码自定义样式
  19. SAP HR 常用函数*持续更新中...
  20. 2019春季学期总结

热门文章

  1. 武汉科技大学计算机二本专业,二本录取发一本学历 武汉科技大学校方确认此事...
  2. 中南林业科技大学第十一届程序设计大赛题解
  3. ubuntu安装nvidia驱动,终于可以控制亮度了,ubuntu18.04+联想Y7000+gtx1650
  4. RecyclerView实现上拉加载更多的正确姿势
  5. wordpress 自定义_如何在WordPress中添加自定义字体
  6. android-ndk-r17c,使用android-ndk-r17c构建ffmpeg 4.2.1时遇到的问题
  7. docker安装nfs文件服务器,使用docker搭建nfs实现容器间共享文件
  8. 从小游戏到APP,登顶iOS排行榜,这款PVP竞技篮球手游都做了些什么?
  9. Burp suite—Intruder中Attack Type模式详解
  10. iOS获取系统时间的各种方式