Сделал мини-игру в составе большого проекта где нужно тапать по появляющимся объектам из-за облаков и тем самым уничтожать их. Самое эффектное - это полет облаков, реально выглядят классно. Облака объединяются в QuadBatch который меняется каждый фрейм.
Во-первых, появляются объекты как-то неестественно. Во-вторых, на слабых устройствах (например iPhone 4) подтормаживает и FPS падает до 10. А что оптимизировать не очень ясно хоть и не более 200 строк кода.
В общем буду рад любым советам по улучшению.
Код AS3:
package games
{
import flash.geom.Point;
import flash.geom.Rectangle;
import animation.InitObject;
import animation.Model;
import controls.NewMenuButton;
import feathers.controls.ImageLoader;
import feathers.core.PopUpManager;
import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Image;
import starling.display.Quad;
import starling.display.QuadBatch;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.text.TextField;
public class CloudGame extends Sprite
{
protected var cloudImg:Image;
protected var dObject:DisplayObject;
private var quadBatch:QuadBatch;
private var cloudArr:Vector.<CloudItem>;
private var cloudCount:int = 50;
private var screenWidth:Number = 960;
private var screenHeight:Number = 640;
private var focalStart:Number=700;
private var focal:Number=0;
private var stageRect:Rectangle;
private var vpX:Number;
private var vpY:Number;
private var centerPoint:Point;
private var tf:TextField;
private var count:int = 0;
private var cancelBut:NewMenuButton;
private static var imageArr:Vector.<DisplayObject>;
private var circleCount:int = 0;
public function CloudGame()
{
super();
addEventListener(Event.ADDED_TO_STAGE,initGame);
}
static public function init(list:Vector.<DisplayObject>):void
{
imageArr = new Vector.<DisplayObject>();
for (var i:int = 0; i < list.length; i++)
{
var obj:DisplayObject = list[i] as DisplayObject;
obj.pivotX = obj.width/2;
obj.pivotY = obj.height/2;
imageArr.push(obj);
}
}
private function initGame(...args):void
{
removeEventListener(Event.ADDED_TO_STAGE,initGame);
vpX=stage.stageWidth/2;
vpY=stage.stageHeight/2;
screenWidth = stage.stageWidth;
screenHeight = stage.stageHeight;
stageRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
centerPoint = new Point(screenWidth * 0.5,screenHeight * 0.7);
var bg:Quad = new Quad(screenWidth, screenHeight, 0x0008a7);
addChild(bg);
cloudImg = new Image(Main.assets.getTexture('cloud'));
cloudImg.pivotX = cloudImg.width * 0.5;
cloudImg.pivotY = cloudImg.height * 0.5;
quadBatch = new QuadBatch();
addChild(quadBatch);
focal = focalStart;
dObject = getRandomElementOf(imageArr) as DisplayObject;
cloudArr = new Vector.<CloudItem>();
for (var i:int = 0; i < cloudCount; i++)
{
var item:CloudItem = new CloudItem();
item.rotation = Math.random()*Math.PI;
setAShape(item);
if (i == 20 || i == 70){
item.type = 'image';
} else {
item.type = 'cloud';
}
cloudArr.push(item);
}
tf = new TextField (200, 100, '', 'Arial', 33, 0xffffff, true);
tf.x = 100;
tf.y = 20;
addChild(tf);
tf.text = String(count);
tf.touchable = false;
cancelBut = new NewMenuButton('btn_cancel');
cancelBut.addEventListener(starling.events.Event.TRIGGERED, closeDialog);
addChild(cancelBut);
cancelBut.x = cancelBut.y = Main.GAP * 0.5;
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
addEventListener(TouchEvent.TOUCH,onTouchHandler);
}
private function closeDialog(e:starling.events.Event):void
{
for (var i:int = 0; i < Model.initList.length; i++)
{
var initObj:InitObject = Model.initList[i];
var targ:DisplayObject = initObj.target;
Starling.juggler.tween(targ, 1, {
x: initObj.x,
y: initObj.y,
scaleX: initObj.scaleX,
scaleY: initObj.scaleY,
alpha: initObj.alpha,
rotation: initObj.rotation
});
}
dispatchEvent(new Event(Event.CLOSE));
PopUpManager.removePopUp(this, true);
}
private function getRandomElementOf(array:Vector.<DisplayObject>):Object {
var idx:int=Math.floor(Math.random() * array.length);
return array[idx];
}
private function setAShape(shape:CloudItem):void
{
shape.scale = 0.001;
shape.startX = screenWidth * 2 * Math.random()-screenWidth;
shape.startY = screenHeight * 0.5 +screenHeight * 0.5 * Math.random() - 100;
shape.x = shape.startX;
shape.y = shape.startY;
shape.zpos = Math.random() * 800 + 400;
}
private function sortArray():void
{
cloudArr.sort(zSortFunction);
}
private function zSortFunction(a:CloudItem,b:CloudItem):Number
{
if(a.zpos > b.zpos)
return -1;
else if(a.zpos < b.zpos)
return 1;
else
return 0;
}
private function shapeAvisible(shape:CloudItem):Boolean
{
var shapeRect:Rectangle = shape.getBounds(this);
return shapeRect.intersects(stageRect);
}
private function enterFrameHandler(event:Event=null):void
{
quadBatch.reset();
var xpos:Number;
var ypos:Number;
var item:CloudItem;
for (var i:int = 0; i < cloudCount; i++)
{
item = cloudArr[i];
//reset properties
item.zpos-=4;
var x1:Number = screenWidth-item.startX*2;
var y1:Number = screenHeight/2-item.startY;
if (item.zpos>-focal && shapeAvisible(item))
{
xpos=centerPoint.x-vpX-x1;
ypos=centerPoint.y-vpY-y1;
item.scale=focal/(focal+item.zpos);
if (item.type == 'image')
{
item.x=vpX+xpos*item.scale;
item.y=vpY + 50;
} else {
item.x=vpX+xpos*item.scale;
item.y=vpY+ypos*item.scale;
}
}
else
{
setAShape(item);
}
}
sortArray();
for (i = 0; i < cloudCount; i++)
{
if (cloudArr[i].type == 'cloud'){
item = cloudArr[i];
cloudImg.x = item.x;
cloudImg.y = item.y;
cloudImg.scaleX = cloudImg.scaleY = item.scale * 3;
cloudImg.rotation = item.rotation;
quadBatch.addImage(cloudImg);
} else {
item = cloudArr[i];
dObject.x = item.x;
dObject.y = vpY + 90;
dObject.scaleX = dObject.scaleY = item.scale;
addChild(dObject);
}
}
circleCount ++;
if (circleCount >= 300)
{
circleCount = 0;
dObject.visible = false;
dObject = getRandomElementOf(imageArr) as DisplayObject;
Starling.juggler.delayCall(function ():void {dObject.visible = true}, 1);
}
}
private function onTouchHandler(event:TouchEvent):void
{
var touch:Touch = event.getTouch(this);
if(touch == null)
return;
if(touch.phase == TouchPhase.BEGAN)
{
if (touch.target is Quad || touch.target is ImageLoader){
trace (touch.target);
count ++;
focal = focalStart - count * 6;
circleCount = 0
tf.text = String(count);
dObject.visible = false;
dObject = getRandomElementOf(imageArr) as DisplayObject;
Starling.juggler.delayCall(function ():void {dObject.visible = true}, 1);
}
}
}
}
}
import flash.geom.Rectangle;
import starling.display.DisplayObject;
class CloudItem
{
private var itemWidth:Number = 256;
private var itemHeight:Number = 256;
public var startX:Number;
public var startY:Number;
public var zpos:Number=0;
public var x:Number = 0;
public var y:Number = 0;
public var scale:Number = 1;
public var rotation:Number = 0;
public var type:String;
public function getBounds(targetSpace:DisplayObject):Rectangle
{
var w:Number = itemWidth*scale;
var h:Number = itemHeight*scale;
var rect:Rectangle = new Rectangle(x-w/2,y-h/2,w/2,h/2);
return rect;
}
}