forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ и уроки (http://forum.boolean.name/forumdisplay.php?f=110)
-   -   Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам. (http://forum.boolean.name/showthread.php?t=4387)

Данил 09.09.2007 11:24

Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Знаю, что новички часто проверяют все объекты на коллизии. А ведь так не надо делать. У меня в игре (Arrow – master2 … ) были тоже проверки на все объекты. И когда на карте было большое количество объектов (типо пуль, врагов, главного героя и бонусов), игра начинала зверски тормозить. Вот и пришёл к тому, что у меня в последних миссиях невозможно было играть.

Затем написал функцию, которая бы определяла, находится ли в радиусе определённом объект, или нет. То есть, если рядом с главным героем находится один враг, то только на него считается коллизия (враг захавать хочет героя). А все остальные не считаются. Следовательно, примерно уже 30 коллизий убиваем. Идём далее. Пули.. пуль может быть много на карте. Особенно, если у тебя пулемёт. :)

Считаем, для каждой пули едёт проверка коллизий на всех монстров. Неправильно, подставляем для каждой пули эту функцию и вуаля! если только рядом с пулей находится монстр, то считаем коллизии. Посчитайте, сколько коллизий убиваем лишних? 30 пуль – 30 монстров. 900 коллизий!!! Так и примерно увеличиваем производительность игры в несколько раз. Так же с бонусами (но тут уже меньше. Всего максимум две коллизии)

Следовательно, ставить надо ограничения функцию просчёта расстояний. Ну, конечно, не в проектах ,где 5-6 коллизий, а где их тьма. Хотя, даже ограничение и на 5 коллизий будет неплохо. Свести коллизии до двух– это класс!



[blitz]
Function IsCollide (x1#, x2# , y1# , y2# , Weight# , Height# )
If X1 > X2 -Weight And X1 < X2 +Weight And Y1 > Y1 - Height And Y1 < Y2 + Height Then Return 1 Else Return 0

End Function
[/blitz]



Так. А терь о функции. Если объект с координатам x1 и y1 находится в зоне шириной weight и высотой height b и координатами центра x2 и y2 (то бишь центр - враг.. иль чё-нить другое), то возвращаем 1. Если нет - 0

[blitz]
If IsCollide (5,5,7,7,25,25)=1 Then ....
[/blitz]

Так же можно и в блитз3д делать, для упрощения коллизий. Допустим ,если два объекта находятся близко друг к другу, то включается коллизия - иначе отключается (просто не видел, чтобы это где-нибудь было реализовано). Только в блитз3д есть функцию EntityDistance, а в блитзмаксе я не знаю (:@ ), по этому идёт проверка координат.

Ну, как вам статья ? :-) :-) :-)
Верю тупая, но у меня вначале было куча проблем с этим.
Кстати, в функции моей возможны ошибки, хотя не знаю. Cкажите если есть. (В игре у меня это не функцией реализовано, а так просто).

Хотя всю статью можно было бы сказать так : "делайте проверку на дистанцию , друзья!" и сё... но чёт растянул я...

З.Ы. Arrow - master 2 :teach: (ссыль в подписи :-) )
З.Ы.Ы. :@ :sarcastic_hand:

ABTOMAT 09.09.2007 11:28

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Молодец, аффтар! Доброе дело написал!
Это будет очень полезно новичкам.

johnk 09.09.2007 11:30

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Функцию лучше поправить на IsCollide, так по смыслу будет правильней.

jimon 09.09.2007 12:23

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Данил
лутче напиши дяде Диме статью по определению колизии между сферами используя KD дерево ...
очень поможеж :)

Данил 09.09.2007 12:38

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
статья гафно? омг... хотя она для новичков.... вроде.. хз, в общем...

tormoz 09.09.2007 14:40

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Почему у меня никогда коллизии не тормозят ?
Может вы стратегию коллизий неправильно определяете ?
правило 1
Избегайте коллизии сфера-полигон
правило 2
Если вы используете сфера-полигон, то оптимизируйте ее:
полигональная модель должна содержать вменяемое число полигонов, если не позволяет графика, используйте так называемую "коллижн-модель" специально сделаную низкополигональную сетку, совпадающую с вашим объектом, с установленной альфой в ноль, и назначайте коллизию на нее.
правило 3
всегда удаляйте ненужные больше вам объекты: как пули, осколки. и тд.
правило 4
не вызывайте многократно функцию EntityCollided, а делайте конструкции типа:
entity=EntityCollided(en,x)
If entity
....
Endif
правило 5
Экономте код, вызывайте функции ТОЛЬКО когда это необходимо.
Например, ваш враг уже умер, зачем проверять его на попадание пули ?
Используйте типы для сущностей, и флаги состояния, который распределяют ЧТО в данный момент делать с тем или иным элементом.

elmortem 10.09.2007 00:55

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Ы... (:
Игры нужно писать так, чтобы все коллизии были либо "сфера-сфера", либо "квадрат-квадрат" - и тогда всё будет шустрее некуда. (:
P.S. Извините, я несколько пьян. Но строго после ремнота. ^__^

dimanche13 11.09.2007 22:34

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Поздравляю, Данил! Ты изобрел еще один велосипед. Этой функции лет эдак... короче больше чем тебе.

Данил 11.09.2007 22:58

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
хехе.. не спорю... но почему-то в 80% примеров или исходников игр этого нет.. хехе

ABTOMAT 11.09.2007 23:28

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Цитата:

Сообщение от Данил
хехе.. не спорю... но почему-то в 80% примеров или исходников игр этого нет.. хехе

Солидарен!

ИМХО далеко не все об этом знают!
Мне в свое время тоже пришлось "изобрести" дельтатайминг просто потому что никто не смог объяснить его толком.

moka 12.09.2007 20:39

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
В моей наработке физики основанной на окружностях и линиях, это было релизовано, и производительность вырастала в 4-20 раз. Т.к. перебор 200 линий и 20 окружностей занимал 4400 (между линия-окружность и окружность-окружность) и просчёт коллизии это занимало по 500мс :) Поэтому я тоже сделал подобное, и это не были уже мс с 3 цифрами на такие просчёты. В прочем, тут зависит от скорости перемещения объекта тоже, и ещё от много чего.
На заметку: все современные физ двиги, такие как PhysX, Bullet, Havok, Newton и другие используют эту систему. Так что мы не изобретаем новое, мы только оптимизируем работу кода и алгоритмов, добиваясь большей производительности. :)

В общем Данил, ты больно писимистичничаешь, т.к. если ктото не отписался "Спасибо!", это не значит что он не прочёл твою статью, и что она не будет полезна ему ;) Так что Спасибо что написал, многим кто об этом не подрузумевал, будет полезно узнать об этом.

Данил 12.09.2007 20:56

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
НЕт, с чего ты взял. Просто по некоторым камментам почему-то кажется, что говорят типа "нах я написал это, это и так все знают".. сорри

elmortem 13.09.2007 13:42

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Данил
Да нет, всё правильно. В разделе ФАК - это очень полезная информация. Мне кажется "правильный новичёк" сказал бы тебе большое спасибо.

IGR 13.09.2007 14:09

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Цитата:

правильный новичёк
как это ??

я думаю каждый кому поможет это статья скажет спасибо !!

elmortem 13.09.2007 18:15

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
IGR
Это означает новичка, который умеет учится на чужих советах и вместо изобретения велосипеда сначала тщательно данные советы собирает, а лишь затем начинает осторожно применять.

moka 13.09.2007 18:20

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
elmortem, это неправильный новичёк, правильный, это тот кто отрубиться от интернета возмёт RTMF и будет учиться. Вот только таких нету почти, но таким респект и они становяться в итоге лучшими...

dimanche13 13.09.2007 18:34

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
MoKa, где ж ты видел таких новичков, которые сами будут "постигать тонкую науку мирового бытия", ведь проще задать вопрос на форуме, пусть чужие мозги парятся.Вижу как форум молодеет, приходят парни лет по 13-15 и задают глупые впросы, вот не знаю хорошо ли это?

moka 13.09.2007 18:40

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
dimanche13, вот от сюда можно заключить. Интернет - зло. Я сидел без инета и зубрил, и на то время считался новичком, и щас в б3д много не знаю, но главное тут опыт иметь, знать мало. И знакомые есть кто так постигал кодинг.

IGR 13.09.2007 18:44

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Цитата:

приходят парни лет по 13-15 и задают глупые впросы, вот не знаю хорошо ли это?
то что такие приходят - хорошо !! приятно что люди интересуются кодингом !!
но то что задают глупые вопросы - плохо !! ведь можно было действительно это прочитать и мозги други не парить !!

Данил 13.09.2007 18:45

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Но все таки без инета тоже как-то неинтерестно прогить.. согласитесь, сделали супер мега игру, а показать почти некому(... также если возник вопрос, а в книги нет овтета, что делать? Инет...

Правда, с появлением безлимитного инета я почти забросил кодить.. так, по чуть-чуть бывает кодю че-нить

IGR 13.09.2007 18:49

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Цитата:

согласитесь, сделали супер мега игру, а показать почти некому
ты когда зделаеш ее, то она сама засветится как звезда в ночном небе (кхм извеняюсь) !!
а форум тебе для того что бы спросить что то , что не получается у самого !!

moka 13.09.2007 18:55

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Данил, не думаю что сделаешь сам мега игру кодя годик, только единицы, редкость. И я не про книги говорил, а про справку, и голову на плечах, книги - учат, и это уже не тот эффект, хотя лучше чем когда человек учит.
В общем заканчиваем оффтоп! FAQ раздел как никак.

Данил 13.09.2007 19:08

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
"мега игру" это образное выражение.. Незнаю, МоКа, но меня лично книга научила первому моему языку - VisualBasic и при чем вполне норм.. основные понятия и как это делается я понял... по этому книги - это весчь. но не все... =)

LD 14.09.2007 10:28

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Сорри, но присоединюсь к всеобщему флуду :-) изобретать велосипеды полезно каждому новичку (и мне в том числе, я тоже задаю на форуме тупые вопросы) очень хорошо сказываетьс9 на логике и дает прирост +10 к умению построения алгоритма. По мне, так лучше изобрести кривой велосипед и потом его доравтывать, чем скопипастить мотоцикл. извините, если что не так сказал.

HolyDel 16.09.2007 06:48

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Данил, молодец.
дядя дима, две сферы соприкасаются если растояние между их центрами меньше чем сумма радиусов.

еще пара советов:
1. не сравнивайте строки (долго), ессено если в этом нет крайней необходимости.
2. не сравнивайте float на равентсово, может смутить.
3. если есть вложенные условия, проверяйте сначала самые маловероятные, если они не выполнются , то вложенные даже небудут проверяться.
4. не используйте "магические числа". т.е. если у вас есть 10 врагов, то заведите константу на их кол-во, чтобы потом незабыть что к чему.
5. скрвайте невидимые еммитеры (ето даже в варкрафте сделано)

jimon 16.09.2007 12:01

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
HolyDel
есть 2000 сфер
из них надо узнать коллизии для 10 сфер (с какой колизится)
как ето оптимизировать ?
20 тыс проходов тормозит однако :)

я тут усилино думаю о разбиении пространства
хотя бы просто сегментную сетку наложить
но все ручки не доходят

HolyDel 16.09.2007 17:04

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
простая сегментная разбивка (впрочем, ты наверное и сам знаеш).
разбиваеш ограниченное пространство на n^3 кубов.
создаеш n^3 списков (aka list из <list>)

игровой цикл:
отчищаеш все спсики
первым прогоном 2000 операций, заносиш сферу в список. к которому она принадлежит (по координатам), если к нескольким (большая сфера), то заносиш во все списки к которым она принадлежит.
далее, прогоняеш все сферы
2000 проходов.
далее проеверяеш на коллизии тока сферы из тогоде списка (или кщк соседних), если сфера большая.

аналогичная система юзается в вартич (тога 2д , n^2), она помогла офигенно поднять производительность при большом кол-ве юнитов (хотя немного ее снизила при малом кол-ве).
исходники либы утеряны, в связи с потерей винта, и на данный момент усильно пишутся заново. Могу потом скинуть, прада ето будет 2д сегментная сетка.

jimon 16.09.2007 18:58

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
HolyDel
у меня тоже 2д :) для jAqua...
в общем в типе мира есть список существ
думаю там и можно его разбивать

идинственая трабла что сейчас нету границы мира
потому трудно представляю как наложить явную сетку
хотя можно сетку генерировать динамически
если юнит математически по координатам
относится к квадрату сетки то просто создадим етот квадрат
ето будет економно со стороны памяти
я уже начал все сильно оптимайзить...
а то памяти жрет много :)
зделал даж динамическую выгрузку ресурсов ...
ибо нефиг мне >100 картинок в памяти держать

в общем осталось подождать пока ручки дойдут :)

HolyDel 16.09.2007 19:30

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
хорошая идея.
сетка допустим из 20 на 20 ячеек.
перввм проходом просто узнаеш максимальные и минимальные координаты по обои осям, и запихиваеш в эту область сетку.
один угол (минимальные координаты в котором) береш за смещение.
пример:
сетка находится тут: (-20,-20)(180,180)
смещение dx = -20
смещение dy = -20
размер сетки sx 180 - (-20) =200 ; asx=1/sx;
размер сетки sy 180 - (-20) =200 ; asy=1/sy;
потом смотриш на сферу, допустим у нее координаты 50, 120
смотриш i = sphere.x-dx * asx * gridsize (размер сетки ето (в нашем случае 20))
смотриш j = sphere.y-dy * asy * gridsize (размер сетки ето)

кстати, как создать массив
typedef std::list<TSphere*> mylist
mylist* m = new mylist[20*20 (угадайте почему?)]

как обратиться к элементу?
m[i*21+j]

вот и получаем:

m[i*21+j].push_back(sphere);

на коллизии (предположим сферы в списке sphs)
for(sphstype (тут должно быть чо то сове)::const_iterator ci=sphs.begin();ci!=sphs.end();++ci)
{
i = sphere.x-dx * asx * gridsize;
j = sphere.y-dy * asy * gridsize;
for (mylist::const_iterator mi=m[i*21+j].begin();mi!=end();++mi)
{
а проврим ка мы их на коллизии тут!
}
}

PS. Данный пост направлен не дяде Диме в первую очередь, он и сам допрет.
а вот новичкам очень рекомендую принять на вооружение, способ сильно поднимет производительность, при огромном количстве объектов.

Да! писалось все в браузере, так что на работспособность не рассчитывайте, идея вроде верная.

И спасибо джимону, за идею с динамически меняющейся сеткой. а то так ее ячейки получаются слишком большими, и в них много юнитов помещаются, такчто пользы почти в ноль.

jimon 16.09.2007 19:54

Re: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
HolyDel
из-за взаимонепонимания мы друг другу новые идеи даем :lol: :lol: :)

я имеел ввиду что размер стороны квадрата сетки будет статичным = A
и потом опишем
type NetCube
..
field objects:TList
..
end type

и Net:TList
но будем создавать квадрат только если обьект туда попадает
тоесть пустых квадратов в сетке у нас не будет

хотя идея с динамическим размером мне понравилась :)

GoodWin 19.06.2008 14:09

Ответ: Увеличиваем производительность игры или как убить лишние коллизии. Советы новичкам.
 
Вложений: 1
Цитата:

Можно банально брать каждый астероид и по списку проверять, не столкнулся ли он с другими. Этот подход возможен только при малом количестве проверяемых объектов. Если объектов много (как планируется в нашем случае), то подобная проверка загрузить процессор на полную и все будет тормозить. Более правильный подход проверять на столкновение не со всеми существующими объектами, а только с теми, что находятся «рядом». Как выяснить кто «рядом»? Один из простых вариантов «Виртуальная сетка», нужно разлинеить игровое поле и для каждого сектора (клеточки) создать список объектов, которые сейчас в нем находятся. Для проверки столкновения мы будем перебирать только те объекты, которые находятся в том же секторе, что и проверяемый объект.
Пример:
[IMG]file:///D:/Downloads/AsteroidStormHtml/images/test4.jpg[/IMG]
Астероид под номером 1 находится в клетке A1, и проверки с кем он столкнулся, не будет вообще, т.к. больше в этом секторе никого нет. Для астероида 2, будет проверка всех, кто пересекает сектор B1, это астероиды 3 и 4.
Таким образом, количество проверок на столкновение уменьшается в сотни раз (особенно для большого поля, как у нас, и при большом количестве объектов). При создании объекта, определяем, какому сектору он принадлежит, и регистрируем его там, а при передвижении переписываем. Размер сектора выбрать можно любой, и у слишком маленького и у слишком большого есть свои преимущества и недостатки. Для простоты расчетов, я решил взять такой, чтобы самый крупный объект не пересекал более 4-х секторов. У нас самая крупная земля, ширина 197, она неподвижна, если ее разместить в вершине одного сектора, то чтобы перекрыть 4 сектора, один сектор будет в 100 точек.
Для определения, какие сектора пересекает объект нужно представить его в виде квадрата, и проверить в каком секторе находится каждый из его углов. Добавляем в базовый класс basic_object хеш
public var sectors:Object; // какие сектора пересекает объект
Лучше делать Object а не массив, чтобы не пробегаться по нему проверяя не добавили ли мы один и тот же сектор дважды.
И пишем функцию пересчета секторов
// Пересчитывает, какие сектора пересекает объект
public function CalcSectors():void {
var dx:Number, dy:Number;
var x1:Number, y1:Number;
var s:String;
sectors = new Object(); // сбрасываем список секторов
for (dx=-1; dx<=1; dx+=2){
for (dy=-1; dy<=1; dy+=2){
// вычисляем координату угла (центр+радиус)
x1 = x + radius*dx;
y1 = y + radius*dy;
// название сектора будет в виде "x_y"
s = Math.floor(x1/100)+"_"+Math.floor(y1/100);
sectors[s]=true; // запоминаем этот сектор
}
}
}
Маленькое отступление. Мне стало интересно, почему при добавлении числа к строке “строка”+Number, его не нужно преобразовывать в строку toString() ? Написал маленькую проверку:
var s:String="1";
var num:Number=4;
s+=num;
num+=s;
trace("s="+s+", num="+num); // s=14, num=414
Ни каких ошибок компилятор не выдал. Это что же получается, все как раньше? Переменная num по пути из Number стала String и в результате получили “414” вместо ожидаемых “18” или хотя бы ошибки компиляции?! Нафига тогда вообще типы переменных нужны? Что-то я не понял.
Вернемся к астероидам. В главном классе sky нужно создать хеш всех секторов, в которых побывали наши объекты, и прописать в них ссылки на сами объекты.
// Объявляем переменную для хранения секторов
var all_sectors:Object; // сектора со ссылками на объекты в них
. . .
// в конструкторе инициализируем
all_sectors = new Object();
. . .
// В функции вброса новых астероидов
// Просим пересчитать в какие сектора попал объект
new_asteroid.CalcSectors();
// добавим в эти сектора ссылку на объект
for each (s in new_asteroid.sectors){
if (!all_sectors[s]){ // такого сектора еще не было, создадим
all_sectors[s] = new Object();
}
all_sectors[s][new_asteroid.name] = new_asteroid;
}
А в функции Update, где мы перемещаем все объекты, нужно вставлять пересчет секторов и проверку на столкновения.
public function Update(e : Event):void {
var s:String, obj2:basic_object;
// Проходим по всему массиву созданных объектов
// и заставляем каждого сдвинуться в своем направлении
for each (var obj:basic_object in all_moving){
// перед тем, как сдвинуться удалим запись об этом объекте из секторов
for (s in obj.sectors){
delete all_sectors[s][obj.name];
}
// смещаемся
obj.move();
// Просим пересчитать в какие сектора попал объект
obj.CalcSectors();
// Проверяем столкновения со всеми объектами, которые есть в новых секторах
for (s in obj.sectors){
if (all_sectors[s]){ // такой сектор есть
for each (obj2 in all_sectors[s]) { // проверяем на столкновение
if (obj.CheckCollision(obj2)){ // столкнулись
// делаем отскок
resolve(obj, obj2);
}
}
} else { // нет такого сектора
all_sectors[s] = new Object(); // теперь будет
}
// регистрируемся в этом секторе
all_sectors[s][obj.name]=obj;
}
}
}

Статья ессно не моя... но мож ккому пригодится и написана для АкшионСкрипт 3 для флеша... но принцип можно взять....

Ниже в аттаче полный урок


Часовой пояс GMT +4, время: 01:47.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot