Показать сообщение отдельно
Старый 29.07.2006, 00:48   #8
SubZer0
Администратор
 
Аватар для SubZer0
 
Регистрация: 03.09.2005
Сообщений: 2,408
Написано 301 полезных сообщений
(для 996 пользователей)
Сообщение Туториал "Змейка" (ЕДА)

Продолжим:

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


на мнужно както представить весь игровой мир... в простых случаях (как наш) его представляют массивом (в сложном случае базой данных)... представим его трехмерным массивом map в котором: первое измерение - координаты по X, второе измерение - координаты по Y и третье измерение - типы объектов (0 - код объекта, 1 хендл объекта)... третье измерение нужно нам для хранения кода препятствия... у нас ведь будут различные типы препятствий (стена и еда), ну и чтобы в любой случай можно было чтонить с объектом (препятствием) сделать и не искать его или не заводить кучу дополнительный переменных тоже нужно поле массива.

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

значит так: создание мира:
Dim Map%(15,15,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
здесь мы в случае нахождения куска от нужной змеи сохраняем координаты... в конце цикла переменные куда мы сохраняли координаты будут содержать координаты последнего элемента (не забываем и про углы)... и теперь мы в создании очередных резервных хранилищ и сегмента оперируем координатами предыдущего...

ну вот вроде бы и все... теперь змея умеет есть, видеть препятствия и ей запрещено выходить за границы карты...

пример рабочего кода на этом шаге см в аттаче
__________________
Как минимум я помог многим (с)
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
LLI.T.A.L.K.E.R. (05.02.2010)