PDA

Просмотр полной версии : Оптимизация эффекта "хвоста кометы"


PainKiller
29.12.2013, 19:04
В общем ситуация такая, есть мобильный проект на Box2D, в нем есть шар - снаряд, который управляется физикой. Решил применить к нему вот этот эффект (http://www.freeactionscript.com/), естественно пример приведенный там, перевел на ООП, получился такой класс:

/**
* http://www.FreeActionScript.com
**/
package effects
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
import game.*;

public class BlittTrailer extends Sprite
{
// canvas bitmap data var
private var canvasBitmapData:BitmapData;

// canvas bitmap - this will be added to the display list
private var canvas:Bitmap;

// canvas rectangle - used to save canvas size
private var canvasRect:Rectangle;

// circle (trailer) bitmap data
private var circleBitmapData:BitmapData;

// circle rectangle - used to save canvas size
private var circleRect:Rectangle;

// color transformer - used to make cavas transparent
private var colorTransform:ColorTransform;

private var _parent:DisplayObjectContainer;
private var _ball:BallActor;

public function BlittTrailer(parent:DisplayObjectContainer, ball:BallActor)
{
_parent = parent;
_ball = ball;
init();
}

public function init():void
{

// create main canvas bitmap data
canvasBitmapData = new BitmapData(Main.screenX, Main.screenY, true, 0x333333);
canvas = new Bitmap(canvasBitmapData);
_parent.addChild(canvas);
canvasRect = canvasBitmapData.rect;
// create circle trailer bitmap data
circleBitmapData = new BitmapData(10, 10, true, 0xFFFFFF);
// draw CircleTrailer movieclip, linked from library, inside circle bitmap data
circleBitmapData.draw(new CircleTrailer());
// save circle rectangle size
circleRect = canvasBitmapData.rect;
// create ColorTransformer to modify alpha of bitmap
colorTransform = new ColorTransform();
// (make it 99% transparent)
colorTransform.alphaMultiplier = .99;
}

public function removeTrailer():void
{
_parent.removeChild(canvas);
}

public function render():void
{
// lock bitmap data to prevent display from updating while we modify it
canvasBitmapData.lock();
// change alpha
canvasBitmapData.colorTransform(canvasRect, colorTransform);
// draw circle
canvasBitmapData.copyPixels(circleBitmapData, circleRect, new Point(_ball.ball.x - 5, _ball.ball.y - 5), null, null, true);
// apply blur filter
canvasBitmapData.applyFilter(canvasBitmapData, canvasBitmapData.rect, new Point(0, 0), new BlurFilter(8, 8)); //3, 3
// unlock bitmap data
canvasBitmapData.unlock();
if (!_ball.ball.stage)
_parent.removeChild(canvas);
}

}
}

где _parent - контейнер где идет вся игра, _ball - шар к которому применяется спецэффект. Визуально все работает как надо, но повторяю проект мобильный и фпс при появлении на сцене такого снаряда падает в 2 раза. Как оптимизировать не знаю, буду рад любым идеям.

Добавлено через 41 секунду
И да - аппаратное ускорение пока не используется.

Добавлено через 14 минут
Сейчас попробовал включить

<renderMode>gpu</renderMode>

абсолютно ничем не помогло, только некоторые фильтры слетели(((

samana
29.12.2013, 19:26
А битмпаДата сильно большая?
Первое, что врезалось в глаза, это постоянное создание фильтра blur. Лучше создайте его отдельно, а потом применяйте. И некоторые точки тоже можно создать и использовать по кругу.

PainKiller
29.12.2013, 20:45
битмапДата 480 х 800, за подсказку с фильтром спасибо, не углядел, но ситуацию это не сильно изменило, фпс все равно около 10 - 15

Добавлено через 58 секунд
попробую уменьшить размер битмапдаты, может это выправит ситуацию

Akopalipsis
29.12.2013, 20:54
Воспользуюсь моментом и задам вопрос, который меня волнует с того момента, как я впервые увидел вот эти эффекты от Starling (http://onebyonedesign.com/flash/particleeditor/) - их в обычных проектах использовать можно?

in4core
29.12.2013, 23:04
PainKiller сам писал такой эффект недавно, просто поиграться. Производительность на уровне, даже на очень слабых машинах, выдает макс фпс.
Вот как я делал его, просто костяк. Если будет нужно, буду на работе выкину фул вершн, с эффекторами и т.п. :

package com.in4core.utils
{
import com.greensock.TweenMax;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.events.MouseEvent;
/**
* ...
* @author in4core progression lab
*/
public final class FlexObject
{
static private var _flexBitmapData:BitmapData;
static private var _stage:Stage;

public function FlexObject()
{

}


public static function setInParams(stage:Stage , lifeTime:int = 50):void
{
_stage = stage;
}

public static function startFlex():void
{
_stage.addEventListener(MouseEvent.MOUSE_MOVE , onMove);
}

static private function onMove(e:MouseEvent):void
{
var bmp:Bitmap = getMouseFlexBitmap();
_stage.addChild(bmp);
bmp.x = e.localX - bmp.width / 2;
bmp.y = e.localY - bmp.height / 2;

var randX:Number = Math.random() * 160 - 80;
var randY:Number = Math.random() * 160 - 80;

TweenMax.to(bmp, 1 , { alpha:0 , x:bmp.x + randX , y:bmp.y + randY , scaleX:3 , scaleY:3, blurFilter: { blurX:4 , blurY:4 } , onComplete:removeTarget , onCompleteParams:[bmp] } );
}

static private function removeTarget(target:Bitmap):void
{
_stage.removeChild(target);
}

public static function createFlex(obj:DisplayObject):void
{
_flexBitmapData = new BitmapData(obj.width, obj.height, true, 0);
_flexBitmapData.draw(obj);
}

private static function getMouseFlexBitmap():Bitmap
{
return new Bitmap(_flexBitmapData);
}
}

}

PainKiller
30.12.2013, 10:25
Спасибо, попробую этот вариант + на работе пройдусь по проекту скаутом, о результатах отпишусь.

Добавлено через 2 часа 45 минут
К сожалению у меня нет возможности подрубиться к скауту с мобильного через вайфай, поэтому смотрел с настольного ПК, запуская приложение в айр дебаг лончере. Итог таков - ф-ция render выполняется за 60 мс, львиную нагрузку в ней выполняют
canvasBitmapData.colorTransform(canvasRect, colorTransform);
canvasBitmapData.applyFilter(canvasBitmapData, canvasBitmapData.rect, new Point(0, 0), new BlurFilter(8, 8));
колортрансформ вынес в ф-цию init, скорость функции render возросла до 8 мс, но при запуске на мобиле никакой разницы я не ощутил. Придется попробовать версию in4core, хотя че то я на нее смотрю и у меня сомнения берут, что она будет более производительной, твинить блер-фильтры это ресурсоемко.

in4core
30.12.2013, 13:20
Не знаю, глубокие тесты не проводил, но как показывает практика твинМакс довольно быстрый, ну и да естественно нужно сделать контейнер для битмапок и туда пихать, а не на стейдж как в примере я показал.

samana
30.12.2013, 15:40
колортрансформ вынес в ф-цию init, скорость функции render возросла до 8 мс
Но тогда эффект исчезновения уже не будет срабатывать.

PainKiller
30.12.2013, 17:30
Но тогда эффект исчезновения уже не будет срабатывать.
Нет, все работает, можете проверить сами, пока временно решил проблему заменив на другой эффект, возможно так и оставлю т.к. работы до фига.

samana
30.12.2013, 17:36
Именно после своих сомнений, я проверил и - не работает)
А как же оно может срабатывать, если строчка
canvasBitmapData.colorTransform(canvasRect, colorTransform);
выполниться только один раз в методе init? Ведь надо постоянно применять colorTransform к canvasBitmapData.
Ну ладно, чудеса да и только.

PainKiller
31.12.2013, 10:35
Странно, но у меня работает, а почему должно не работать? ни один параметр в этой строчке не меняется. Прикрепил архив с примером с сайта, в котором перенес эту строчку в init, можете посмотреть сами.

samana
31.12.2013, 16:36
Ага, я понял вас. Это просто размытие дает такой эффект. Постоянно размывается и прозрачные пиксели так сказать - побеждают. Если размытие убрать, то исчезать конечно уже ничего не будет. Конечно тогда можно оставить и так, если просто размытие дает такой эффект.