时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画
系列目录
【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、时长求余法(我自己起的名字,比较巧妙可能也是用的比较多的方法)
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)
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偏偏没有封装定时器,所以就需要我们深刻了解其的特性,然后选最优的方式(虽然前人已经栽树了),万里长征第一步继续吧。
时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画的更多相关文章
- 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率
系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...
- 时光煮雨 Unity3D实现2D人物移动-总结篇
系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...
- 时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现
本文首发蛮牛,次发博客园.接系列 第一篇,第二篇,本文为第三篇,再次感谢“武装三藏”在前两篇无私且精彩的问题解答 写在最前,时光煮雨,为了怀念 以下引用曾今读过的一些教程文章 其实这3种动画都有它特定 ...
- 时光煮雨 Unity3d 序列目标点的移动①
系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...
- Unity3d的序列帧动画
马上这星期就要过去了,为了完成每星期写一篇博客的目标,熬夜也要写完. 最近项目中用到了很多序列帧动画,之前看教程也接触过序列帧动画,但当时没用到,就没仔细研究,这次就借着这个机会好好总结一下序列帧动画 ...
- Unity3D学习笔记(十八):动画内容补充
动画系统: 旧动画系统(帧动画系统:关键帧驱动,关键帧记录的数据进行插值移动) 1.添加Animation,添加到父物体上 2.添加动画片段 3.添加关键帧(子物体的坐标是相对于父物体的坐标),帧之间 ...
- CSS3中2D/3D转换、过渡、动画
转换.过渡.动画 2D 转换 1.translate() 方法 通过 translate() 方法,元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数: 实例 d ...
- 【Away3D代码解读】(五):动画模块及骨骼动画
动画模块核心存放在away3d.animators包里: Away3D支持下面几种动画格式: VertexAnimator:顶点动画 SkeletonAnimator:骨骼动画 UVAnimator: ...
- Android动画总结#补间动画(Tween Animation/View Animation) #帧动画(Frame Animation/Drawable Animation)#属性动画(PropertyAnimation)
1.共有三种动画,英文名字多种叫法如下 第一种动画:补间动画(Tween Animation/View Animation) 四个:RotateAnimation旋转. AlphaAnimation透 ...
随机推荐
- 爬虫_Crawler4j的使用
Crawler4j的使用 (以下内容全部为转载,供自己查阅用) 下载地址: http://code.google.com/p/crawler4j/ Crawler4j的使用 网上对于crawler4j ...
- Redis_master-slave模式
类似mysql的master-slave模式一样,redis的master-slave可以提升系统的可用性,master节点写入cache后,会自动同步到slave上. 环境: master node ...
- 翻译-In-Stream Big Data Processing 流式大数据处理
相当长一段时间以来,大数据社区已经普遍认识到了批量数据处理的不足.很多应用都对实时查询和流式处理产生了迫切需求.最近几年,在这个理念的推动下,催生出了一系列解决方案,Twitter Storm,Yah ...
- Redis常用命令(一)
Redis::__construct描述:创建一个Redis客户端范例:$redis = new Redis(); connect, open描述:实例连接到一个Redis.参数:host: stri ...
- 服务器由于redis未授权漏洞被攻击
昨天阿里云拦截到了一次异常登陆,改了密码后就没有管他, 今天阿里云给我发消息说我的服务器可能被黑客利用,存在恶意发包行为....... 不过我不打算只是单纯的重置系统,经过一系列的查找原因后,发现被攻 ...
- jq遍历url判断是否为当前页面然后给导航上色
举例:我们希望在此页面点击“我的头像”从而加亮它的背景颜色,跟“我的爱好”的背景颜色一样. 之前: 之后: 我是这样实现的:通过判断当前url是否存在某字段,遍历字段所在的位置给加上相应的样式,我这么 ...
- PHP如何关闭notice级别的错误提示
1.在php.ini文件中改动error_reporting改为:error_reporting=E_ALL & ~E_NOTICE2.如果你不能操作php.ini文件,你可以使用如下方法在你 ...
- 数位DP HDU3652
B-number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- 您的服务器没有安装这个PHP扩展:OpenSSL(其他平台API同步需要)
今天在安装一个博客系统的时候提示这个错,在网上找了半天,自己慢慢弄出来的,具体如下: 1.找到你的php.ini 文件,将“;extension=php_openssl.dll”前面分号去掉. 2.复 ...
- 使用spring提供的LocalSessionFactoryBean来得到SessionFactory
一直不明白,spring为什么可以通过注入LocalSessionFactoryBean的bean名称来得到SessionFactory,起初以为LocalSessionFactoryBean必然是S ...
