Eduard, проверка столкновения большого количества объектов вопрос довольно серьезный
и прежде всего тем, что как правило это нужно делать без тормозов.
для снижения тормозов нужно следовать нескольким правилам:
- выносить из циклов ненужные вычисления;
- заменять множественные вычисления объектов на ссылки;
- ограничивать циклы обхода только нужными объектами;
например, исходный код:
Код:
for (var i in this._parent) {
if (this._parent[i] != this) {
if (this.hitTest(this._parent[i])) {
trace("hit: "+this._parent[i])
}
}
}
оптимизированный:
Код:
//создаем объект-хранитель ссылок на мувиклипы, участвующие в проверке на столкновения:
_global.movies_obj = {}; // _global не лучшее место, но для примера сойдет.
// при создании мувиклипа добавляем ссылку на него в неком объекте:
_global.movies_obj[this._name] =this;
// далее, в методе проверки:
var m_obj= _global.movies_obj; //
// в методе проверки вначале удаляем себя из этого объекта:
delete movies_obj[this._name];
for (var i in m_obj) {
var mc = m_obj[i];
if (this.hitTest(mc)) {
trace("hit: "+mc)
}
}
m_obj[this._name] = this; // а при выходе возвращаем.
- таким образом мы убрали одну проверку
Код:
if (this._parent[i] != this) {
- плюс к тому, мы заменили 3 вычисления мувиклипа:
Код:
this._parent[i]
на одно:
Код:
var mc = movies_obj[i];
и в дальнейшем использовали готовую ссылку;
- мы ограничили цикл обхода только нужными объектами
обходя не this._parent, в котором по идее может оказаться что угодно
а специальный объект, содержащий ccылки только на нужные мувики.
если объектов очень много, то возможно будет полезным реализовать
разбиение на сектора и последующее уточнение.
что это значит?
например можно на фоне создать прозрачные мувиклипы-секторы.
затем обежать их и, если обнаружится пересечение, то добавить мувик в список
конкретного сектора.
и только затем делать проверку на пересечение используя конкретные объекты-сектора.
Код:
this.sectors_mc.broadcastMessage("onClearSectorsList"); // очищаем лист секторов
//
this.hit_movies.broadcastMessage("onMoveObjects"); // передвигаем мувики
this.hit_movies.broadcastMessage("onCheckHits"); // проверяем пересечения
// это в секторах
function onClearSectorsList() {
this.hits_container = {}
}
// это в движущихся мувиках:
function onMoveObjects () {
this._x+= this.xspeed;
this._y+= this.yspeed;
this.hit_list_of_sectors = {}
var sectors = this._parent._parent.sectors_mc;
for (var i in sectors) {
var sector_mc = sectors[i]
if (this.hitTest(sector_mc)) {
sector_mc.hits_container[this._name] = this;
this.hit_list_of_sectors[sector_mc._name] = sector_mc
}
}
}
function onCheckHits () {
for (var i in this.hit_list_of_sectors) {
var hits_object = this.hit_list_of_sectors
delete hits_object[this._name]
for (var k in hits_object) {
var mc = hits_object[k]
if (this.hitTest(mc)) {
// дальнейшая проверка
}
}
hits_object[this._name] = this;
}
}
еще одним эффективным способом может оказаться предварительная сортировка
массива мувиклипов по одной из координат, с последующей проверкой соседних
мувиклипов на пересечение.
вот этот код дал 4х кратное увеличение производительности:
(нужно создать и залинковать в либе мувик с именем Ball_mc, в нем нарисовать квадратик
этот код втыкаем просто в руте в первый и единственный кадр)
Код:
this.setBallClass = function() {
delete this.setBallClass;
var Ball = function () {
this.init();
};
AsBroadcaster.initialize(Ball);
Ball.onMessage = function() {
this.broadcastMessage.apply(this, arguments);
};
var compareFunction = function (a, b) {
return a._x>b._x ? 1 : a._x<b._x ? -1 : 0;
};
Ball.checkHits = function() {
this._listeners.sort(compareFunction);
var first_mc = this._listeners[0];
for (var i = 1, length = this._listeners.length; i<length; i++) {
var next_mc = this._listeners[i];
if (first_mc.hitTest(next_mc)) {
first_mc.highlight();
next_mc.highlight();
}
first_mc = next_mc;
}
};
//
Object.registerClass('Ball_mc', Ball);
Ball.prototype.__proto__ = MovieClip.prototype;
//
var tmp = Ball.prototype;
tmp.init = function() {
Ball.addListener(this);
this._xscale = this._yscale=50+_global.Math.random()*50;
this.radius = this._width/2;
this._x = this.radius+(Stage.width-this._width)*_global.Math.random();
this._y = this.radius+(Stage.height-this._height)*_global.Math.random();
this.x_speed = Math.ceil(_global.Math.random()*10-5) || 1;
this.y_speed = Math.ceil(_global.Math.random()*10-5) || 1;
this.cacheAsBitmap = true;
};
tmp.onMove = function() {
var clr = new Color(this);
clr.setRGB(0xCCCCCC);
this._x += this.x_speed;
this._y += this.y_speed;
if ((this._x+this.radius)>Stage.width || (this._x-this.radius)<0) {
this.x_speed = -this.x_speed;
}
if ((this._y+this.radius)>Stage.height || (this._y-this.radius)<0) {
this.y_speed = -this.y_speed;
}
/*
var p = this._parent;
for (var i in p) {
var mc = p[i];
if (mc != this) {
if (this.hitTest(mc)) {
this.highlight()
}
}
}
// */
};
tmp.highlight = function() {
var clr = new Color(this);
clr.setRGB(0xFF0000);
};
_global.Ball = Ball;
ASSetPropFlags(_global, 'Ball', 7, 1);
};
this.setBallClass();
// -----------------------------
this.createEmptyMovieClip("balls_mc", 0);
for (var i = 0; i<50; i++) {
this.balls_mc.attachMovie("Ball_mc", "ball"+i+"_mc", i);
}
// ----------------------
this.onEnterFrame = function() {
var t = getTimer();
Ball.onMessage("onMove");
Ball.checkHits();
trace(getTimer()-t);
};
чтобы сравнить производительность, нужно закомментировать строку Ball.checkHits();
и раскоментировать закомментированные строки.
ну, полагаю, пока достаточно.
будут вопросы - вэлкам.
вообще, тема определения пересечений достаточно широка и нужно смотреть в каждом
конкретном случае что можно применить для увеличения производительности.