前言
今天关于场景中特效MovieClip和UI上的不同之处思考尝试了一些。场景中的MovieClip需要考虑多个方向,以及挂载点,且大多是通过配置来创建的,相比UI上公告板式样规则处理要复杂,所以把UI上的序列帧单独拆开,结合EXML编辑实现。
官方提供的MovieClip无法在EgretWing中所见即所得,于是…
第一种 通过MovieClipDataFactory创建
包 egret
类 public class MovieClip
继承 egret.MovieClip Inheritance egret.DisplayObjectInheritance egret.EventDispatcherInheritance egret.HashObject
影片剪辑,可以通过影片剪辑播放序列帧动画。MovieClip 类从以下类继承而来:DisplayObject 和 EventDispatcher。不同于 DisplayObject 对象,MovieClip 对象拥有一个时间轴。
官方提供示例如下
MovieClip序列帧动画-egret.MovieClip
帧动画演示http://developer.egret.com/cn/example/egret2d/index.html#100-anim-flash
优点
- 美术使用
TextureMerger
编辑。提供mc的json配置和图集。 - 支持单帧图片的偏移(虽然这个工具真的。。但这个功能还是有的)
- 支持添加事件
- 支持swf,gif作为源文件
缺点
- 无法在EgretWing中预览(这个很苦恼)
- TextureMerger使用太酸爽(谁用谁知道,我们的美术被折磨的不轻)
示例代码如下:
/**
* 以下示例演示了 MovieClip 序列帧动画的使用。
* 该示例中假设资源已经用RES模块加载完成
*/
class MovieClipExample extends egret.DisplayObjectContainer {
private data:any;
private texture:egret.Texture;
public constructor() {
super();
var loader:egret.HttpRequest = new egret.HttpRequest();
loader.responseType = egret.HttpResponseType.TEXT;
loader.addEventListener(egret.Event.COMPLETE, this.onLoadJsonComplete, this);
loader.open("resource/assets/chunli.json", egret.HttpMethod.GET);
loader.send();
}
private onLoadJsonComplete(event:egret.Event):void {
var loader:egret.HttpRequest = <egret.HttpRequest>event.target;
this.data = JSON.parse(loader.response);
var imageLoader:egret.ImageLoader = new egret.ImageLoader();
imageLoader.addEventListener(egret.Event.COMPLETE, this.onLoadTextureComplete, this);
imageLoader.load("resource/assets/chunli.png");
}
private onLoadTextureComplete(event:egret.Event):void {
var loader:egret.ImageLoader = <egret.ImageLoader>event.target;
//获取加载到的纹理对象
var bitmapData:egret.BitmapData = loader.data;
//创建纹理对象
this.texture = new egret.Texture();
this.texture.bitmapData = bitmapData;
this.createMovieClip();
}
private createMovieClip():void {
//创建动画工厂
var mcDataFactory:egret.MovieClipDataFactory = new egret.MovieClipDataFactory(this.data, this.texture);
//创建 MovieClip,将工厂生成的 MovieClipData 传入参数
var mc:egret.MovieClip = new egret.MovieClip(mcDataFactory.generateMovieClipData("test"));
this.addChild(mc);
//添加播放完成事件
mc.addEventListener(egret.Event.COMPLETE, function (){
egret.log("COMPLETE");
}, this);
//添加循环播放完成事件
mc.addEventListener(egret.Event.LOOP_COMPLETE, function (){
egret.log("LOOP_COMPLETE");
}, this);
//播放攻击动画
mc.gotoAndPlay("attack", -1);
}
}
在此基础上,可以对操作进行封装,实现MovieClipManager,略过不说了。
第二种
不导出MovieClip,使用TextureMerger导出sheet格式。在EXML里面放入一张图片,使用该图集的第一帧作为source。逻辑中实现一个FrameAnimation类。
代码中使用:
let frameAnimation = new FrameAnimation(this.image_xx, "mc_001");
传入占位Image组件和序列帧名,通过Update(dt)或者使用Timer计时计算应该切换到的图片名称。
优点
- EgretWing里面可以预览到动画位置
- EgretWing里面可以直接把适配设置好
- 逻辑调用简单
- 只有图集json,相比Mc格式的json资源小
缺点
- 不能加事件
- 看到EXML上的单个Image组件可能并不清楚这里是个特效占位符
- 需要对应的配置表来确定帧率,子图片下标等
第三种
实现一个通用组件UIComponent_MovieClip。
使用:
- 固定特效:
摆到EXML上,填好source,如Eui_001.1
,可以自动播放。 - 动态加载特效: 摆到EXML上,留空source,如``,程序动态设置如:
this.uicomponent_mc_task.initMc("Eui_001");
/**
* UI序列帧特效
*/
class UIComponent_MovieClip extends eui.Image implements eui.UIComponent{
protected childrenCreated(): void {
super.childrenCreated();
let effectName = getDefaultEffectName(this.source);
if(effectName != ""){
this.initEffect(effectName);
}
}
/**
* 初始化特效
* @paramp_effectId cfg_effect中id 如Eui_52
*/
public initEffect(p_effectId: string) {
let config = GetConfig(p_effectId);
if(config == null) {
return;
}
···
this.addEventListener(egret.Event.ENTER_FRAME, this.onEnterFrame, this);
}
private onEnterFrame() {
···
if(this.mIndex == -1|| this.mIndex > this.endIndex) {
this.mIndex = this.startIndex;
}
this.source = this.imgPath + "_json."+ this.mIndex
this.mIndex++;
}
}
优点
- EgretWing可以预览动画位置大小
- EgretWing可以直接把适配设置好
- 不需要动态加载的固定特效可以不添加代码
- 只有图集json,相比Mc格式的json资源小
- 程序看到其他设计人员提交的EXML上该组件就清楚这里是一个特效,如有设置source不处理,无则确认需求动态加载
缺点
- 需要对应的配置表来确定帧率,子图片下标等
其他
- 自定义事件也可以统一配置在配置表里面
后记
- 吐槽一下,工具真的是无力,TextureMerger不支持实时刷新,MovieClip编辑也是极其反人类。。Egret前路漫漫啊。。