Performance AS3:使用环绕(graph)将许多相同的形状向左移动--我的尝试太慢了
在Flash Pro(AS3)中开发一个简单的教育应用程序时,我陷入了尴尬的停顿 我试图制作一个简单的图表,在发生某些事情时显示垂直峰值(空闲时显示一条平线)。图形是实时的,因为它从程序开始,每隔一帧更新一次。这条线从“图形”对象的一端开始,一直延伸到另一端(例如,超过60秒)。到达末尾后,整个图形开始向左滚动,以便为添加到末尾的更多数据腾出空间。它被设计为永远保持滚动和记录数据(直到用户停止/暂停) 下面是一个例子: 实现这种图形的最佳方式是什么?一个由基线和刻度组成的简单滚动图形 不应该这么难。。。至少我是这么想的。我尝试了4种不同的方法(其中两种证明100%有效,但速度太慢)。外面一定有更好的东西!也许矩阵变换+位图填充Performance AS3:使用环绕(graph)将许多相同的形状向左移动--我的尝试太慢了,performance,actionscript-3,graph,air,scroll,Performance,Actionscript 3,Graph,Air,Scroll,在Flash Pro(AS3)中开发一个简单的教育应用程序时,我陷入了尴尬的停顿 我试图制作一个简单的图表,在发生某些事情时显示垂直峰值(空闲时显示一条平线)。图形是实时的,因为它从程序开始,每隔一帧更新一次。这条线从“图形”对象的一端开始,一直延伸到另一端(例如,超过60秒)。到达末尾后,整个图形开始向左滚动,以便为添加到末尾的更多数据腾出空间。它被设计为永远保持滚动和记录数据(直到用户停止/暂停) 下面是一个例子: 实现这种图形的最佳方式是什么?一个由基线和刻度组成的简单滚动图形 不应该这么
问题结束;简化代码如下
公共类图扩展了Sprite
{
包括“constants.as”;
常量像素因子:数字=(1/图形时间刻度)*1050;//60000ms
const amountToMove:Number=轮询速率*像素因子,inverseTS:Number=1.0/图形\时间刻度;
var graphHolder:graphHolder;//具有许多图形实例的简单(大型)精灵
变量基线:Shape=newshape(),拉伸:Boolean=false;
var apArray:Array=[],apRecycle:Vector.=new[];
var apLength:int=0,firstPeak:Shape;
//变量numberIndicator:TextField=newtextfield();
公共函数图(graphHolder:graphHolder)
{
//设置变量
this.graphHolder=graphHolder;
mouseEnabled=false;mouseChildren=false;
addChild(基线);
有(基线)
{
x=55;y=10;//基线。从55个像素开始,以便添加标签
graphics.lineStyle(2,0x000000);//厚度2,黑色
图形.lineTo(1050,0);
scaleX=0.0005;//基线以一个小点开始,随时间扩展
}
}
//不滚动时,绘制空闲基线。滚动时,向后拖动峰值。
函数drawIdle(timeappeased:int):void
{
if(时间经过图\时间刻度)?1050:(时间经过*像素因子))+54;//55-1
firstPeak.visible=true;
apArray[apArray.length]=第一峰值;
}
其他的
{
//从基线向上绘制7像素的线。
var peakShape:Shape=新形状();
//peakShape.cacheAsBitmap=true;
addChild(峰值形状);
带(峰值形状)
{
//cacheAsBitmap=true;
图形.线型(0x000000);
图形。移动到(1,10);
图形。lineTo(1,3);
x=((时间流逝>图形时间尺度)?1050:(时间流逝*像素因子))+54;//55-1
apArray[apArray.length]=峰值形状;
}
}
++长度;
}
/*将基线重置为小点,移除峰值,重置峰值阵列。
在下一个循环中,循环中的所有峰值仍需提取*/
函数resetGraph():void
{
baseLine.scaleX=0.0005;拉伸=false;
对于每个(var峰值:阵列中的形状)移除Child(峰值);
apArray.length=0;apLength=0;
}
}
因此,本质上,图表上应该有记号,指示实时发生的“动作”。图形到达屏幕末端后开始向左滚动(N秒)。换句话说,在到达指定空间的边缘后,它会无限期地滚动。以下是我尝试的三种实现方法——它们都不是很快,而且其中一些还存在其他问题
- 开始时速度很慢,但几分钟后速度就慢得令人难以置信,因为Flash显然仍在屏幕左侧处理整个图形
- 将直线段直接绘制到图形对象是不好的,因为每个线段显然都是一个对象,而且这些无数对象中的每一个在绘制后都没有显式(或隐式)引用。(“眼不见,心不烦”=缓慢且错误。)
- 这是一个坏消息,因为2048像素之后,无法再将更多数据绘制到位图李>
- 缩放应用程序会导致所有位图看起来粗糙、参差不齐,并引入间隙(尽管将每个位图标记为“平滑”),这可能是因为构成图形的线段数量过多,这些线段都是完全不同的,并且绘制在其他像素边界附近
- GPU无法加速Scrollrect(应用程序需要在移动设备上运行)
- 维护并发位图、将一个位图复制并粘贴到另一个位图上以刷新图形(“blitting”?)非常繁琐,但与矢量技术不同,它在亚像素级也非常不准确。此外,重新计算每帧或每帧的所有峰值所需的计算
public class Graph extends Sprite { include "constants.as"; const pixelFactor:Number = (1 / GRAPH_TIMESCALE) * 1050; //60,000ms const amountToMove:Number = POLLING_RATE * pixelFactor, inverseTS:Number = 1.0/GRAPH_TIMESCALE; var graphHolder:GraphHolder; // A simple (large) sprite with many Graph instances var baseLine:Shape = new Shape(), stretched:Boolean = false; var apArray:Array = [], apRecycle:Vector.<Shape> = new <Shape>[]; var apLength:int = 0, firstPeak:Shape; //var numberIndicator:TextField = new TextField(); public function Graph(graphHolder:GraphHolder) { //Set variables this.graphHolder = graphHolder; mouseEnabled = false; mouseChildren = false; addChild(baseLine); with (baseLine) { x = 55; y = 10; // the base-line. Starts 55 pixels out so labels can be added graphics.lineStyle(2,0x000000); // Thickness 2, color black graphics.lineTo(1050,0); scaleX = 0.0005; // base-line starts as a little dot, expands with time } } // When not scrolling, draws idle baseline. When scrolling, drags peaks backwards. function drawIdle(timeElapsed:int):void { if (timeElapsed <= GRAPH_TIMESCALE) baseLine.scaleX = inverseTS * timeElapsed; else { //if (graphNo < 1) graphHolder.scrollAxis(pixelFactor); if (!stretched) { baseLine.scaleX = 1.001; stretched = true; } // scroll all peaks if (apLength) { for (var i:int = 0; i < apLength; i++) { apArray[i].x -= amountToMove; } firstPeak = apArray[0]; if (firstPeak.x < 55) { firstPeak.visible = false; apRecycle[apRecycle.length] = firstPeak; // peaks are recycled instead of removed apArray.shift(); // apArray is a linked-list Array; less shift cost --apLength; } } } //lbd.copyPixels(graphHolder.baseCache,lbr,new Point(timeElapsed * pixelFactor,0), null, null, true); //line.graphics.lineTo(timeElapsed * pixelFactor,10); } function drawAP(timeElapsed:int):void { // Check for a peak in the recycle array if (apRecycle.length) { firstPeak = apRecycle.pop(); firstPeak.x = ( (timeElapsed > GRAPH_TIMESCALE) ? 1050 : (timeElapsed * pixelFactor) ) + 54; //55-1 firstPeak.visible = true; apArray[apArray.length] = firstPeak; } else { // Line drawn from baseline up 7 pixels. var peakShape:Shape = new Shape(); //peakShape.cacheAsBitmap = true; addChild(peakShape); with (peakShape) { //cacheAsBitmap = true; graphics.lineStyle(2, 0x000000); graphics.moveTo(1, 10); graphics.lineTo(1, 3); x = ( (timeElapsed > GRAPH_TIMESCALE) ? 1050 : (timeElapsed * pixelFactor) ) + 54; //55-1 apArray[apArray.length] = peakShape; } } ++apLength; } /* Reset baseline as tiny dot, remove peaks, reset peak array. All peaks in recycle remain to draw from during next cycle. */ function resetGraph():void { baseLine.scaleX = 0.0005; stretched = false; for each (var peak:Shape in apArray) removeChild(peak); apArray.length = 0; apLength = 0; } }
public class Graph extends Sprite private var container:Sprite; public function Graph():void { //create your baseline //create the container container = new Sprite(); addChild(container); this.addEventListener(Event.ENTER_FRAME, drawIdle); } private function drawIdle(e:Event){ //move your baseline? //scroll container container.x += scrollAmount; //iterate through all the ticks var i:int = container.numChildren; var tick:Shape; //iterate through the container children backwards (has to be backwards since your potentially removing items) while(i--){ tick = container.getChildAt(i); //check if the tick is off screen to the left if(container.x + tick.x < 0){ //if so, remove it so it can be garbage collected container.removeChild(tick); } } public function drawAp(timeElapsed):void { //create your tick var tick:Shape = new Shape(); //draw your tick tick.graphics.beginFill(0); tick.graphics.drawRect(0,0,tickWidth,tickHeight); tick.graphics.endFill(); //position your tick tick.x = whatever; tick.y = whatever; //add it to your tick container container.addChild(tick); } }