24 марта 2010 в 11:47
Blitz3d уроки 12. Первая 3Д игра–устранение багов
…Надоело играть… слишком сырая получилась… хотелось бы её переделать. Вот и давайте её доработаем…
Первым, что бросается в глаза – во-первых, (во всяком случае на более медленных машинах это заметно) это то, что когда мы прикасаемся к цилиндру, он меняет своё положение, причём 2 раза, во-вторых очки тоже прибавляются на 2, хотя мы белым по синему написали “Score=Score+1” то бишь на 1, а не на 2, ну, и кроме того в общем скорость тоже увеличивается в 2 раза быстрее чем надо… Когда я это заметил (а заметил я это сразу), моё подсознание сразу так выдала мне способ решения этой баги (интуиция, блин, хорошая вещь), затем через некоторое время сознание дало подробное объяснение, почему это происходит, ну, а память, блин, посчитала эту информацию ненужной и не запомнила … короче не помню я почему, но решается это всего одной единственной строкой:
UpdateWorld
Что вы уже эту команду знаете? И она уже у нас стоит? Правильно, а вы добавьте ещё одну! Да не рядом с предыдущей! Добавьте её в условие соприкосновения шара и Типа Цилиндра после установки цилиндра на новое место… кому здесь не понятно? Объясняю подробнее, кто не хочет осмысливать мою предыдущую фразу: поставьте эту команду после строчки PositionEntity Target,Rnd(-40,40),0,Rnd(-40,40) … Как где она? В программе! !
Почему так происходит? Вспоминать не охота, попробуйте догадаться сами, помню только, что это связано с коллизион детекшном и, кажется после первого UpdateWorld как бы коллизия остаётся, хотя цилиндр перемещается, поэтому надо ставить ещё один… муть какая-то… не помню, в общем и всё тут … (программист называется
Вторая бага:
Вы наверное уже заметили, что иногда, когда вы запускаете игру, она сразу выходит? Вот здесь всё наоборот: объяснение простое, а попариться придётся дольше! Так вот, если вы ещё не поняли, в таких случаях получается так, что кубик создаётся слишком близко к шарику, так что шарик уже «влезает» в него при своём создании, дольше срабатывает условие… и игра выходит… так что нам нужно будет сделать так, что бы кубики не создавались слишком близко к центру…
Сделать это можно в начале… Алгоритм таков: когда кубики случайным образом расставляются по местам, нужно проверять их положение, и, если они будут находиться на расстоянии меньше чем 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), то цикл повторяется (так пока кубик не встанет в нужное место)… короче, получается такой квадрат размером 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… так как здесь применяется метод проверки полигон к полигону, она довольно медленная, (зато точная ) но для нашей игры как раз…
Дальше – как идёт цикл…
Сначала мы задаём переменной inter значение False, затем ставим в случайное место цилиндр, и затем идёт цикл из 29 проверок, и если цилиндр пересекается хотя бы с одним из кубиков, значение переменной inter становится равным True. Ну и дальше проверяем – если inter так и осталась False идём дальше, если нет – возвращаемся и проводим все операции заново…
Ну, вот вроде все самые бросающиеся в глаза баги убрали – теперь это довольно играбельный движок …
А вот всё что у нас есть на данный момент:
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
комментарии отсутствуют
авторизуйтесь