Коллизии в BlitzMax. Первая часть Автор: (c) Assari 2006 Перевел: (c) JohnK 2007
Содержание.
- Вступление
- Пересечение_Прямоугольников
- Пересечение_Прямоугольника и Круга
- Функции коллизий в_BlitzMax
- ImagesCollide
- ImagesCollide
с Анимацией
- ImagesCollide
с Масштабированием
- ImagesCollide
с Вращением
- Итоги
Вступление
Играть в игру, где разные
движущиеся объекты пролетают сквозь друг друга, не интересно. Даже в такой
простой игре как Пинг Понг есть механизм столкновения.
Простейший способ определения коллизии – это когда два объекта “накладываются”
друг на друга. Существует много способов проверки на столкновение, но лучше
начинать с простых.
Пересечение Прямоугольников
Самый
простой способ проверки коллизии – это пересечение прямоугольников.
Давайте рассмотрим пример:
|
Graphics 640,480
While Not (KeyHit(key_escape) Or
AppTerminate())
Cls
SetColor 0,255,0
DrawRect 150,200,100,100
SetColor 0,0,255
DrawRect MouseX(),MouseY(),100,100
Flip
Wend
End
|
|
Как
вы могли заметить из кода выше, при пересечении прямоугольников ничего не
происходит. Это из-за того, что в коде нет проверки коллизии.
Давайте добавим ее, используя команду RectsOverlap (Пересечение прямоугольников) И при столкновении
сменим цвет синего прямоугольника.
|
Graphics 640,480
While Not (KeyHit(key_escape) Or
AppTerminate())
Cls
SetColor 0,255,0
DrawRect 150,200,100,100
If RectsOverlap(150,200,100,100,MouseX(),MouseY(),100,100)
SetColor 255,0,0
Else
SetColor 0,0,255
EndIf
DrawRect MouseX(),MouseY(),100,100
Flip
Wend
End
Function RectsOverlap:Int(x0,
y0, w0, h0, x2, y2, w2, h2)
If x0 > (x2 + w2) Or (x0 + w0) < x2
Then Return False
If y0 > (y2 + h2) Or (y0 + h0) < y2
Then Return False
Return True
End Function
|
|
Как вы могли заметить,
синий прямоугольник становится красным каждый раз, когда происходит пересечение
(коллизия).
Пересечение Прямоугольника и Круга
Давайте
немного изменим код, дабы вместо прямоугольника появился овал:
|
Graphics 640,480
While Not (KeyHit(key_escape) Or AppTerminate())
Cls
SetColor 0,255,0
DrawRect 150,200,100,100
If RectsOverlap(150,200,100,100,MouseX(),MouseY(),100,100)
SetColor 255,0,0
Else
SetColor 0,0,255
EndIf
DrawOval MouseX()-50,MouseY()-50,100,100
Flip
Wend
End
Function RectsOverlap:Int(x0, y0, w0, h0, x2, y2, w2, h2)
If x0 > (x2 + w2) Or (x0 + w0) < x2 Then Return
False
If y0 > (y2 + h2) Or (y0 + h0) < y2 Then Return
False
Return True
End Function
|
|
Как вы заметили, функция больше не
работает должным образом. Нам нужна другая функция, которая поможет нам
определить коллизию между овалом и прямоугольником. Вот она:
|
Graphics 640,480
While Not (KeyHit(key_escape) Or AppTerminate())
Cls
SetColor 0,255,0
DrawRect 150,200,100,100
If CircRectsOverlap(150,200,100,100,MouseX(),MouseY(),50)
SetColor 255,0,0
Else
SetColor 0,0,255
EndIf
DrawOval MouseX()-50,MouseY()-50,100,100
Flip
Wend
End
Function CircRectsOverlap(x0, y0, w0, h0, cx, cy, r)
testX=cX
testY=cY
If TestX < x0
Then TestX=x0
If TestX >
(x0+w0) Then TestX=(x0+w0)
If TestY < y0
Then Testy=y0
If TestY >
(y0+h0) Then Testy=(y0+h0)
Return ((cX-TestX)*(cX-TestX)+(cY-TestY)*(cY-TestY))<r*r
End Function
|
|
Функции коллизий в BlitzMax
Если нам захочется
использовать отдельную функцию для каждой пары различных объектов, у нас будут
проблемы. Так же если это не функция RectsOverlap можно заметить, что математика в функциях на
проверку столкновений становиться сложнее.
К счастью, BlitzMax (а точнее Max2D) предоставляет пару функций, которые облегчат нам
жизнь. А теперь давайте посмотрим, как можно использовать встроенные в Max2D функции.
ImagesCollide
Самая
простая функция в BlitzMax это ImagesCollide. Она имеет следующий синтаксис:
|
Function
ImagesCollide(image1:TImage,x1,y1,frame1,image2:TImage,x2,y2,frame2)
|
|
Функции требуется два изображения, которые
надо проверить, а так же их положение на экране. Мы можем игнорировать параметр
Frame, указав вместо значения - ноль.
|
ImagesCollide(Alien,150,200,0,Player,MouseX(),MouseY(),0)
|
|
Итак, позиция НЛО =(150,200), а позиция
игрока равна позиции мыши.
Скомпилируйте код, что бы увидеть функцию
в действии:
|
Graphics 640,480
Local Player:TImage=LoadImage("blobship_1-1.png")
Local Alien:TImage=LoadImage("cartoonufo_1-1.png")
While Not (KeyHit(key_escape) Or
AppTerminate())
Cls
DrawImage Alien,150,200
DrawImage Player,MouseX(),MouseY()
If ImagesCollide(Alien,150,200,0,Player,MouseX(),MouseY(),0)
SetClsColor 255,0,0
Else
SetClsColor 0,0,0
EndIf
Flip
Wend
End
|
|
Как вы могли заметить, использовать
эту функцию очень просто.
ImagesCollide с
Анимацией
Давайте
разберемся с параметром Frame, который
мы пропустили ранее. Что бы коллизия работала с анимационным изображением нужно
немного изменить код:
|
Graphics 640,480
Local Player:TImage=LoadImage("blobship_1-1.png")
Local Alien:TImage=LoadAnimImage("exp1.png",64,64,0,16)
Local Frame:Int=0
Local AnimDelay:int=10
While Not (KeyHit(key_escape) Or AppTerminate())
Cls
DrawImage Alien,150,200, Frame
DrawImage Player,MouseX(),MouseY()
If ImagesCollide(Alien,150,200,Frame,Player,MouseX(),MouseY(),0)
SetClsColor 255,0,0
Else
SetClsColor 0,0,0
EndIf
Flip
If AnimDelay<0 Then
Frame :+ 1
If Frame>15 Then Frame=0
AnimDelay=10
EndIf
AnimDelay :- 1
Wend
End
|
|
Чтобы использовать ImagesCollide с
анимационными изображениями, нам нужен параметр, характеризующий кадр анимации,
что бы потом использовать в функции ImagesCollide. А увеличение параметров AnimDelay и Frame сделано для
того, что бы анимация проигрывалась
должным образом.
ImagesCollide с
Масштабированием
Blitzmax позволяет масштабировать
изображения в реальном времени. Это можно сделать с помощью функции SetScale, ее
синтаксис таков:
|
Function SetScale( scale_x#,scale_y# )
|
|
К сожалению, если используется функция SetScale, ImagesCollide не
работает должным образом. Что бы убедится в этом, скомпилируйте этот код:
|
Graphics 640,480
Local Player:TImage=LoadImage("blobship_1-1.png")
Local Alien:TImage=LoadAnimImage("exp1.png",64,64,0,16)
Local Frame:Int=0
Local AnimDelay:int=10
Local PlayerSize:Int=1
Local AlienSize:Int=2
While Not (KeyHit(key_escape) Or AppTerminate())
Cls
SetScale AlienSize,AlienSize
DrawImage Alien,150,100,Frame
SetScale PlayerSize,PlayerSize
DrawImage Player,MouseX(),MouseY()
If ImagesCollide(Alien,150,100,Frame,Player,MouseX(),MouseY(),0)
SetClsColor 255,0,0
Else
SetClsColor 0,0,0
EndIf
Flip
If AnimDelay<0 Then
Frame :+ 1
If Frame>15 Then Frame=0
AnimDelay=10
EndIf
AnimDelay :- 1
Wend
End
|
|
К счастью в BlitzMax есть еще одна
функция, которая позволяет работать с масштабированными изображениями, чудо
функция зовется ImagesCollide2,ее синтаксис таков:
|
Function
ImagesCollide2(image1:TImage,x1,y1,frame1,rot1#,scalex1#,scaley1#,image2:TImage,x2,y2,frame2,rot2#,scalex2#,scaley2#)
|
|
Прим. Переводчика: Запомните!
Функция не будет вращать или масштабировать изображение! Она лишь учитывает эти
факторы, для определения коллизии!
Итак, все, что нам нужно
чтобы использовать ImagesCollide2, это добавить:
|
If
ImagesCollide2(Alien,150,100,Frame,0,AlienSize,AlienSize,Player,MouseX(),MouseY(),0,0,PlayerSize,PlayerSize)
|
|
Теперь вы можете смело заменять ImagesCollide на ImagesCollide2, только не забудьте учитывать фактор вращения и масштабирования.
ImagesCollide с
Вращением
Этот пункт я оставил вам,
как упражнение, чтобы вы выяснили, что нужно ввести, чтобы функция заработала :)
Итоги
Сначала в этом туториале мы
разобрали два простых (и быстрых) способа проверки на коллизии. Жаль, что они
работают только с кругами и прямоугольниками.
А так как многие игры полностью состоят из изображений, мы рассмотрели и
разобрали функции ImagesCollide и ImagesCollide2.
В следующем туториале мы рассмотрим более сложную систему коллизий в BlitzMax.
|