2016-09-12 11:44:09 qq_26270779 阅读数 625

unity3d如何播放帧动画,我写的这种方法比较麻烦。得一张一张图片的往数组里拖,适合图片较少的帧动画。

效果如下:



上代码吧:

using UnityEngine;
using System.Collections;


public class play : MonoBehaviour {
    public GameObject startscene;//页面
    public GameObject selectscene;

    public float animSpeed = 10;//1秒播放10帧图片
    private float animTimeInterval = 0;//每一帧的时间间隔

    public SpriteRenderer lantiao;//渲染器
    public Sprite[] lantiaoSpriteArray;//创建精灵数组
    private int lantiaoIndex = 0;//当前播放的帧的索引
    private int lantiaoLength = 0;//数组长度
    private float lantiaoTimer = 0;//计时器

    public bool m_bpress; //是否按下


	// Use this for initialization
	void Start () {
        animTimeInterval = 1 / animSpeed;//每一帧的时间间隔
        lantiaoLength = lantiaoSpriteArray.Length;
	}
    void OnPress(bool isPressed) 
    {
        print("press");
         if (isPressed) 
         {
             m_bpress = isPressed;
         } 
         else 
         {
             m_bpress = isPressed; 
         } 
    }
	
	// Update is called once per frame
	void Update () {
        if (m_bpress)
        {
            print("m_bpress:" + m_bpress);
            
            lantiaoTimer += Time.deltaTime;
            if (lantiaoTimer > animTimeInterval)
            {
                print("in if"); 
                lantiaoTimer -= animTimeInterval;//计时器减去一个周期的时间
                lantiaoIndex++;//自动播放下一帧
                if (lantiaoIndex >= lantiaoLength)
                {
                    startscene.SetActive(false);
                    selectscene.SetActive(true);
                }
                lantiaoIndex %= lantiaoLength;//判断索引是否超过长度
                lantiao.sprite = lantiaoSpriteArray[lantiaoIndex];
            }
        }
        else
        {
            lantiao.sprite = lantiaoSpriteArray[0];
            lantiaoIndex = 0;
        }
	}
}


2018-02-06 18:01:34 SerenaHaven 阅读数 2939

序列帧动画经常用到,最直接的方式就是用Animation录制。但某些情况下这种方式并不是太友好,需要靠代码的方式进行序列帧动画的实现。

代码实现序列帧动画,基本的思路是定义一个序列帧的数组/列表,根据时间的流逝来确定使用哪一帧并更新显示。

NGUI的UI2DSpriteAnimation已经实现了此功能,但是它支持的目标只有Native2D的SpriteRenderer组件或者NGUI自身的UI2DSprite组件,并不支持UGUI的Image组件。

当然可以通过改写源码的方式来添加对Image组件的支持,不过秉着学习的目的,我这里重新写了一个同时支持Image组件和SpriteRenderer组件的序列帧动画播放器。

代码如下,注释写的很详细了,不再赘述。

using UnityEngine;
using UnityEngine.UI;
using System;

/// <summary>
/// 序列帧动画播放器
/// 支持UGUI的Image和Unity2D的SpriteRenderer
/// </summary>
public class FrameAnimator : MonoBehaviour
{
	/// <summary>
	/// 序列帧
	/// </summary>
	public Sprite[] Frames{ get { return frames; } set { frames = value; } }

	[SerializeField]private Sprite[] frames = null;

	/// <summary>
	/// 帧率,为正时正向播放,为负时反向播放
	/// </summary>
	public float Framerate { get { return framerate; } set { framerate = value; } }

	[SerializeField] private float framerate = 20.0f;

	/// <summary>
	/// 是否忽略timeScale
	/// </summary>
	public bool IgnoreTimeScale{ get { return ignoreTimeScale; } set { ignoreTimeScale = value; } }

	[SerializeField]private bool ignoreTimeScale = true;

	/// <summary>
	/// 是否循环
	/// </summary>
	public bool Loop{ get { return loop; } set { loop = value; } }

	[SerializeField]private bool loop = true;

	//动画曲线
	[SerializeField]private AnimationCurve curve = new AnimationCurve (new Keyframe (0, 1, 0, 0), new Keyframe (1, 1, 0, 0));

	/// <summary>
	/// 结束事件
	/// 在每次播放完一个周期时触发
	/// 在循环模式下触发此事件时,当前帧不一定为结束帧
	/// </summary>
	public event Action FinishEvent;

	//目标Image组件
	private Image image;
	//目标SpriteRenderer组件
	private SpriteRenderer spriteRenderer;
	//当前帧索引
	private int currentFrameIndex = 0;
	//下一次更新时间
	private float timer = 0.0f;
	//当前帧率,通过曲线计算而来
	private float currentFramerate = 20.0f;

	/// <summary>
	/// 重设动画
	/// </summary>
	public void Reset ()
	{
		currentFrameIndex = framerate < 0 ? frames.Length - 1 : 0;
	}

	/// <summary>
	/// 从停止的位置播放动画
	/// </summary>
	public void Play ()
	{
		this.enabled = true;
	}

	/// <summary>
	/// 暂停动画
	/// </summary>
	public void Pause ()
	{
		this.enabled = false;
	}

	/// <summary>
	/// 停止动画,将位置设为初始位置
	/// </summary>
	public void Stop ()
	{
		Pause ();
		Reset ();
	}
		
	//自动开启动画
	void Start ()
	{
		image = this.GetComponent<Image> ();
		spriteRenderer = this.GetComponent<SpriteRenderer> ();
		#if UNITY_EDITOR
		if (image == null && spriteRenderer == null) {
			Debug.LogWarning ("No available component found. 'Image' or 'SpriteRenderer' required.", this.gameObject);
		}
		#endif
	}

	void Update ()
	{
		//帧数据无效,禁用脚本
		if (frames == null || frames.Length == 0) {
			this.enabled = false;
		} else {
			//从曲线值计算当前帧率
			float curveValue = curve.Evaluate ((float)currentFrameIndex / frames.Length);
			float curvedFramerate = curveValue * framerate;
			//帧率有效
			if (curvedFramerate != 0) {
				//获取当前时间
				float time = ignoreTimeScale ? Time.unscaledTime : Time.time;
				//计算帧间隔时间
				float interval = Mathf.Abs (1.0f / curvedFramerate);
				//满足更新条件,执行更新操作
				if (time - timer > interval) {
					//执行更新操作
					DoUpdate ();
				}
			}
			#if UNITY_EDITOR
			else {
				Debug.LogWarning ("Framerate got '0' value, animation stopped.");
			}
			#endif
		}
	}

	//具体更新操作
	private void DoUpdate ()
	{
		//计算新的索引
		int nextIndex = currentFrameIndex + (int)Mathf.Sign (currentFramerate);
		//索引越界,表示已经到结束帧
		if (nextIndex < 0 || nextIndex >= frames.Length) {
			//广播事件
			if (FinishEvent != null) {
				FinishEvent ();
			}
			//非循环模式,禁用脚本
			if (loop == false) {
				currentFrameIndex = Mathf.Clamp (currentFrameIndex, 0, frames.Length - 1);
				this.enabled = false;
				return;
			}
		}
		//钳制索引
		currentFrameIndex = nextIndex % frames.Length;
		//更新图片
		if (image != null) {
			image.sprite = frames [currentFrameIndex];
		} else if (spriteRenderer != null) {
			spriteRenderer.sprite = frames [currentFrameIndex];
		}
		//设置计时器为当前时间
		timer = ignoreTimeScale ? Time.unscaledTime : Time.time;
	}
}
2017-06-27 09:34:51 athryin 阅读数 3658

这里的播放序列帧动画不仅仅是UGUI,我使用的是创建在3d的物体plane上面。

代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeTexture : MonoBehaviour {
    //texture贴图变量
    [SerializeField]
    private Texture ImageAmi;
    //计数器
    [SerializeField]
    private int _countImageNumber = 138;
    //当前时间
    private float _currentTime = 0f;
    //每帧间隔时间
    [SerializeField]
    private float IntervalTime = 3.0f;
    //贴图文件名
    private string _leftTextureName = "Image/A021212315";
    //贴图名字
    public string _myTextureName;
    //起始帧
    public int _myStartFrame = 0000;
    //帧间隔
    public int _myOffsetFrame = 1;
    //当前帧
    private int _currentFrame = 0;
    
	// Use this for initialization
	void Start () {
        _countImageNumber = 0;
        this.GetComponent<Renderer>().material.mainTexture = ImageAmi;
    }
	
	// Update is called once per frame
	 void Update () {
         
            if (_currentFrame < 136)
            {
                LeftLoadImage();
                _currentFrame++;
            }
            else
            {
                _countImageNumber = 0;
                _currentFrame = 0;
            }

    }
    //顺序加载图片
    void LeftLoadImage() {

        string _rightTextureName = string.Format("{0:D4}", _currentFrame);
        _myTextureName = _leftTextureName + _rightTextureName;
        Texture ImgAmi = (Texture)Resources.Load(_myTextureName);
        this.GetComponent<Renderer>().material.mainTexture = ImgAmi;
        
    }
}
使用的方法是将顺序的序列帧放在resources文件下的image中,然后通过字符串拼接,每次加载一张序列帧,通过顺序加载来达到播放动画的效果。因为我是在plane上使用的,所以是将获取到的贴图赋予到物体的材质贴图上的。至于具体的播放间隔时间,可以自己设置,我是直接使用的update的更新速率,但是在命名是也考虑了怎么调整播放间隔,不过因为update的速率满足了我的需求所以没有再自己写。

除了上面的简单方案,还可以通过加入倒序播放,然后再加上一个按钮按下播放,松开停止播放,来实现一个伪3d操控效果。

2017-02-26 01:20:00 weixin_30642869 阅读数 8

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

思路

序列帧动画的原理很好理解,首先必须要有一个载体,一般是一个图片,然后申请一个数组或List用来存放序列帧,然后再根据需要遍历这个数组替换载体的图片源,这样就实现动画效果了。

代码


public class Anim : MonoBehaviour {

    public float animSpeed = 10;  //动画播放速度 默认1秒播放10帧图片
    private float animTimeInterval = 0;  //帧与帧间隔的时间
   
    public SpriteRenderer animRenderer;//动画载体的渲染器
   
    public Sprite[] SpriteArray; //序列帧数组
    private int frameIndex = 0;  //帧索引
    private int animLength = 0;  //多少帧
    private float animTimer = 0; //动画时间计时器

   // Use this for initialization
    void Start () {
        animTimeInterval = 1 / animSpeed;//得到每一帧的时间间隔
        animLength = SpriteArray.Length; //得到帧数
       
    }

    // Update is called once per frame
    void Update()
    {
        animTimer += Time.deltaTime;
        if (animTimer > animTimeInterval)
        {
            animTimer -= animTimeInterval;//当计时器减去一个周期的时间
            frameIndex++;//当帧数自增(播放下一帧)
            frameIndex %= animLength;//判断是否到达最大帧数,到了就从新开始  这里是循环播放的
            animRenderer.sprite = SpriteArray[frameIndex]; //替换图片实现动画
        }      

    }
}

其他形式

基于上面的代码还可以添加一些其他动画的功能,比如暂停/停止(添加bool变量,Pause方法内判断是否暂停)快进慢进(方法内调节每秒播放的帧数)主要通过对这个类变量的控制来实现的,NGUI里有SpriteAnimation,UI SpriteAnimation等内置的序列帧动画脚本,里面的序列帧动画的功能比较全,有感兴趣的可以去看下NGUI的源码。
除了spriterenderer,通过texturerenderer和ui sprite也可以实现序列帧动画,效果差不多

一些思考

在最近项目中遇到的序列帧动画是全屏的,图片都很大,第一次加载时非常卡,这个问题后来通过两个途径解决的,在这里说一下

  • 在可以接受的情况下降低画质

    1.png
    如图,调节MaxSize属性能控制画质,缩小图片的大小
  • 分割序列帧数组

    因为序列帧在播放前需要先加载进数组里面,图片多了内存占用过大就很卡,因此可以优化资源加载算法实现分阶段加载视频,具体代码就不写了,这里我说一下思路:有500帧图片,不要一次加载完,100帧100帧的加载,第一个100帧播放到50帧的时候开始加载第二个100帧,以此类推,这样就分散了对系统资源的占用,相应的会流畅一些。

转载于:https://www.cnblogs.com/qiaogaojian/p/6443474.html

2015-02-22 15:13:04 book_longssl 阅读数 10822




今天主要总结的是 unity3d 中内置动画操作,以及代码事件编写动画实现

1.如何导入、执行外部动画 

在项目窗口中,首先,单击选择我们所准备的动画模型,在属性面板中选择Animations栏,
在属性中点击“+","-"可以增加和删除动画片段,
而在Start以及End中,可以分别设置每一个动画片段的开始帧数及结束帧数。
下面是我自己动画做的一个分解:
Idle:表示我动画中的准备动作。
Aim:表示我动画中的瞄准动作。
Fire:表示我动作中的投篮动作。



当上面动画片段设置好以后,我们用代码来实现,如何通过键盘上的数字按键”1“来控制这些片段完成一个动画流程

首先,如何设置一个按键:
在菜单栏中选择 Edit->roject Setting->Input
在Input属性面板中选择一项
Name设置成Play
Negative Button(按下键)设置成数字键”1“ ; 
Positive Button (松开键)设置成数字键”1“ ; 
如下图所示:

 

好了,按键我们在上面已经设置好了。
接下来到底如何用代码来实现通过键盘上的数字按键”1“来控制这些片段完成一个动画流程呢?
下面请看详细代码 :
  1. //是否可控
  2. bool CanControl=true;
  3. // Update is called once per frame
  4. void Update ()
  5. {
  6.    //当按下play  也就是我们上面设置的数字键”1“。
  7.   if (Input.GetButtonDown ("Play"))
  8.   {
  9.         //执行动画 叫"Aim"的动画片段 也就是我们上面设置的瞄准动画片段
  10. gameObject.animation.PlayQueued ("Aim");
  11.   }
  12.    //当按下1键 且可控
  13.    else if (Input.GetButtonUp ("Play")&&CanControl  )
  14.    {
  15.     //执行动画 fire 也就是我们上面设置的投篮动画片段
  16.     gameObject.animation.PlayQueued ("Fire");
  17.     //接着继续执行 Idle  也就是我们上面设置的准备动画片段
  18.     gameObject.animation.PlayQueued ("Idle");
  19.      CanControl =false ;
  20.    }
  21.   CanControl =true;
  22. }
复制代码

 
复制代码
通过上述简单的代码我们即可实现动画分解片段的串联
下面请看效果图:

1.按下键盘数字键"1"所执行瞄准的动作,"Aim"的动画片段



2.松开数字键”1“所执行的投篮动作,动画 fire



3. .松开数字键”1“所执行的准备动作,接着继续执行 Idle



2.使用unity3d内置的动画系统

首先,拖放素材到场景窗口中,设置好摄像机坐标,加入平行光



在游戏窗口右上角,单击  ,在弹出的菜单中依次选择 Add Tab->Animation



那么我们将发现游戏窗口上多了一个叫Animation(动画)的选项卡


接下来创建一个动画,在Animation(动画)选项卡中点击  后,在
弹出的窗体中保存我们的动画。



在Animation(动画)选项卡中,我们发现会有一小段菜单栏,我们从左到右先一一解释下
1:表示调到动画上一帧;
2:表示跳刀动画下一帧;
3:文本框输入 表示任意时间点
4:添加一个key
5:表示添加一个事件(需要代码编写)动作
 

可在对应选择项后面单击”-“号,则在弹出的菜单中 选择添加一条对应曲线或 key 



下面我们添加 Rotation.y (以Y轴旋转),值为360度。
表示我们的对象将以360度的旋转物体。



在曲线区域 左键按住不放 拖拽选择一块区域



按”F“键后,就会发现 此区域会局部放大,这样很方便我在曲线节点较多的情况下查看




上面简单介绍了下Unity3d的内置动画,下面 我们将介绍代码事件动画



如上图 我们首先定义了一个 摄像机的对象
然后 写了2个公共事件方法
CameraFarAway():这个方法我们实现了 摄像机视角拉远
CameraClose():这个方法我们实现了 摄像机视角拉近

然后通过上面的方法,在对应事件节点添加一个事件动画 即可实现 拉远拉近的动画
如下图:

视角拉近 叉车旋转,叉车前面的夹子下降的动画
 

视角拉远 叉车旋转,叉车前面的夹子上升的动画

 



unity3d代码实现动画功能

  1. //定义一个时间变量
  2. public float time=5.0f;
  3. // Use this for initialization
  4. void Start () {
  5.                 //定义一个动画曲线 起始位置 坐标为-3.023f,经过5.0秒后 坐标移动到2.96f
  6. AnimationCurve curve=AnimationCurve.Linear (0.0f,-3.023f,time,2.96f);
  7. //添加
  8. curve.AddKey (2*time,-3.023f );
  9. //创建一个动画片段
  10. AnimationClip clip=new AnimationClip ();
  11. //设置该片段中的曲线对象 以X轴移动
  12. clip.SetCurve ("",typeof (Transform ),"localPosition.x",curve );
  13. //添加该片段到动画
  14. animation.AddClip (clip,"Test" );
  15. //播放名叫“Test”的动画片段
  16. animation.Play ("Test");
  17. //循环播放该动画
  18. animation.wrapMode =WrapMode.Loop ;
  19. }
  20. // Update is called once per frame
  21. void Update () {
  22. }
复制代码


复制代码
由上可以看出 代码创建 跟昨天所总结内部设置动画差不多【狗刨学习网
首先 创建一个曲线 然后由曲线生成片段 最后由片段生成动画。
没有更多推荐了,返回首页