2010年09月21日 | 12 comments getBounds不给力啊 刚发现Flash的DisplayObject/getBounds在只有矢量图形的补间中会计算不出正确的大小,总是得到补间所在的前一个关键帧中的形状区域。 证据:getBounds不给力的证据 延伸阅读2016-07-21 -- 编写的ANE出现Extension context为null的解决2013-02-25 -- 萝莉大冒险 项目完成上架2012-09-25 -- StarlingMVC2012-09-24 -- Links about Feathers2011-08-18 -- Flash编译Robotlegs的项目导致运行时报错2011-08-07 -- Mousebomb Ver.2009 Flash网站源文件2011-06-28 -- 王国战争对战演示2011-03-14 -- RobotLegs最佳实践PDF2010-12-07 -- 战略游戏未探索区域黑影挖空的杂记2010-11-02 -- 推荐一个富互联网游戏开发团队 as3flashgetBounds
鼠标炸弹 | 二月 18th, 2011 @kitsudo, 测试中已经得出了“总是得到补间所在的前一个关键帧中的形状区域”,你可以测试,不管拉多长的补间都一样。并不是渲染异步的问题(这里是运算而并非渲染,并不受舞台渲染的影响,代码是同步线性执行的)。
kitsudo | 二月 18th, 2011 package com.blessjoy.component { import com.pblabs.engine.PBE; import com.pblabs.engine.core.IAnimatedObject; import flash.display.Bitmap; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.geom.Point; /** * 将一个MovieClip转化为一个Bitmap提高效率(通用版本, 对MC本身无任何要求) * @author thinkpad */ public class CommonMovieClipAdvRenderer extends Sprite implements IAnimatedObject { private var mcInfo : MovieClipInfo; public var currentFrame : int = 0; private var fps : int; private var delta : int; private var last : Number; private var isPlaying : Boolean; private var loop : Boolean; private var autoPlay : Boolean; private var bitmap : Bitmap; public function clone() : CommonMovieClipAdvRenderer { var mcr : CommonMovieClipAdvRenderer = new CommonMovieClipAdvRenderer(null, fps, autoPlay, loop); mcr.mcInfo = mcInfo; return mcr; } public function CommonMovieClipAdvRenderer(mc : MovieClip,fps : int = 0,autoPlay : Boolean = true,loop : Boolean = true,start : int = 1,end : int = -1) { this.autoPlay = autoPlay; this.loop = loop; this.fps = fps; addEventListener(Event.REMOVED_FROM_STAGE, onRemove); addEventListener(Event.ADDED_TO_STAGE, onAdd); if(fps) { this.delta = 1000 / fps; } this.mcInfo = new MovieClipInfo(); bitmap = new Bitmap(); addChild(bitmap); if(mc) { mc.gotoAndStop(start); mcInfo.init(mc, start, end); } } private function onAdd(event : Event) : void { if(autoPlay) { play(); } PBE.processManager.addAnimatedObject(this); } private function onRemove(event : Event) : void { stop(); PBE.processManager.removeAnimatedObject(this); } public function play() : void { if(!isPlaying) { isPlaying = true; } } public function gotoAndPlay(frame : int) : void { gotoAndStop(frame); play(); } public function gotoAndStop(frame : int) : void { currentFrame = Math.min(mcInfo.totalFrames, frame); } /** * 初始化完毕 */ public function get inited() : Boolean { return mcInfo.inited; } public function stop() : void { if(isPlaying) { isPlaying = false; } } public function onFrame(deltaTime : Number) : void { if(!mcInfo.inited) { return; } if(!currentFrame) { currentFrame = 1; } else { if(!isPlaying) { return; } } if(delta && PBE.processManager.virtualTime – last mcInfo.totalFrames) { stop(); currentFrame = 1; } else { bitmap.bitmapData = mcInfo.frames[(currentFrame – 1) % mcInfo.totalFrames]; var position : Point = mcInfo.positions[(currentFrame – 1) % mcInfo.totalFrames]; bitmap.x = position.x; bitmap.y = position.y; currentFrame++; } } override public function set visible(value : Boolean) : void { super.visible = value; if(!value) { stop(); } else { play(); } } } } import com.pblabs.engine.PBE; import flash.display.BitmapData; import flash.display.MovieClip; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; internal class MovieClipInfo { public var frames : Array /*BitmapData*/ = []; public var positions : Array /*Point*/ = []; public var totalFrames : int; public var inited : Boolean; public function init(mc : MovieClip,start : int = 1,end : int = -1) : void { if(start > mc.totalFrames + 1 + end) { totalFrames = frames.length; inited = true; } else { PBE.pushStageQuality(“best”); var bound : Rectangle = mc.getBounds(mc); var width : int = Math.ceil(bound.width); var height : int = Math.ceil(bound.height); var oldScaleX : Number = mc.scaleX; var oldScaleY : Number = mc.scaleY; if(oldScaleX != 1 || oldScaleY != 1) { width = width * oldScaleX; height = height * oldScaleY; } var bd : BitmapData = new BitmapData(Math.ceil(mc.width) * Math.ceil(oldScaleX), mc.height * oldScaleY, true, 0x0); var mtx : Matrix = new Matrix(); mtx.a = oldScaleX; mtx.d = oldScaleY; mtx.tx = -Math.floor(bound.x * oldScaleX); mtx.ty = -Math.floor(bound.y * oldScaleY); bd.draw(mc, mtx); PBE.popStageQuality(); frames.push(bd); positions.push(new Point(bound.x, bound.y)); mc.gotoAndStop(start + 1); PBE.processManager.schedule(1000 / PBE.mainStage.frameRate, this, init, mc, start + 1, end); } } }
kitsudo | 二月 18th, 2011 @鼠标炸弹, 这个是我之前写的一个MC转Bitmap的工具 最早的时候我是希望可以在构造函数中就全部缓存 结果出现了全部是第一帧的情况(先gotoAndStop 然后draw的) 之后摸索了半天就成了现在这个版本了 测试过形状补间 通过getBounds获得的大小又那么一点点的误差(大概几个像素应该是取整导致的问题, scale大些比较明显) 这个代码的灵感来自于一个国内的人写的引擎CopyEngine (GoogleCode上有 这个功能的代码在copyengine.cache.MemoryPoolcache方法 copyengine.cache.CacheMovieClip 是他用到的工具类) 不过它的这个工具类在处理使用图形做动画的时候会有问题, 对mc有一定要求 例子有需要的话可以发给你 (下面的那个代码用到了PBE框架来替代了EnterFrame的部分, 而且有mc第一周期没有显示的问题, 这个可以弥补 CopyEngine的方案没有这个问题 )
kitsudo | 二月 18th, 2011 @鼠标炸弹, 形状补间所使用的MorphShape不能被正确捕捉 代码的局限性就体现在这里…. 测试的时候没有注意 用的图形是方变圆, 形状虽然变了 但是尺寸变化不大…… 汗了….
我也发现了,还以为是我的问题.有没有发现替代getBounds()的方法.
@glaycial, 目前没有替代方案可以解决它不给力的问题。
好像是由于渲染是异步跟不上问题
@kitsudo, 测试中已经得出了“总是得到补间所在的前一个关键帧中的形状区域”,你可以测试,不管拉多长的补间都一样。并不是渲染异步的问题(这里是运算而并非渲染,并不受舞台渲染的影响,代码是同步线性执行的)。
package com.blessjoy.component {
import com.pblabs.engine.PBE;
import com.pblabs.engine.core.IAnimatedObject;
import flash.display.Bitmap;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
/**
* 将一个MovieClip转化为一个Bitmap提高效率(通用版本, 对MC本身无任何要求)
* @author thinkpad
*/
public class CommonMovieClipAdvRenderer extends Sprite implements IAnimatedObject {
private var mcInfo : MovieClipInfo;
public var currentFrame : int = 0;
private var fps : int;
private var delta : int;
private var last : Number;
private var isPlaying : Boolean;
private var loop : Boolean;
private var autoPlay : Boolean;
private var bitmap : Bitmap;
public function clone() : CommonMovieClipAdvRenderer {
var mcr : CommonMovieClipAdvRenderer = new CommonMovieClipAdvRenderer(null, fps, autoPlay, loop);
mcr.mcInfo = mcInfo;
return mcr;
}
public function CommonMovieClipAdvRenderer(mc : MovieClip,fps : int = 0,autoPlay : Boolean = true,loop : Boolean = true,start : int = 1,end : int = -1) {
this.autoPlay = autoPlay;
this.loop = loop;
this.fps = fps;
addEventListener(Event.REMOVED_FROM_STAGE, onRemove);
addEventListener(Event.ADDED_TO_STAGE, onAdd);
if(fps) {
this.delta = 1000 / fps;
}
this.mcInfo = new MovieClipInfo();
bitmap = new Bitmap();
addChild(bitmap);
if(mc) {
mc.gotoAndStop(start);
mcInfo.init(mc, start, end);
}
}
private function onAdd(event : Event) : void {
if(autoPlay) {
play();
}
PBE.processManager.addAnimatedObject(this);
}
private function onRemove(event : Event) : void {
stop();
PBE.processManager.removeAnimatedObject(this);
}
public function play() : void {
if(!isPlaying) {
isPlaying = true;
}
}
public function gotoAndPlay(frame : int) : void {
gotoAndStop(frame);
play();
}
public function gotoAndStop(frame : int) : void {
currentFrame = Math.min(mcInfo.totalFrames, frame);
}
/**
* 初始化完毕
*/
public function get inited() : Boolean {
return mcInfo.inited;
}
public function stop() : void {
if(isPlaying) {
isPlaying = false;
}
}
public function onFrame(deltaTime : Number) : void {
if(!mcInfo.inited) {
return;
}
if(!currentFrame) {
currentFrame = 1;
} else {
if(!isPlaying) {
return;
}
}
if(delta && PBE.processManager.virtualTime – last mcInfo.totalFrames) {
stop();
currentFrame = 1;
} else {
bitmap.bitmapData = mcInfo.frames[(currentFrame – 1) % mcInfo.totalFrames];
var position : Point = mcInfo.positions[(currentFrame – 1) % mcInfo.totalFrames];
bitmap.x = position.x;
bitmap.y = position.y;
currentFrame++;
}
}
override public function set visible(value : Boolean) : void {
super.visible = value;
if(!value) {
stop();
} else {
play();
}
}
}
}
import com.pblabs.engine.PBE;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
internal class MovieClipInfo {
public var frames : Array /*BitmapData*/ = [];
public var positions : Array /*Point*/ = [];
public var totalFrames : int;
public var inited : Boolean;
public function init(mc : MovieClip,start : int = 1,end : int = -1) : void {
if(start > mc.totalFrames + 1 + end) {
totalFrames = frames.length;
inited = true;
} else {
PBE.pushStageQuality(“best”);
var bound : Rectangle = mc.getBounds(mc);
var width : int = Math.ceil(bound.width);
var height : int = Math.ceil(bound.height);
var oldScaleX : Number = mc.scaleX;
var oldScaleY : Number = mc.scaleY;
if(oldScaleX != 1 || oldScaleY != 1) {
width = width * oldScaleX;
height = height * oldScaleY;
}
var bd : BitmapData = new BitmapData(Math.ceil(mc.width) * Math.ceil(oldScaleX), mc.height * oldScaleY, true, 0x0);
var mtx : Matrix = new Matrix();
mtx.a = oldScaleX;
mtx.d = oldScaleY;
mtx.tx = -Math.floor(bound.x * oldScaleX);
mtx.ty = -Math.floor(bound.y * oldScaleY);
bd.draw(mc, mtx);
PBE.popStageQuality();
frames.push(bd);
positions.push(new Point(bound.x, bound.y));
mc.gotoAndStop(start + 1);
PBE.processManager.schedule(1000 / PBE.mainStage.frameRate, this, init, mc, start + 1, end);
}
}
}
@鼠标炸弹, 这个是我之前写的一个MC转Bitmap的工具
最早的时候我是希望可以在构造函数中就全部缓存
结果出现了全部是第一帧的情况(先gotoAndStop 然后draw的)
之后摸索了半天就成了现在这个版本了
测试过形状补间
通过getBounds获得的大小又那么一点点的误差(大概几个像素应该是取整导致的问题, scale大些比较明显)
这个代码的灵感来自于一个国内的人写的引擎CopyEngine (GoogleCode上有 这个功能的代码在copyengine.cache.MemoryPoolcache方法 copyengine.cache.CacheMovieClip 是他用到的工具类)
不过它的这个工具类在处理使用图形做动画的时候会有问题, 对mc有一定要求
例子有需要的话可以发给你
(下面的那个代码用到了PBE框架来替代了EnterFrame的部分, 而且有mc第一周期没有显示的问题, 这个可以弥补
CopyEngine的方案没有这个问题
)
@kitsudo,谢谢兄弟的分享,我现在完整方案已成型,也没必要换了。
@鼠标炸弹, 形状补间所使用的MorphShape不能被正确捕捉
代码的局限性就体现在这里….
测试的时候没有注意
用的图形是方变圆, 形状虽然变了
但是尺寸变化不大……
汗了….
呵呵,谢谢kitsudo ,收下了CommonMovieClipAdvRenderer 这几天一直在想这个问题呢,呵呵 ,在这里找到了答案,偶会勤来的..
@kitsudo, PBE? 是不是BPE?求详细介绍
PBE = PushButton engine