12. Первая 3Д игра. Часть 2 – устранение багов

 

…Надоело играть… слишком сырая получилась… хотелось бы её переделать. Вот и давайте её доработаем…

 

Первым, что бросается в глаза – во-первых, (во всяком случае на более медленных машинах это заметно) это то, что когда мы прикасаемся к цилиндру, он меняет своё положение, причём 2 раза, во-вторых очки тоже прибавляются на 2, хотя мы белым по синему написали “Score=Score+1” то бишь на 1, а не на 2, ну, и кроме того в общем скорость тоже увеличивается в 2 раза быстрее чем надо… Когда я это заметил (а заметил я это сразу), моё подсознание сразу так выдала мне способ решения этой баги (интуиция, блин, хорошая вещь J), затем через некоторое время сознание дало подробное объяснение, почему это происходит, ну, а память, блин, посчитала эту информацию ненужной и не запомнила J… короче не помню я почему, но решается это всего одной единственной строкой:

 

UpdateWorld

 

Что вы уже эту команду знаете? И она уже у нас стоит? Правильно, а вы добавьте ещё одну! Да не рядом с предыдущей! Добавьте её в условие соприкосновения шара и Типа Цилиндра после установки цилиндра на новое место… кому здесь не понятно? Объясняю подробнее, кто не хочет осмысливать мою предыдущую фразу: поставьте эту команду после строчки PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40) … Как где она? В программе! J!

 

Почему так происходит? Вспоминать не охота, попробуйте догадаться сами, помню только, что это связано с коллизион детекшном и, кажется после первого UpdateWorld как бы коллизия остаётся, хотя цилиндр перемещается, поэтому надо ставить ещё один… муть какая-то… не помню, в общем и всё тут J… (программист называется J)

 

Вторая бага:

 

Вы наверное уже заметили, что иногда, когда вы запускаете игру, она сразу выходит? Вот здесь всё наоборот: объяснение простое, а попариться придётся дольше! Так вот, если вы ещё не поняли, в таких случаях получается так, что кубик создаётся слишком близко к шарику, так что шарик уже «влезает» в него при своём создании, дольше срабатывает условие… и игра выходит… так что нам нужно будет сделать так, что бы кубики не создавались слишком близко к центру…

 

Сделать это можно в начале…  Алгоритм таков: когда кубики случайным образом расставляются по местам, нужно проверять их положение, и, если они будут находиться на расстоянии меньше чем 3 от центра, задавать их положение заново… т.е. циклом с условием.

 

Так нам просто строчку в цикле создания кубиков:

 

PositionEntity Walls(i),Rnd(-40,40),0,Rnd(-40,40)

 

Нужно заменить на:

 

Repeat 

 PositionEntity Walls(i),Rnd(-40,40),0,Rnd(-40,40)

Until Abs(EntityX(Walls(i)))>4 Or Abs(EntityZ(Walls(i)))>4

 

Так, новые слова: Abs(число) – это не команда, а функция. Она возвращает нам модуль числа в скобках (т.е. если в скобках было –4, то она возвращает 4, если 5 – то число так и остаётся положительным: 5).

 

Эти строчки расшифровываются так: Сначала в случайное место ставится кубик, затем идёт проверка, если X координата или Z координата меньше 4 по модулю (т.е. в диапазоне от –4 до 4), то цикл повторяется (так пока кубик не встанет в нужное место J)… короче, получается такой квадрат размером 4*4 вокруг центра, в который кубики уже никогда не попадут… (можно кстати сделать ограничение не квадратом, а кругом – заменив на Until Sqr(Abs(EntityX(Walls(i)))^2 + Abs(EntityZ(Walls(i)))^2)>10 , по обычной теории Пифагора, но это ни к чему…)

 

Третья бага:

 

Особенно некрасиво смотрится, когда цилиндр оказывается внутри какого-либо кубика, и его невозможно достать… сейчас мы с ней справимся.

 

Опять же исправлять это надо в тот момент, когда цилиндр куда-то ставится случайным образом… Алгоритм будет примерно такой же как в прошлый раз – т.е. в цикле с условием, только на этот раз предметом проверки будет пересечение цилиндра с кубиками…

 

Так, строчку в главном цикле:

 

PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40)

 

…нам нужно заменить, вот только каким образом это лучше сделать? В прошлый раз у нас было 29 квадратов, и на каждый была одна проверка… здесь у нас один цилиндр, только кубиков – 30… поэтому и цилиндр будет проверяться на пересечение 30 раз – таким образом:

 

  Repeat

   inter=False

   PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40)

   For i=0 To 29

    If MeshesIntersect(Target, Walls(i)) inter=True

   Next

  Until inter=False

 

Объясняю как это происходит:

 

Для начала новая команда – MeshesIntersect(объект1,объект2) возвращает True, если объект1 пересекается с объектом2… так как здесь применяется метод проверки полигон к полигону, она довольно медленная, (зато точная J) но для нашей игры как раз…

 

Дальше – как идёт цикл…

 

Сначала мы задаём переменной inter значение False, затем ставим в случайное место цилиндр, и затем идёт цикл из 29 проверок, и если цилиндр пересекается хотя бы с одним из кубиков, значение переменной inter становится равным True. Ну и дальше проверяем – если inter так и осталась False идём дальше, если нет – возвращаемся и проводим все операции заново…

 

Ну, вот вроде все самые бросающиеся в глаза баги убрали – теперь это довольно играбельный движок J

А вот всё что у нас есть на данный момент:

 

SeedRnd MilliSecs()

 

Graphics3D 640,480,16,1

SetBuffer BackBuffer()

 

Const TypePlayer=1,TypeWalls=2,TypeTarget=3

Global Speed#=.1,Score=0

 

Global Player=CreateSphere()

 

Plac=CreateCone(8)

RotateMesh Plac,-90,0,0

ScaleMesh Plac,1,1,1.2

PositionMesh Plac,0,0,-1.5

AddMesh Plac,Player

EntityType Player, TypePlayer

 

FreeEntity Plac

 

Dim Walls(29)

 

For i=0 To 29

 Walls(i)=CreateCube()

 Repeat 

  PositionEntity Walls(i),Rnd(-40,40),0,Rnd(-40,40)

 Until Abs(EntityX(Walls(i)))>10 Or Abs(EntityZ(Walls(i)))>10

 EntityType Walls(i), TypeWalls

Next

 

Target=CreateCylinder()

PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40)

 

EntityType Target,TypeTarget

 

cam=CreateCamera()

PositionEntity cam,0,60,0

TurnEntity cam,90,0,0

 

lit=CreateLight()

TurnEntity lit,70,70,0

 

Collisions TypePlayer,TypeWalls,2,2

Collisions TypePlayer,TypeTarget,2,2

 

Repeat

 

 

 MoveEntity Player,0,0,Speed#

 If KeyDown(203) TurnEntity Player,0,3,0

 If KeyDown(205) TurnEntity Player,0,-3,0

 

 If EntityCollided (Player,TypeTarget)

  Repeat

   inter=False

   PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40)

   For i=0 To 29

    If MeshesIntersect(Target, Walls(i)) inter=True

   Next

  Until inter=False

  UpdateWorld

  Score=Score+1

  Speed=Speed+.01

 EndIf

 

 If EntityCollided (Player,TypeWalls) End

 

 UpdateWorld

 RenderWorld

 

 Color 255,215,0

 Text 320,10,"Score : "+Score,True,True

 

 Flip

 

Until KeyHit(1)

 

End

 

 

 Оглавление:

 

0.  Введение

1.  В начале была Тьма

2.  Есть ли жизнь в DirectX

3.  Свобода и Власть 3Д (0)

4.  Свобода и Власть 3Д (1)

5.  2Д в 3Д

6.  Трёхмерный курсор

7.  Родительская зависимость или Привязки

8.  Фишки с привязками

9.  Коллизион Детекшн или как устроен мир…

10.     Первая 3Д игра. Часть 0 – основы движка

11.     Первая 3Д игра. Часть 1 – разработка движка

12.     Первая 3Д игра. Часть 2 – устранение багов

13.     Первая 3Д игра. Часть 3 – внешний вид

14.     Первая 3Д игра. Часть 4 – от массива к спискам

15.     Первая 3Д игра. Часть 5 – оптимизация кода

16.     Первая 3Д игра. Часть 6 – завершение

17.     Выведение

 

 

 

 

Используются технологии uCoz