Вторник, 23.04.2024, 12:41
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Категории каталога
BlitzMax [14]
Blitz3D [9]
BlitzPlus [0]
Xna [1]
DarkBasic [0]
Общее [3]
Наш опрос
Hans Zimmer - что это для вас?
1. Где?
2. Композитор вроде
3. Простые символы
4. Любимый композитор
5. Я не определился
Всего ответов: 12
Форма входа
Поиск
Друзья сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Статьи
Главная » Статьи » BlitzMax

Подробно о попиксельных коллизиях (Автор: Oxid)
ResetCollisions очищает эти слои для следующего цикла отрисовки/проверки. Для отрисовки и определения коллизий в слоях используются CollideImage и CollideRect . Для простого определения коллизии двух картинок используются ImagesCollide и ImagesCollide2, которые используют слой 32 по умолчанию, на что следует обратить внимание при работе со слоями коллизий.

Теперь подробнее о функциях:

ImagesCollide( image1:TImage,x1,y1,frame1,image2:TImage,x2,y2,frame2 )
image1 – первая картинка;
x1,y1,frame1 – координаты и кадр первой картинки.
image2 – вторая картинка
x2,y2,frame2 – координаты и кадр второй картинки.
Возвращает: True если картинки пересекаются.
!: Для тестирования используются текущие величины поворота и размера, которые будут применяться одинаково и к первой и ко второй картинке. Поэтому при необходимости их надо определить перед использованием этой функции, используя SetScale и SetRotation.
Использование: Это одна из простейших функций определения попиксельной коллизии и подходит больше для не объектно-ориентированного подхода к программированию или когда у нас небольшое количество объектов.

ImagesCollide2( image1:TImage, x1, y1, frame1, rot1#, scalex1#, scaley1#, image2:TImage, x2, y2, frame2, rot2#, scalex2#, scaley2# )
image1 – первая картинка;
x1,y1,frame1 – координаты и кадр первой картинки.
rot1#, scalex1#, scaley1# – величины поворота, размера по x и y для первой картинки.
image2 – вторая картинка
x2,y2,frame2 – координаты и кадр второй картинки.
rot2#, scalex2#, scaley2# – величины поворота, размера по x и y для второй картинки.
Возвращает: True если картинки пересекаются.
Использование: Это вторая из простейших функций определения попиксельной коллизии. Продвинутый вариант первой функции. Здесь мы можем задать поворот и размер каждой картинке индивидуально. Подходит лучше для не объектно-ориентированного программирования или когда мы работаем с небольшим количеством объектов.

ResetCollisions ( mask%=0 )
mask – маска слоев для очистки, по умолчанию – все слои. Маска задаются в виде комбинации следующих величин: COLLISION_LAYER_ALL, COLLISION_LAYER_1 … COLLISION_LAYER_32.
Использование: служит для очистки слоев коллизий. Есть смысл использовать в начале цикла отрисовки/проверки коллизий.
!: Вот тонкий момент – со слоями. Cлои нельзя определять просто цифрами от 1 до 32, а определяются они масками (это относится и к остальным функциям, которые работают со слоями коллизий). Это нужно и что самое главное - полезно, если мы будем работать сразу с несколькими слоями. Это будет показано подробнее дальше.
!: при работе с ImagesCollide и ImagesCollide2 не надо использовать ResetCollisions - При вызове этих функций ResetCollisions вызывается автоматически. (спс Crunatus за дополнение).
Примеры:
ResetCollisions – очищает все слои
ResetCollisions ( COLLISION_LAYER_ALL ) – очищает все слои
ResetCollisions ( COLLISION_LAYER_1 ) – очищает слой 1
ResetCollisions ( COLLISION_LAYER_1 | COLLISION_LAYER_2 ) – очищает слой 1 и 2

CollideImage:Object[( image:TImage,x,y,frame,collidemask%,writemask%,id:Object=Null )
image – наша картинка
x,y,frame – ее координаты и кадр
collidemask – маска для слоев, где будем проверять коллизии
writemask – маска для слоев, куда будем рисовать картинку
Object – ссылка на наш объект(класс, тип – как кому нравится), который будет сохраняться в слое(ях) для отрисовки картинки
Возвращает: массив базовых объектов Objectс которыми наша картинка столкнулась. Если картинка ни с чем не сколлидилась, то массив объектов будет равен NULL.
Описание: функция тестирует на пересечение картинку со слоем(ями) collidemask и сохраняет в слое(ях) writemask картинку и ссылку на наш объект. Таким образом, в слое накапливается некоторое количество картинок, которые мы туда помещаем. Поэтому его и надо очищать перед новым циклом отрисовки с новыми координатами картинок.
Использование: благодаря возвращаемому значению и параметру Object хороша для использования при объектно-ориентированном программировании (ООП). Ах как хороша Пример использования: при отрисовке врагов, отрисовываем их и в слой коллизий. Потом при отрисовке пули (или игрока) тестируем коллизию со слоем, в который мы сохраняли врагов.
!: Для отрисовки в слои коллизий используются текущие установки поворота и размера, поэтому удобно использовать функцию в методе отрисовки объекта.
!: Слои для отрисовки и тестирования на коллизии можно задавать одновременно: CollideImage( Bullet_Image, x, y, frame, COLLISION_LAYER_1, COLLISION_LAYER_2, Bullet_Object ).
!: Можно использовать два метода определения коллизии с помощью этой функции:
просто есть ли коллизия:
Quote
If CollideImage(…) Then …

и не просто, а с объектами:
Quote
Local obj:Object = CollideImage(…)
If obj Then
For Local i%=0 To obj.length-1
...
Next
EndIf

!:
Преобразование типов для возвращаемого значения не работает. Т.е. возвращается всегда Object и при преобразовании TMyType ( CollideImage(…) ) будет возвращаться NULL. А было бы приятно, если бы при преобразовании производилась автоматическая выборка элементов нужного типа. Преобразование работает для конечного элемента: TMyType( obj]i[).myMethod(Paramaters).
!: При использовании 0 (COLLISION_LAYER_ALL ) в качестве параметра маски слоя происходит игнорирование операции. Т.е. если мы выставим collidemask = 0, то будет производиться только запись в слои по writemask.

Еще немного и перейдем к практике.

CollideRect:Object( x,y,w,h,collidemask%,writemask%,id:Object=Null )
Здесь останавливаться долго не будем - все идентично предыдущей функции, только вместо картинки для определения коллизии используется прямоугольник, который задается параметрами x, y, w, h – координаты, ширина и высота. И вообще по сабжу – я говорю о попиксельных коллизиях, а это коллизия попрямоугольная.

Вот и практика.

Простейшее определение коллизии двух объектов:
Quote
'сбрасываем угол поворота и размеры (если надо)
SetRotatin 0
SetScale 1, 1
'определяем коллизию
If ImagesCollide(BulletImage, BulletX, BulletY, BulletFrame, EnemyImage, EnemyX, EnemyY, EnemyFrame ) Then
... 'делаем доброе дело
EndIf

или так:
Quote
'определяем коллизию
If ImagesCollide2(BulletImage, BulletX, BulletY, BulletFrame, BulletAngle, BulletScaleX, BulletScaleY, EnemyImage, EnemyX, EnemyY, EnemyFrame, EnemyAngle, EnemyScaleX, EnemyScaleY) Then
... 'творим действо
EndIf

Вот посложнее:
Quote
'начало цикла
ResetCollisions 'очищаем слои коллизий
... 'что-нибудь делаем
For i=0 To Enemyes.Count-1 'цикл отрисовки врагов
SetScale EnemyScaleX, EnemyScaleY 'размер
SetRotation EnemyAngle 'угол поворота
'рисуем супостата в соответсвии с его местом и текущим кадровым положением
DrawImage( Enemy.Image, Enemy.X, Enemy.Y, Enemy.Frame )

'сохраяем картинку противника в коллизионном слое 1
'здесь есть такой момент, что маска слоя 1 равна цифре 1, поэтому приведенное
'ниже выражение правильно, но если мы хотим сохранить информацию о гаде в слое 4,
'то надо использовать COLLISION_LAYER_4 вместо 1
'при этом не тестируем остальные слои на коллизии
CollideImage( EnemyImage, EnemyX, EnemyY, EnemyFrame, 0, 1 )
Next
... 'что-нибудь делаем
'проверяем коллизию пули с врагами, которые в коллизионном слое №1
If CollideImage (BulletImage, BulletX, BulletY, BulletFrame, 1, 0)
... 'что-нибудь делаем??? А что тут можно вообще делать – примерчик так – для понимания только
EndIf

Этот пример дан просто для понимания того, что буфер коллизий можно заполнять. Потому как что делать с врагом при попадании в него пули не ясно, потому, что не ясно с каким врагом нам надо это делать. Ну пуля вроде одна (или даже если не одна и в цикле), она определяется однозначно – с ней можно что-то сделать. А как быть с врагами – как добраться до супостатов и учинить над ними месть неминучую? А вот если мы расширим немного пример, использовав всю мощь и красоту ООП и БМакса, то поймем, что месть действительно неминучая и враги будут настигнуты.
Хотя если в этом примере заменить врагов на стены, то пуля может о них разбиться. А если еще пулю на игрока – то тогда при столкновении со стеной игрок останавливается. Т.е. просто взяты неправильные игровые объекты для примера. Но хватит флейма, снова к делу:

Quote
'начало цикла
ResetCollisions 'очищаем слои коллизий
... 'что-нибудь делаем
For i=0 To Enemyes.Count-1 'цикл отрисовки врагов
SetScale EnemyScaleX, EnemyScaleY 'размер
SetRotation EnemyAngle 'угол поворота
'рисуем супостата в соответсвии с его местом и текущим кадровым положением
DrawImage( Enemy.Image, Enemy.X, Enemy.Y, Enemy.Frame )

'сохраяем картинку противника в коллизионном слое 1
'и !!! сохраняем на него ссылку
CollideImage( EnemyImage, EnemyX, EnemyY, EnemyFrame, 0, 1, Enemy )
Next
... 'что-нибудь делаем
'получаем массив врагов из слоя №1 с которыми столкнулась пуля
Local obj[ = CollideImage (BulletImage, BulletX, BulletY, BulletFrame, 1, 0)
'проверяем не пуст ли массив – а было ли столкновение
If obj
'проходим по полученному массиву
For Local i%=0 To obj.length-1
Local e: TEnemy = TEnemy(obj]i[) 'получаем врага, используя приведение типов
If e Then e.Kick(BulletPower) 'если это враг, а не кто-то другой, бьем его
Next
DestoyBullet() 'пуля сделала свое дело – она должна исчезнуть
EndIf


!: В слой коллизий можно записывать несколько типов объектов, а не только один, как в примере. Определить что это за объект можно приведением типов.
!: Как уже говорилось выше, можно одновременно и записывать в слой коллизий и проверять на коллизии. Это надо – если вы используете динамическое создание объектов без их сортировки, то вам не известно какой из объектов отрисуется первым, а какой последним – поэтому тестировать столкновения можно перекрестно во время их отрисовки.
Вот фрагмент кода:
Quote
Type TBullet Extends TSсeneObject

Method Draw()
SetBlend LIGHTBLEND
SetAlpha 1
DrawImage(img, x, y)
'COLLISIONS
Local o:Object = CollideImage(img,x,y, 0, enemy_collide_layer, bullet_collide_layer, self )
If o Then
destroy = true
For Local i%=0 To o.length-1
TEnemy(o]i[).destroy = true
Next
End If

End Method

End Type

Я не использую здесь проверку на валидность объекта из массива коллизий к классу TEnemy, т.к. отрисовываю в слое enemy_collide_layer только врагов, и, следовательно, там столкновение может быть только с TEnemy.

В классе TEnemy код идентичный, только меняется местами слои для записи и тестирования коллизий.

Quote
Local o:Object = CollideImage(img,x,y, i, bullet_collide_layer, enemy_collide_layer, self )



Источник: http://-

Категория: BlitzMax | Добавил: JohnK (26.03.2007) | Автор: Oxid
Просмотров: 2531
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright JohnK© 2024