【问题标题】:Flash AS3 (shape class) CPU usage and optimizationFlash AS3(形状类)CPU使用和优化
【发布时间】:2014-03-01 11:43:56
【问题描述】:

我是 Flash Actionscript 3.0 和一般对象编程的新手。我正在尝试创建一个简单的游戏,它基于转向绘制形状。

public class Player extends Shape
{
    public var X,Y,v,vX,vY,size,a,r:Number;
    public var k,counter,leftKey,rightKey,_color:uint;  
    public var line:Shape = new Shape();
    public var dot:Shape = new Shape(); 

  /*...*/
  /*constructor, giving values to variables here, not important*/       
  /*...*/

   public function Move():void
    {

        a=a+0.05*k; 
       //player controls k parameter k=0 by default 
       //k=1 when right key pressed
       //k=-1 when left key pressed

        vX=v*Math.cos(a);
        vY=v*Math.sin(a);

        X=X+vX;
        Y=Y+vY;

        dot.x=X+vX*size/(2*v);
        dot.y=Y+vY*size/(2*v);

        if (counter==0)
        {
            line.graphics.lineTo(X,Y);
            if (Math.random()<0.008) counter=12;
        } else 
        {
            line.graphics.moveTo(X, Y);
            counter--;
        }
    }

}

Function Move 在我的 Player 类中,从我的 Main 类中的无限 TimerEvent 函数调用

public function mainLoop(TimerEvent:Event):void
{           
    for (var i:uint=0; i<players; i++) player[i].Move();
}

一开始似乎运行良好,但一段时间后 CPU 使用率急剧上升,游戏变得无法玩。我相信这是由于我的形状(线)变得越来越复杂造成的。

有什么合理的优化方法吗?我能以不那么消耗的方式画一条线吗?我尝试将其转换为位图,但看起来很难看,并没有真正的帮助。

感谢和欢呼!

【问题讨论】:

  • 计数器是否保持当前的玩家人数?
  • @abhinav 不,变量计数器只负责在行中创建随机间隙 - 对我的问题无关紧要。我手动设置了玩家数量,但是即使只有一个玩家,CPU使用率也会随着时间的推移而增加。
  • 我猜部分问题是不断绘制(更不用说不清除)。我建议画一次线,然后简单地移动或旋转对象(使用 .x,.y,.rotation 属性或 .transform.matrix 如果您想要较低级别的控制)。如果您想绘制轨迹,请考虑在您的形状下方使用 BitmapData 对象draw(),将形状的转换矩阵作为第二个参数传递。

标签: actionscript-3 flash line shape


【解决方案1】:

您的假设是正确的,因为您的形状代码会降低速度 - 矢量数据在 Flash 中的每一帧都会重新绘制,因此它越复杂,绘制所需的时间就越长。一些解决方案,取决于您愿意做什么:

  • 您的保真度非常高——您每帧都调用Move 函数;您可能不需要那么高,因为自上一帧以来的运动差异可能小于一个像素。而是每隔 X 帧对您的位置进行采样(其中 X 是您愿意降低的保真度)。这可以通过输入框架中的简单计数器来完成
  • 如果您不需要保留绘图的整个历史记录,请将所有点放入一个数组/向量中,并根据需要剔除长度。然后每一帧,做一个line.graphics.clear() 并在数组中绘制点
  • 如果您确实需要保留整个历史记录,请在您的行下方保留BitmapData(例如舞台的大小)。每隔一段时间,将line 绘制到BitmapData 并在您的图形上调用clear() 以获得正确的矢量数据。您应该不会注意到任何质量损失(在绘图时将 smoothing 设置为 true

无论如何我都会做第一点,然后根据您的用例在第二点和第三点之间进行选择

【讨论】:

  • 我已经对其进行了测试,相信我,我只是在需要时才调用移动函数以使移动看起来更流畅。无论如何,您的第三点似乎运行良好,但是与矢量位图相比,其位图版本中的绘制线看起来要差得多,它的像素化程度非常高。我不确定为什么以及是否有可能以某种方式改善其外观。谢谢!
  • 绘制位图时smoothing是否设置为true?应该是myBMD.draw( line *(or stage)*, null, null, null, null, **true**); 如果还不行,那么试试drawWithQuality() 方法:help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/… - 通常,当您将draw() 转换为BitmapData 时,质量应该没有损失 - 我一直使用它是时候缓存矢量图形了
  • 还请注意,如果您的 Bitmap 被缩放或旋转,您将遭受伪像(类似于在 Photoshop 中缩放和旋转图像),所以 draw() 记住这一点
【解决方案2】:

扩展我的评论,尝试这样的事情:

public class Player extends Shape
{
    public var X,Y,v,vX,vY,size,a,r:Number;
    public var k,counter,leftKey,rightKey,_color:uint;  
    public var line:Shape = new Shape();
    public var dot:Shape = new Shape(); 

  /*...*/
  /*constructor, giving values to variables here, not important*/       
  /*...*/
    public function Player(){
        //draw shapes
        graphics.lineStyle(1);
        graphics.drawCircle(0,0,r);
        graphics.lineTo(size,0);//can't test this now, but make sure the line is in the same direction as rotation 0 (guessing it's to the right)
        //your other constructor code here
    }
   public function Move():void
    {

        a=a+0.05*k; 
       //player controls k parameter k=0 by default 
       //k=1 when right key pressed
       //k=-1 when left key pressed

        vX=v*Math.cos(a);
        vY=v*Math.sin(a);

        X=X+vX;
        Y=Y+vY;

        x=X+vX*size/(2*v);
        y=Y+vY*size/(2*v);
        rotation = a * 57.2957795;//quick'n'dirty radians to degrees
    }

如果你想画出轨迹,你可以试试这样:

var canvas:Bitmap = new BitmapData(state.stageWidth,stage.stageHeight,true,0xFF000000);
var ct:ColorTransform = new ColorTransform(1,1,1,.1);   
public function mainLoop(TimerEvent:Event):void
{           
    for (var i:uint=0; i<players; i++) {
        player[i].Move();
        canvas.draw(player[i],player[i].transform.concatenatedMatrix,ct);
    }
}

希望这是有道理的。

更新 这是一个独立的代码 sn-p 来说明上面的想法(其语法未经测试):

package {
    import flash.display.Bitmap;
    import flash.geom.ColorTransform;
    import flash.display.BitmapData;
    import flash.text.TextField;
    import flash.ui.Keyboard;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.utils.Dictionary;
    import flash.display.Sprite;
    public class PlayerMoveTest extends Sprite {
        private var keys:Dictionary = new Dictionary();
        private var players:Vector.<Player> = new Vector.<Player>();
        private var trails:BitmapData;
        private var fade:ColorTransform = new ColorTransform(1,1,1,.1);
        public function PlayerMoveTest() {
            addEventListener(Event.ADDED_TO_STAGE,init);
        }
        private function init(e:Event):void{
            trails = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00FFFFFF);
            addChild(new Bitmap(trails));
            for(var i:int = 0 ; i < 2; i++){
                var p:Player = addChild(new Player(10+i*10)) as Player;
                p.x = stage.stageWidth * .5;
                p.y = stage.stageHeight * .5;
                players.push(p);
            }
            stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP,onKeyUp);
            stage.addEventListener(Event.ENTER_FRAME,update);
        }
        private function onKeyDown(e:KeyboardEvent):void{
            keys[e.keyCode] = true;
        }
        private function onKeyUp(e:KeyboardEvent):void{
            keys[e.keyCode] = null;
        }
        private function update(e:Event):void{
            if(keys[Keyboard.LEFT] != undefined)  {players[0].a -= .05;players[1].a += .05;}
            if(keys[Keyboard.RIGHT] != undefined) {players[0].a += .05;players[1].a -= .05;}
            if(keys[Keyboard.UP] != undefined)    {players[0].s += .15;players[1].s -= .15;}
            if(keys[Keyboard.DOWN] != undefined)  {players[0].s -= .15;players[0].s += .15;}
            for(var i:int = 0 ; i < players.length; i++) {
                players[i].move();
                trails.draw(players[i],players[i].transform.concatenatedMatrix,fade);
            }
        }
    }

}
import flash.display.*;
class Player extends Shape{
    public var vx:Number,vy:Number,a:Number,size:Number,r:Number,s:Number;
    public function Player(size:Number){
        init(size);
    }
    private function init(size:Number):void{
       vx = vy = a = s = 0;
       this.size = size;
       this.r = size * .25;
       graphics.lineStyle(1);
       graphics.drawCircle(0,0,r);
       graphics.lineTo(size,0);     
    }
    public function move():void{
        rotation = a * 57.2957795;
        vx = Math.cos(a) * s;
        vy = Math.sin(a) * s;
        x += vx;
        y += vy;
        if(x < 0) x = 0;
        if(y < 0) y = 0;
        if(x > stage.stageWidth) x = stage.stageWidth-width;
        if(y > stage.stageHeight) y = stage.stageHeight-height;
    }
}

您可以测试此代码here,这是一个预览:

使用箭头键驱动(向上箭头加速,左/右转向)。 第一个玩家是较小的玩家,拥有正确的控制,另一个只是镜像以前的控制)

【讨论】:

  • 总体思路不错,但代码根本不工作,而且有些部分对我来说没有意义,所以我修改了它。谢谢你给我一个想法!
  • @Rames 看到我上面的更新,最初发布的代码没有经过测试,我认为这足以说明这个想法。我发布了另一个可以运行的 sn-p。随意投票/标记你认为合适的;)
猜你喜欢
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多