Продолжим:
сегодня мы научим нашу змею есть и покажем что в этом мире бывают еще препятствия за которые кусать не желательно...
на мнужно както представить весь игровой мир... в простых случаях (как наш) его представляют массивом (в сложном случае базой данных)... представим его трехмерным массивом map в котором: первое измерение - координаты по X, второе измерение - координаты по Y и третье измерение - типы объектов (0 - код объекта, 1 хендл объекта)... третье измерение нужно нам для хранения кода препятствия... у нас ведь будут различные типы препятствий (стена и еда), ну и чтобы в любой случай можно было чтонить с объектом (препятствием) сделать и не искать его или не заводить кучу дополнительный переменных тоже нужно поле массива.
НЕ советую юзать проверку на столкновения объектов... поскольку на проверку этого уйдет наааамного больше компьютерного времени, по сравнению с проверкой на наличие элемента в массиве по нужным координатам...
значит так: создание мира:
мир создан (богом быть всетаки легко), идем далее...
добавим несколько препятствий
For i=2 To 10
t%=CreateCube()
PositionEntity t%,i*10,1,i*10
ScaleEntity t%,5,2,5
Map(i,i,0)=1
Map(i,i,1)=t%
Next
для препядствий будет код "1", его и надо записать в нулевое индекс третьего измерения массива, в первый индекс запишем сам хендл, в случае если нам прийдется убрать препятствие или анимацию запускать надо будет, да мало-ли чего...
Покажем нашей змее что в этом мире не только она одна бывает
If map(Int(SnakeGetX(a)/10),Int(SnakeGetZ(a)/10),0)=1 Or map(Int(SnakeGetX(a)+9)/10,Int(SnakeGetZ(a)+9)/10,0)=1 Then
WaitKey()
End
EndIf
Думаю тут объяснять много не надо... просто берем координату головы змеи и проверяем есть ли по "кратным" координатам в массиве стена (код 1)
в коде условие двойное...
объясняется это отсутствием функции округления... на самом деле функция int() не округляет а отбрасывает все что после запятой и получается что если у нас змея находится по Х координате примерно на 4.5, то физически будет отображено так, что половина головы будет уже в следующей клетке а результат вычисления будет показывать что она еще полностью в предидущей... вот для избежания таких случаев делается такого рода коррекция... заключается она в дополнительной проверке других координат (какбы координат объекта расположенного немножко в другом месте)...
Покажем змее, что мир не безграничный, а что это всеголишь карта из 14 на 14 клеток
If SnakeGetX(a)<-3 Or SnakeGetX(a)>143 Or SnakeGetZ(a)<-3 Or SnakeGetZ(a)>143 Then
WaitKey()
End()
EndIf
Здесь вообще все просто... проверяем "выход" координат змеи за границы карты если да, то выходим...
Теперь змея уже чтото видит... займемся едой
Заведем переменную FoodT% которая будет определять есть ли еда на поле, создавать второй кусок еды или нет, и будет служить задержкой... т.е. чтоб еда не появлялась сразу как ее только съели (так не интересно играть), а чтоб появлялась немного позже...
теперь идем в главный цикл и пишем код создания куска еды:
; ----- Create a Food --------------------------------------------
If FoodT%>0 Then FoodT%=FoodT%-1
If FoodT%=0
FoodX%=Int(Rand(0,14))
FoodZ%=Int(Rand(0,14))
While map(FoodX%,FoodZ%,0)=1
FoodX%=Int(Rand(0,14))
FoodZ%=Int(Rand(0,14))
Wend
map(FoodX%,FoodZ%,1)=CreateSphere()
ScaleMesh map(FoodX%,FoodZ%,1),3,3,3
EntityColor map(FoodX%,FoodZ%,1),255,50,50
PositionEntity map(FoodX%,FoodZ%,1),FoodX%*10,2,FoodZ%*10
map(FoodX%,FoodZ%,0)=2
FoodT%=-1
EndIf
; ----------------------------------------------------------------
Смотрим... если FoodT% больше нуля, значит еда съедена и запущен таймер по истечении времени которого надо создать еду... уменьшаем таймер на единицу...
если FoodT равно нулю, то: или истекло время, или только зашли в игру... приступаем к созданию куска еды... делаем случайные координаты и запускаем цикл генерации новых координат пока по этим координатам не будет ничего в массиве map, чтобы кусок еды нечайно не создался в стене... как его потом оттудова выгрызать?... цикл будет крутиться пока не будут найдены координаты пустой ячейки массива... значит на выходе у нас будут координаты в которых можно создавать еду...
создаем объект еды CreateSphere(), красим его в красный цвет, скалим, позиционируем где надо, и записываем в массив map код еды "2" и сам хендл объекта тоже сохраняем, это для того, чтобы при съедании еды объект можно было удалить...
и не забываем FoodT% поставить в такое состояние, чтобы эта процедура не вызвалась второй раз... и чтоб не отмерялось время... если мы здесь присвоим чтонить положительное то автоматически запустим таймер и еда будет создаваться не зависимо от того съели ли предыдущую...
приступаем к поеданию еды:
If map(Int(SnakeGetX(a)/10),Int(SnakeGetZ(a)/10),0)=2 Or map(Int(SnakeGetX(a)+9)/10,Int(SnakeGetZ(a)+9)/10,0)=2 Then
FoodT%=Rand(50,300)
FreeEntity map(FoodX%,FoodZ%,1)
map(FoodX%,FoodZ%,0)=0
t%=CreateSphere()
EntityColor t%,10,250,30
ScaleMesh t%,1*j1#,1*j1#,1.5*j1#
PositionMesh t%,0,(1*j1#)-0.2,0
SnakeAddSegment(a%,t%)
j1#=j1#-0.05
EndIf
По принципу проверки на коллизию со стенкой проверяем на коллизию с едой... если true то приступаем к поеданию... для начала запустим таймер еды, поскольку эта будет съедена и надо будет создавать другую... затем удаляем с поля объект еды FreeEntity()? хендл еды хранится в соответствующей ячейке массива map... так, еду удалили,,, теоретически она должна быть в животе у змеи и она должна от этого вырасти - реализуем это на практике путем создания дополнительного сегмента... тут все просто: создаем сферу, скалим ее, позиционируем, и взываем функцию добавления
кстати про функцию добавления... ее пришлось маленько переписать... в прошлом мы брали позицию головы и создавали в ней очередной сегмент... теперь нам надо создавать новый сегмент в хвосте... иначе видно мигание куска хвоста в голове...
новая процедура выглядит следующим образом
Function SnakeAddSegment(id%,h%)
For SnakeManager.snm = Each snm
If id%=SnakeManager\id% Then
s%=SnakeManager\s%
SnakeManager\c%=SnakeManager\c%+1
For Snake.sn=Each sn
x#=Snake\x#
y#=Snake\y#
z#=Snake\z#
ax#=Snake\ax#
ay#=Snake\ay#
az#=Snake\az#
Next
For i=1 To s
Snake.sn = New sn
Snake\id%=id%
Snake\x#=x#
Snake\y#=y#
Snake\z#=z#
Snake\ax#=ax#
Snake\ay#=ay#
Snake\az#=az#
If i=s Then Snake\h%=h%
Next
Return
EndIf
Next
End Function
здесь мы в случае нахождения куска от нужной змеи сохраняем координаты... в конце цикла переменные куда мы сохраняли координаты будут содержать координаты последнего элемента (не забываем и про углы)... и теперь мы в создании очередных резервных хранилищ и сегмента оперируем координатами предыдущего...
ну вот вроде бы и все... теперь змея умеет есть, видеть препятствия и ей запрещено выходить за границы карты...
пример рабочего кода на этом шаге см в аттаче