码迷,mamicode.com
首页 > 编程语言 > 详细

Unity3D初学之2D动画制

时间:2015-03-17 00:26:33      阅读:323      评论:0      收藏:0      [点我收藏+]

标签:

作者: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初学之2D动画制

标签:

原文地址:http://www.cnblogs.com/lihonglin2016/p/4343159.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!