Просмотр полной версии : Движение множества символов
forgottensmile
22.02.2011, 01:54
Здравствуйте!
Начал осваивать flash + actionscript 3.0 и столкнулся с проблемкой
Имею поле 800x700px, на котором постепенно появляются (выходят из-за границы поля) символы (для простоты, представляют собой небольшие прямоугольнички, рисуемые в actionscript)
создаю класс, в который засовываю массив этих символов, в этом же классе добавляю обработчик на ENTER_FRAME и реализую перемещение каждого из символов, в цикле пробегая по массиву
таким образом при количестве в 100 символов, все начинает безбожно тормозить (около 15фпс), а если усложнить и добавить анимацию в символы, то вообще беда
Как по правильному реализуется перемещение множества объектов на сцене? какие-то подводные камни? оптимизация?
Дайте совет
Спасибо
Сразу бы код выкладывали, раз вопрос про оптимизацию.
Division
22.02.2011, 09:35
cacheAsBitmap возможно поможет. А вообще рендер у флеша софтварный и медленный :)
forgottensmile
22.02.2011, 09:36
ничего сверхъестественного
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.display.MovieClip;
import com.greensock.*;
import com.greensock.easing.*;
import hype.extended.layout.ShapeLayout;
import hype.extended.behavior.VariableVibration;
import hype.framework.core.ObjectPool;
public class CreepCrowd extends Sprite
{
private var creeps:Array = [];
private var targetPointX:Number;
private var targetPointY:Number;
private var respawnZone:MovieClip;
private var respawnZoneLayout:ShapeLayout;
public function CreepCrowd(respawnZone:MovieClip, targetPointX:Number, targetPointY:Number, num:Number=100)
{
this.respawnZone = respawnZone;
this.targetPointX = targetPointX;
this.targetPointY = targetPointY;
respawnZoneLayout = new ShapeLayout(respawnZone);
createNamedCreeps(num);
addEventListener(Event.ENTER_FRAME, moveCreep);
}
public function moveCreep(e:Event):void
{
for each (var itemNamed:CreepNamed in creeps)
{
var item:Creep = itemNamed.getCreep();
var point:Point = item.globalToLocal(new Point(targetPointX, targetPointY));
if (point.y > 2) {
item.rotation += item.getRotationSpeed();
} else if (point.y < -2){
item.rotation -= item.getRotationSpeed();
}
itemNamed.x += Math.cos(item.rotation * (Math.PI / 180)) * item.getSpeed();
itemNamed.y += Math.sin(item.rotation * (Math.PI / 180)) * item.getSpeed();
}
}
private function createNamedCreeps(num:Number):void {
for (var i:int = 0; i < num; i++)
{
var creepNamed:CreepNamed = new CreepNamed();
var creep:Creep = creepNamed.getCreep();
creep.rotation = Math.random() * 360;
creep.setSpeed(Math.random() * 0.5 + 0.2);
creep.setRotationSpeed(Math.random() * 3 + 2);
respawnZoneLayout.applyLayout(creepNamed);
addChild(creepNamed);
creeps.push(creepNamed);
}
}
public function getCreepArray():Array {
return creeps;
}
public function killCreep(creep:CreepNamed):void {
removeChild(creep);
creeps.splice(creeps.indexOf(creep), 1);
}
}
CreepNamed представляет собой символ Creep с привязанным к нему текстовым полем
import flash.display.Sprite;
import flash.text.*;
import flash.ui.Keyboard;
public class CreepNamed extends Sprite {
private var creep:Creep;
private var txt:String;
public function CreepNamed(coord_x:int = 0, coord_y:int = 0) {
x = coord_x;
y = coord_y;
creep = new Creep();
creep.x = coord_x;
creep.y = coord_y;
txt = new String();
for (var i=0; i<5; i++) {
txt = txt.concat(String.fromCharCode(Math.random() * 10 + 80)).toLowerCase();
}
var txtField:TextField = new TextField();
txtField.text = txt;
txtField.textColor = 0xFFFFFF;
txtField.width = 50;
txtField.height = 20;
txtField.mouseEnabled = false;
txtField.type = TextFieldType.DYNAMIC;
txtField.x = creep.x - 20;
txtField.y = creep.y - 25;
addChild(creep);
addChild(txtField);
}
public function getCreep():Creep {
return creep;
}
public function getText():String {
return txt;
}
}
Ну и сам Creep
import flash.display.MovieClip;
import flash.text.*;
import flash.ui.Keyboard;
public class Creep extends MovieClip {
private var speed:Number;
private var rotationSpeed:uint;
public function Creep() {
graphics.beginFill(0x000000);
graphics.drawRect( -5, 0, 10, 2);
graphics.endFill();
}
public function setSpeed(speed:Number):void {
this.speed = speed;
}
public function getSpeed():Number {
return speed;
}
public function setRotationSpeed(rotationSpeed:uint):void {
this.rotationSpeed = rotationSpeed;
}
public function getRotationSpeed():uint {
return rotationSpeed;
}
}
forgottensmile
22.02.2011, 09:39
то есть суть в том, что создается некое подобие игрушки Crimsonland, наверное все знают) так вот оригинал конечно был нефлешовый, но там одновременно на экране собиралось 100-200 монстриков, причем все активно шевелилось, пересчитывалось и т.д.
пытаясь повторить то же самое во флеше получаю дикие тормоза элементарно при перемещении сотни прямоугольничков
ЗлОй ПрОграММер
22.02.2011, 10:13
может лучше сделать класс для каждого символа и в нём прописать движение, тормозить тогда возможно не будет
Один общий цикл enterFrame, где двигать все объекты сразу. Ну кэширование поставить.
может лучше сделать класс для каждого символа и в нём прописать движение
Не лучше.
forgottensmile
22.02.2011, 21:40
Один общий цикл enterFrame, где двигать все объекты сразу
Собственно в классе CreepCrowd так и сделано в функции moveCreep
На сцене создается один объект CreepCrowd и внутри него в enterFrame все это хозяйство крутится
А насчет кеширования можно по подробнее?)
хммм...взял тестовый пример с частицами, включив отображение области перерисовки, заметил, что перерисовывается вся область экрана, что не есть гуд
попробовал избавиться от класса с символами, ради эксперимента, поместив создание и перемещение всех символов прямо в кадре на таймлайне, и результат на лицо: экран стал перерисовываться не полностью, а фрагментами с наибольшим скоплением символов, в результате был получен ОЧЕНЬ большой прирост производительности
однако применяя данный подход к текущему случаю, прироста производительности ровным образом не наблюдается совсем....интересно почему
cacheAsBitmap помогает только при translate-преобразованиях (изменяются x, y). Остальные преобразования — rotation, scale и skew вынуждают FP заново рендерить из вектора.
mikhailk
23.02.2011, 21:57
Кстати, на мой взгляд, все, что не требует векторных преобразований в процессе визуализации, надо гнать в растр. Лучше самостоятельно. Векторное дерево с cashAsBitmap и оно же собранное и целиком записанное как битмап - две большие разницы.
Но к рассматриваемому случаю это не относится. :)
Вопрос к автору - если убрать текст (вообще), производительность повышается? Если повышается, можно попробовать заэмбедить шрифт в тексфилд. Если не повышается - подумать, как уменьшить количество вычислений. Тут, опять же, можно заменить сложные вычисления на простые (itemNamed.x += 2; ) и посмотреть, как все шевелится. Если 100 пустых квадратов без текста, передвигаемые за итерацию на 2 пикселя, не будут шевелиться - значит достигнут предел производительности ФП.
Добавлено через 22 минуты
на самом деле я вот тут запустил 1000 полосочек в упрощенном режиме, тормозов нет вообще:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
private var clips:Array = new Array();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
ClipForMoving.xBound = 700;
ClipForMoving.yBound = 500;
for (var i:int = 0; i < 1000; i++)
{
var startX:int = 50 + int(Math.random() * 600);
var startY:int = 50 + int(Math.random() * 400);
var dX:int = -10 + int(Math.random() * 20);
var dY:int = -10 + int(Math.random() * 20);
var rotationSpeed:int = 1 + int(Math.random() * 90);
var clipForMoving:ClipForMoving = new ClipForMoving(startX, startY, dX, dY, rotationSpeed);
addChild(clipForMoving);
clips.push(clipForMoving);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event) : void
{
var clipsCount:int = clips.length;
for (var i:int = 0; i < clipsCount; i++)
{
clips[i].move();
}
}
}
}
package
{
import flash.display.Sprite;
public class ClipForMoving extends Sprite
{
public static var xBound:int;
public static var yBound:int;
private var dX:int;
private var dY:int;
private var rotationSpeed:int;
public function ClipForMoving(x:int,y:int,dX:int,dY:int,rotationSpeed:int)
{
this.x = x;
this.y = y;
this.dX = dX;
this.dY = dY;
this.rotationSpeed = rotationSpeed;
graphics.beginFill(0xff0000);
graphics.drawRect( -5, 0, 10, 2);
graphics.endFill();
}
public function move() : void
{
this.x += dX;
if (this.x > xBound && dX > 0) dX = -dX;
if (this.x < 0 && dX < 0) dX = -dX;
this.y += dY;
if (this.y > yBound && dY > 0) dY = -dY;
if (this.y < 0 && dY < 0) dY = -dY;
this.rotation += rotationSpeed;
}
}
}
Добавлено через 28 минут
Вот пример, если лень компилировать:
http://mikhailk.ru/testing/clipMoving/
Добавлено через 1 час 24 минуты
Стало интересно, попробовал с текстом, производительность упала примерно в 6 раз.
http://mikhailk.ru/testing/clipMoving/withText.html
forgottensmile
26.02.2011, 02:07
Не подумал, что это важно, но сейчас понял, что ошибся))) на заднем плане программно рисуются гексы порядка 300 штук (контур и прозрачное заполнение). Видимо они перерисовываются постоянно (еще пока не совсем знаком с этой "кухней"), хотя казалось бы нарисовались один раз и всё....
Прикрутив к этому полю гексов cacheAsBitmap получил много радости))))
Шестиугольники, насколько я помню.
nOobCrafter
26.02.2011, 08:27
сам делаю сейчас подобную штуку забавы ради, итак:
1. Один ентерфрейм в котором ВСЕ крутится.
2. Мобов в контейнер, контейнер каждый раз после перемещения мобов отрисовываем в битмапу и ее выводим на экран (сам контейнер и мобы не находятся в дисплей листе), вообще все так можно сделать, прирост очень чувствуется даже на глаз, я запускал так 1500 мобов).
3. Оптимизировать расчеты, избегать использования пакета Math без крайней нужды, можно вместо констант исопльзовать литералы.
4. Убрать альфу, градиенты и т.д...
Если интересно могу выложить свою варианцию, но до конца она еще не доделана.
forgottensmile
26.02.2011, 11:15
думаю всем было бы интересно посмотреть на такой поход)
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.