打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
关于Unity 2d动画实现
userphoto

2014.06.10

关注
本文转自:http://gamerboom.com/archives/76709
本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦
作者:Alex Rose
Unity最近宣布推出额外的2D游戏支持,添加了Box 2D物理和一个精灵管理器。
但这里还是有些技巧需要牢记在心。逐帧更改图像只是动画制作的冰山一角,若要让你的游戏出色运行,你还得使用转换和旋转等功能。
现在让我们先从基本技巧开始。
更改帧
如果你已经准备好了制作动画的纹理,你可能会使用SpriteManager脚本的付费版本,或者Unity的新版本。假设你使用的是2D位面和纹理。这就是一个低效率的方法,但如果你是在制作一个game jam的项目,你可能会想塞入一些可行而好看,但却不一定有效的元素。这也是一种覆盖了所有步骤的全面方法,如果是在精灵管理器中则可能被删除某些步骤。
首先,你将需要一个公开的Texture[] 阵列,所以你可以将纹理拖入到Unity编辑器中的对象,以及一个在Start()中初始化到0的整数currentTexturep。下一步你需要一个像这样运行的NextTexture() 函数:
NextTexture(){
currentTexture++;
if(currentTexture>=textureArray.Length) currentTexture=0;
AnimatedPlane.renderer.material.mainTexture = textureArray[currentTexture];}
有两种简便的方法可以调用这种函数:协同程序递归和固定间隔。
使用固定间隔是最快的方法(但较不精确)。你需要一个整数计数器,在你的Start()函数中初始化到0,以及一个FixedUpdate() 函数(游戏邦注:每次都会更新,你可以在Unity时间管理器中自己调整)。
在FixedUpdate()中放置你的条件句(例如if(walking)),并在其中用conter++增加你的计时器,之后设置如下声明:
if(counter>=animationDelay){
counter=0;
NextTexture();
}
这里的animationDelay可以是你自己选择的任意值。这将以持续速度(取决于你在Unity时间管理器中设置的速度)推进帧。
第二个方法是使用递归。但这一方法的劣势在于不易处理条件句,但你还是能够获得所需要的准确延时。如果你想让特定帧延长或缩短,这一方法就尤其管用。你需要一个IEnumerator TextureChanger() 以及to StartCoroutine(TextureChanger()) in Start().
IEnumerator TextureChanger(){
yield return new WaitForSeconds(timeInterval);
if([conditions]) NextTexture();
}
这里timeInterval也是你自己选择的任意值。有了这些函数,你就可以将任意数量的纹理拖到GameObject,这样只要你提供正确的条件,它就会正确运行动画。
现在让我们做一些更有趣的操作。
平滑移动到一个点
以下公式是制作Unity 2D动画的一个诀窍:
where 0 < slidespeed < 1. I recommend 0.1f as a good slidespeed value.
这个公式允许你把对象完美移动到一个点。在滑动GUI、角色控制、关卡生成、摄像跟随、褪色/移位等操作中尤其管用。
descension(from gamasutra)
这是我即将发布的新游戏《Rotation Station》中的一个高级版本,是从一个较低点移到一个较高点,最后变成一个小泡。每个贴图都会根据该公司向下移动,但每个贴图都有随机的延时,随机的初始化旋转(也使用这一公式旋转至它所期望的方向)。
关于角色控制的例子可以参考我最近推出的《Rude Bear Radio》,在这个项目中,该公式运用于制作流畅的鼠标控制方法。
Bearo-Wing(from gamasutra)
那么,让我们看看如何将其运用于上述例子。
首先,我们需要知道鼠标位于2D区域。为了找到它,我们要先将这个代码放置于滑动GameObject的FixedUpdate()函数中:
Vector3 MousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
Input.mousePosition.y, transform.position.z-Camera.main.transform.position.z));
这里使用了鼠标的X和Y轴位置,以及从摄像机到滑动GameObject的距离来确定鼠标的2D位置和3D坐标。现在我们要从这个环节的开端来调整该公式。所以,要记住Unity中的2D步骤。
transform.position += new Vector3((MousePosition.x-transform.position.x),
(MousePosition.y-transform.position.y),0)*slidespeed;
你就只要这两行代码就搞定了!至于GUI这类东西,你可以在之后编写一个声明:
if(Mathf.Abs(finalvalue-currentvalue)
让我们再看另一个例子,《Rude Bear Radio》中的困难模式Mario台阶。
Super-Bario-Bros(from gamasutra)
其中的背景使用以下公式由黑变白:
background.renderer.material.color =
(1-factor)*background.renderer.material.color+factor*desiredcolor;
你从中可以看到它遵从的基本形式,简写就是Next = current+(final-current)*factor。代码会检查R值是否处于一定的色彩范围,如果是,它就会更改factor,令其更为迅速地褪色。如果R值非常接近于1,它就会将其所需颜色设置为黑。你还可以检查下R、G和B,并以一个阵列推进颜色。你可以在我的第二个案例项目《Rude Bear Rising》的背景中看到这种例子。
目前来看,这些都很简单,你可以照搬公式做。而下一步操作则需要考虑更多因素。
三角法和数学的重要性
三角法对动画制作来说非常重要。就算有了优秀的帧,也不一定能够令它们看起来生动美丽,有时候你根本不需要帧就能做事。
例如,我首次进入Ludum Dare工作室时,我的室友就给我画了几张图。我至今仍然记得其中的每个角色,用什么方法呢?像木偶一样将角色绑在棍子上操作。
RudeBear(from gamasutra)
这种移动方式非常简单,转换时用正弦(sin),旋转时用余弦(cos)。
为了创造这种动画,你要让波纹停止并在你松手和输入时继续,否则这种动作就会极端分散。
所以你需要一个首要变量(即我所谓的walkbob),只要对象还在移动,它就会在FixedUpdate中增加Time.deltaTime。之后就制作你的函数:
translation = maxHeight*Mathf.Sin(speed*walkbob);
rotation =  maxRoll*Mathf.Cos(speed*walkbob/2);
然后将位置和旋转设为这些值(例如transform.position = new Vector3(transform.position.x,translation,transform.position.y))。
这可以处理类似那种动作,但是还有一种动画需要考虑更多因素,这就是我所谓的三角舞,它用于制作可爱角色随着音乐摇摆起舞,例如下图:
Rude-Bear-Radio(from gamasutra)
首先,你在打算移动游戏对象时,就要选取一个浮动的initialtime = Time.time,这样你的对象才能以正确的位置和方向开始,并且不会突然跳入动作。
下一步,我们就要想想三角函数的概念。
我们使用简谐运动,其形式如下:
Y是指当前值,A是振幅,f是频率,t是运行时间,phi是指阶段。首先,我们很容易确定振幅。它是我们希望对象所具有的最大化高度或旋转。
下一个就是运行时间和阶段。我们将用(Time.time-initialtime)轻松取代t而一次性处搞定这两者。这会将φ降为0,所以最后我们只需要得到频率。我强烈推荐令此频率与你的音乐频率吻合(如果你是自己作曲,这一点很容易办到)。
如果你还不知道自己音乐的BPM,那就去摸索每个节拍,直到弄懂为止。如果你已经有节奏感,这就很好办了。如果你没有,那也不用担心,我们会利用中心极限定理。持续点触你的整首歌,每欠点触都会减少平均值中的错误。
现在你就知道它每分钟如何打节拍了。你将以60来划分这个值,找到每秒多少拍。如果你只想在半小节或一个完整的小节中使用一次动作,那就可以按2或4数值来划分。这个数值就是频率,你可以从 Mathf.PI获得pi。所以现在你要将对象的位置设为该数值。此时你只是在调整高度:
transform.position = new Vector3(transform.position.x,maxheight*
Mathf.Sin(2*Mathf.PI*frequency*(Time.time-initialtime)),transform.position.z);
但这还不够好。首先,我们要让对象合拍,这样它就得从其最大振幅开始。我们此时要使用余弦。但更重要的是,要让它从一端跳跃到另一端,这样它就不会像波纹一样滑上滑下。这时要用cos^2,这样它才会突然停在0标记,并再次走向正数。因此:
transform.position = new Vector3(transform.position.x,maxheight*Mathf.Pow(Mathf.Cos(
2*Mathf.PI*frequency*(Time.time-initialtime)),2),transform.position.z)
这里要注意舞动的高度。最终旋转要使用正弦,这样其旋转和转化就是异相的。因此:
transform.rotation = Quaternion.EulerAngles(0, maxRotation*
Mathf.Cos(2*Mathf.PI*frequency*Mathf.Sin(Time.time-initialtime)), 0);
这里要记住两件事:如果你使用一个位面,并希望它面对摄像机,这些值就不能是0和0,而必须是pi/2和–pi/2。这里我使用的是EulerAngles而不是Euler,因为Euler使用的是度数,而EulerAngles使用的是弧度。我们要做一些数学运算,我们现在要运用弧度,所以得使用EulerAngles!否则你之扣就得输入一个换算因数。
在此你可以看到我新游戏的一种类似动画,你可以用同种方法更改比例而不是位置。
RoStlogo(from gamasutra)
现在我们要讨论最后一种动画类型:
纹理补偿
你可以用自己所学到的一切来操作2D纹理补偿,以制作美妙的动画背景。你可以在《Rude Bear Radio》及其主界面中看到我对《VVVVVV》的拙劣模仿。抓取一个位面,在其上粘附一个重复纹理,编写一个FixedUpdate() 函数,并根据下属性进行调整:
renderer.material.mainTextureOffset
renderer.material.color
这将导致墙体四处滑动并改变颜色。最后,如果你想让它们看起来更有趣,还可以运用renderer.material.mainTextureScale。这可以制作一个真正有趣的视觉效果,但它很有干扰性,不要让它影响你的主要游戏玩法。
最后,你还得看一下其中的插值。这可以让动画制作更轻松,但我个人认为在第二部分中最好使用公式
http://express.ruanko.com/ruanko-express_56/tech-overnight5.html
作为一款制作3D的跨平台的游戏引擎,相对与其他2D游戏的开发工具(如cocos2d、cocos2d-x等),Unity有许多优点,如可视化、所见即所得;如跨平台;如开放的插件平台等等。作为一个初学者,简单分享一下Unity3D制作2D动画的经验。
Unity3D制作2D动画方法也有多种:
1、动画帧序列
作为常见的方法,相信很多开发者都会用。与cocos2d一样,Unity中也可以使用动画帧使你的角色动起来。示例代码:
using UnityEngine;using System.Collections;public class AnimateDemo : MonoBehaviour { public Texture[] frames; public float framesPerSecond=10; private int index; private float dTime=0; // Use this for initialization void Start () { } // Update is called once per frame void Update () { AnimaOne(); AnimaAlways(); } void AnimaAlways(){ int nowIndex=(int)(Time.time *framesPerSecond) % frames.Length; if(index!=nowIndex){ index = nowIndex; renderer.material.mainTexture = frames[index]; } } void AnimaOne(){ dTime+=Time.deltaTime; if(dTime>1/framesPerSecond){ dTime-=1/framesPerSecond; renderer.material.mainTexture = frames[++index]; if(index+1>=frames.Length){ } } }}
这里代码很详细,没有执行过,到时动画帧按照这种思路可以轻松实现。AnimaOne方法可以在动画最后一帧的时候实现其他控制;AnimaAlways方法则一直循环播放动画。
2、动画渲染
有些情况动画帧太多或者太浪费资源,我们就把动画做在一张图片上,控制相机或者材质渲染图片的位置。个人认为这种方法比较适合数据,Tag的动态显示。
例如:
public Texture imgTexture; //申明一张图片Vector2 scaleVec2=new Vector2(0.1f,1);// 控制好渲染的图片的区域renderer.material.mainTexture= imgTexture;// 动画的渲染实现renderer.sharedMaterial.SetTextureScale("_MainTex", scaleVec2);
3、上面介绍了简单的动画效果,其实在游戏中,我们经常要使游戏里的角色们动起来,位移,旋转,等等。
在Unity中,没有刚体的Object的位移和旋转都是通过Transform属性来控制的。transform下有position和rotation属性,且Unity提供了普通旋转和位移的方法。最常用的就是通过坐标增量来控制Object的动作。这里比较难缠的一点就是相对位移和绝对位移。所以在做object移动的时候要格外小心,是相对世界坐标还是其parent的坐标。
其次iTween是做2D动画比较常用的插件。其官网和其他博客对方法的使用有比较详细的介绍。这里叙述一点,就是关于iTween.Hash().iTween提供了hash表,使得简单的动画更加自然和多样。hash的参数根据iTween不同的方法而稍有差异。
比较常用的:
x,y,z,表示目标Vectore3的量;
time,时间;
easeType,过渡方式,平滑,直线,或者其他;
incomplete,当前iTween动画结束调用的动作或这方法;等等。
作为一个Unity3D的初学者,总结一下最近的工作,作为分享吧。一起学习还是在Unity的论坛和高手的博客上慢慢研究。最后祝各位看官工作顺利!谢谢!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
unity导入模型的transform.position和外框renderer.center不一样
Unity相机平滑跟随
Unity3D 游戏引擎之FBX模型的载入与人物行走动画的播放(十二)
Root Motion深度解析[Unity]
Unity实战篇 |制作一个跟随鼠标转向的 简易箭头指示标,包括 UI指向 和 3D指向标
Unity镜子效果的实现(无需镜子Shader)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服