Blitz 3D - полезная дипломная работа (часть 2)
[ Поделиться ]
[ Спасибо! ]
|
В дальнейшем в спецкурсе условия понадобятся только для организации опроса клавиатуры, т. е. выполнения каких – либо действий при нажатии определенных клавиш. Но, будет нелишне дать определение условий и разъяснить принцип действия структуры условия.
Условие IF-THEN-ELSE-END IF (20 мин)
Условия - это выражения, которые бывают ЛОЖНЫМИ или ИСТИННЫМИ.
В условиях можно использовать следующие знаки: равно (=), больше (>), меньше (<), больше или равно (>=), меньше или равно (<=), не равно (<>)
Условие A = B ИСТИННО, когда A равно B и ЛОЖНО в других случаях
Условие A > B ИСТИННО, когда A больше B и ЛОЖНО в других случаях
И т. д.
Строки могут быть равными или не равными (учитывается регистр букв).
Примеры ИСТИННЫХ условий:
1 = 1, 5 > 3, 2 <= 2, 1 <= 2, 65 <> 22, = <> "Машина” <> ”МаШиНа” (*)
Примеры ЛОЖНЫХ условий:
10 = 11, 51 < 3, 25 >= 20, 0 <> 0, = ”Стоп!”, = <> (*)
Синтаксис условия IF-THEN:
IF условие THEN
….
эти операторы выполняются, когда условие ИСТИННО
….
ELSE
….
эти операторы выполняются, когда условие ЛОЖНО
….
END IF
Примеры:
Принцип действия этих примеров стоит разъяснить дословно.
IF Power > 10 THEN (*)
PRINT "Перегрузка!”
ELSE
PRINT "Все в порядке!”
END IF
Можно записать и так:
IF Power > 10 THEN PRINT "Перегрузка!” ELSE PRINT "Все в порядке!” (*)
ELSE можно и не включать:
IF Points >= 5 THEN PRINT "Великолепно!” (*)
Программа, проверяющая пароль (10 мин)
Password$ = INPUT$("Введите пароль:”)
IF Password$ = THEN
PRINT "Пароль правильный!”
PRINT "Добро пожаловать в систему!”
ELSE
PRINT "Пароль неправильный. Вход воспрещен.”
END IF
WAITKEY
Программа, проверяющая, больше ли пятидесяти введенное число (10 мин)
A = INPUT$("Введите число:”)
IF A > 50 THEN
PRINT "Число больше ELSE
PRINT "Число не больше END IF
WAITKEY
Бесконечные циклы (5 мин)
Цикл, выполняющийся бесконечно много раз легко организовать с помощью команд REPEAT-FOREVER:
REPEAT
PRINT "Это будет повторяться бесконечно!”
FOREVER
Циклы этого типа понадобятся в дальнейшем для осуществления бесконечного повторения опроса клавиатуры и визуализации трехмерной сцены в соответствии с изменениями параметров трехмерных объектов.
Остановка программы
Как же теперь остановить программу? Для этого нужно нажать на кнопку с крестом в правом верхнем углу окна.
Команда EXIT (10 мин)
Выходом из этого цикла (и из других тоже) служит команда EXIT:
Данная команда в дальнейшем будет использоваться для осуществления выхода из бесконечного цикла и завершения программы при нажатии клавиши "Esc".
Пример:
A = 1
REPEAT
A = A * 2
PRINT A
IF A > 500 THEN
PRINT "Слишком много!”
EXIT
END IF
FOREVER
WAITKEY
Управление камерой с клавиатуры (25 мин)
Следующее условие ИСТИННО в том случае, если в данный момент нажата определенная клавиша и ЛОЖНО, если она не нажата.
IF KEYGET (scancode) THEN
Каждая клавиша на клавиатуре имеет скан-код (scancode). В таблице по адресу Help \ Command Reference \ Scancodes приведены скан-коды для каждой клавиши. Скан-коды часто используемых клавиш приведены в памятке.
Теперь сделаем управление камерой с клавиатуры для программы "fir" - для этого мы должны создать бесконечный цикл (чтобы компьютер вновь и вновь опрашивал клавиатуру) и поместить внутри него команды поворота камеры. При этом мы должны периодически осуществлять визуализацию. Также, добавим условие для выхода из программы при нажатии клавиши ESC. Итак, заменим строки:
RENDERWORLD
FLIP
WAITKEY
на следующие:
Задаем начальные значения углов:
xa = 0
ya = 0
REPEAT
Меняем угол поворота вокруг оси OX:
IF KEYDOWN(200) THEN xa = xa + 1; вверх
IF KEYDOWN(208) THEN xa = xa - 1; вниз
Меняем угол поворота вокруг оси OY:
IF KEYDOWN(203) THEN ya = ya + 1; влево
IF KEYDOWN(205) THEN ya = ya - 1; вправо
Устанавливаем углы поворота камеры:
ROTATEENTITY cam, xa, ya, 0
Выход по нажатию клавиши ESC:
IF KEYDOWN(1) THEN EXIT; ESC - выход
Визуализируем трехмерный мир:
RENDERWORLD
FLIP
FOREVER
Запишем эту программу под именем Урок 5 – Функции и группирование объектов
Функции (10 мин)
В Blitz3D есть множество различных функций. Это выражения, которые выдают какое-либо значение и могут требовать один или несколько параметров. Функции записываются так: сначала имя функции, затем в скобках перечисляются параметры через запятую. Функции можно использовать в выражениях наравне с переменными.
Список функций:
SQR (a) - квадратный корень числа
ABS (a) - модуль числа
SIN (a) - синус угла
COS (a) - косинус угла
TAN (a) - тангенс угла
ASIN (a) - арксинус
ACOS (a) - арккосинус
ATAN (a) - арктангенс
ATAN2 (x,y) - угол между осью OX и радиус-вектором AB (A(0,0), B(x,y))
INT(a) - округление числа до ближайшего целого
FLOOR (a) - округление числа в меньшую сторону
CEIL (a) - округление числа в большую сторону
RAND (a, b) - случайное целое число в диапазоне от a до b
RND (a, b) - случайное дробное число в диапазоне от a до b
MILLISECS () - текущее системное время в миллисекундах
Примеры использования функций:
B = INT (A#), X = X + RAND(-1, 1) (*)
X = R * Cos (Ang#), R = SQR (X * X + Y * Y) (*)
Игра "Угадай число" (25 мин)
Эта программа использует большинство структур, изученных ранее и будет хорошим закрепляющим материалом.
Эта строка для того, чтобы каждый раз не загадывалось одно и то же число:
SEEDRND MILLISECS()
Компьютер загадывает число:
N = RAND (1, 100)
Бесконечный цикл, чтобы игрок мог пытаться угадывать число несколько раз:
REPEAT
Играющий вводит число:
I = INPUT$("Угадай число:”)
IF I = N THEN
Играющий угадал число, поздравляем его с победой и выходим:
PRINT "Поздравляю! Вы выиграли!”
EXIT
END IF
IF I > N THEN
Число больше задуманного:
PRINT "Это число слишком велико”
ELSE
Число меньше задуманного:
PRINT "Это число слишком мало”
END IF
FOREVER
WAITKEY
Задание: изменить программу так, чтобы у играющего было только 8 попыток, количество попыток выводилось на экран и при их исчерпании выводилось сообщение о проигрыше (10 мин)
Задание может вызвать трудности у некоторых учащихся, поэтому стоит помочь им наводящими вопросами. Ученики, имеющие опыт в программировании, скорее всего, смогут справиться с заданием самостоятельно.
Введем следующие строки программы после REPEAT:
Увеличиваем счетчик попыток:
Tries = Tries + 1
If Tries > 8 THEN
Если попыток больше восьми, то выходим с сообщением о проигрыше:
PRINT исчерпали количество попыток. Вы проиграли.”
PRINT число было + N
EXIT
END IF
Выводим количество попыток на экран:
PRINT "Попытка номер + Tries
Группирование объектов (10 мин)
Настало время поговорить о дополнительном параметре "род". Этот параметр задает "родительский" объект для данного. Когда "родительский" объект трансформируется (поворачивается, перемещается, масштабируется), с ним также трансформируются и все его "дети". Для группировки объектов, удобно сначала создать "пустой" объект с помощью следующей команды:
piv = CREATEPIVOT()
Этот объект не отображается на экране, но имеет все параметры трехмерного объекта (координаты, углы поворота, масштаб). Затем, "привяжем" все части объекта к пустому, указав при их создании параметр "род" = piv.
Этот прием, в сущности, позволяет оперировать объектами, которые являются частями более масштабного объекта, как одним целым, используя один адрес. Манипулирование всеми этими объектами по отдельности было бы крайне затруднительно и объем программы заметно увеличился бы.
Есть еще одна полезная команда, копирующая объект:
новый_объект = COPYENTITY(копируемый_объект)
А эта команда позволяет создать массу объектов, идентичных созданному. Причем, при изменении исходного объекта, меняются и все его копии.
Программа, выводящая на экран лес из уже созданных елок (25 мин)
Эта программа наглядно демонстрирует копирование и группирование объектов
Загрузим файл с елкой "fir.bb" и создадим пустой объект (после камеры и света):
fir = CREATEPIVOT()
Добавим в каждый оператор создания объекта созданный "родительский" объект, заменим, например
c1 = CREATECONE(20, 1)
на
c1 = CREATECONE(20, 1, fir)
Затем, создадим цикл (перед командой RENDERWORLD):
FOR x = 1 TO 50
fir2 = COPYENTITY(fir)
POSITIONENTITY fir2, RND(-120, 120), 0, RND(-120, 120)
NEXT
Для большего эффекта, поменяем строки задания камеры:
cam = CREATECAMERA()
POSITIONENTITY cam, 0, 30, -20
ROTATEENTITY cam, 30, 0, 0
Итак, программа:
GRAPHICS3D 640,480
cam = CREATECAMERA()
POSITIONENTITY cam, 0, 30, -20
ROTATEENTITY cam, 30, 0, 0
l = CREATELIGHT()
ROTATEENTITY l, 0, 45, 45
fir = CREATEPIVOT()
c1 = CREATECONE(20, 1, fir)
SCALEENTITY c1, 5, 5, 5
Rnd(-120, 120), 0, Rnd(1, 240)
NEXT
RENDERWORLD
FLIP
WAITKEY
Можно еще поэкспериментировать с программой - добавить модуль управления камерой из программы fir2.
Урок 6 – текстуры, плоскости, модели
На этом уроке рассматриваются дополнительные объекты трехмерной сцены
Плоскости и текстуры (10 мин)
Плоскости в Blitz3D так же, как и в геометрии, простираются в бесконечность. Создать плоскость можно с помощью следующей команды:
a = CREATEPLANE()
Эту плоскость можно поворачивать и перемещать, как обычный объект. Но простая плоскость выглядит достаточно неэффектно, поэтому разберемся с таким полезным понятием, как текстура. Текстура - это растровый (то есть точечный) рисунок, который можно наложить на плоскость и на любой другой трехмерный объект. Это похоже на то, как подарок завертывают в бумагу с орнаментом. Итак, для начала нам нужно загрузить текстуру в память:
a = LOADTEXTURE(файл)
Определение текстуры довольно сложно воспринимается на слух, практическое закрепление будет более результативным.
Файл - это растровый рисунок с расширением bmp, png или jpg. bmp-рисунок можно создать в редакторе Paint, который можно запустить, нажав кнопку "Пуск", затем выбрав в меню Программы->Стандартные->Paint. Рисунки желательно копировать в директорию, где находится программа либо указывать полный путь к ним. Мы будем использовать рисунки из директории C:\media.
После того, как мы загрузили текстуру, ее нужно "привязать" к объекту с помощью команды ENTITYTEXTURE:
ENTITYTEXTURE объект, текстура
Также, текстуру можно масштабировать командой:
SCALETEXTURE текстура, SX, SY
Программа "Лес на траве" (10 мин)
Воспользуемся старой программой и добавим строки создания плоскости перед командой CREATEPIVOT):
Cоздаем плоскость:
ground = CREATEPLANE()
Опускаем плоскость вниз на 8 единиц:
POSITIONENTITY ground, 0, -8, 0
Загружаем текстуру:
grass = LOADTEXTURE("C:\media\grass.jpg")
Увеличиваем текстуру в 50 раз:
SCALETEXTURE grass, 50, 50
Привязываем текстуру к плоскости:
ENTITYTEXTURE ground, grass
Зеркала (5 мин)
Зеркало - это тоже плоскость, которая отражают объекты. Зеркала задаются командой:
a = CREATEMIRROR([род])
Но на зеркало нельзя наложить текстуру, поэтому для создания зеркальной поверхности мы должны применить такой прием: установить прозрачность затекстурированной плоскости и создать на ее месте зеркало.
Программа "Зеркальная земля"
Добавьте следующие строки после недавно введенных команд:
Делаем плоскость земли полупрозрачной:
ENTITYALPHA ground, 0.5
Создаем зеркало:
mirror = CREATEMIRROR()
Перемещаем его туда же, куда переместили плоскость:
POSITIONENTITY mirror, 0, -8, 0
Задание: оттекстурировать ели текстурами moss.jpg и wood.jpg (10 мин)
Это задание является довольно несложным и вполне может быть выполнено учащимися самостоятельно.
Вставить строки перед командой "FOR x = 1 TO 100”:
moss = LOADTEXTURE("C:\media\moss.jpg")
ENTITYTEXTURE c1, moss
ENTITYTEXTURE c2, moss
ENTITYTEXTURE c3, moss
ENTITYTEXTURE c4, moss
wood = LOADTEXTURE("C:\media\wood.jpg")
ENTITYTEXTURE cyl, wood
Трехмерные модели (2.5 мин)
Blitz3D позволяет загружать трехмерные модели, сделанные в 3D-редакторах. Поддерживаются форматы "X", "3DS", "B3D". Модель загружается командой:
a = LOADMESH(файл)
Затем можно работать с ней, как с обычным трехмерным объектом. Часто модели уже оттекстурированы и имеют ссылки на файлы текстур, применять к таким моделям команду ENTITYTEXTURE не стоит.
Наведение камеры на объект (2.5 мин)
Навести камеру на объект можно так:
POINTENTITY камера, объект
В принципе, можно навести любой объект на любой другой.
Управление объектом с клавиатуры (17.5 мин)
Загрузим модель робота с помощью команды:
robot = LOADMESH("C:\MEDIA\running.3ds")
Изменим размеры модели:
SCALEENTITY robot, 0.4, 0.4, 0.4
Теперь зададим начальные значения переменных - координаты робота:
rx#=10; координата X модели робота
rz#=0; координата Z модели робота
ang=90; угол поворота модели робота
Создадим бесконечный цикл, команды для изменения положения робота и условия, изменяющие координаты при нажатии соответствующих клавиш:
REPEAT
Изменение координат и угла поворота:
POSITIONENTITY robot, rx#, -8, rz#
ROTATEENTITY robot, 0, ang + 90, 0
Наводим камеру на робота:
POINTENTITY cam, robot
Если нажата клавиша "вверх", перемещаем робота на вектор с длиной 0.5 под углом ang:
IF KEYDOWN(200) THEN
rx# = rx# + COS(ang) * 0.5
rz# = rz# + SIN(ang) * 0.5
END IF
Изменяем угол поворота модели при нажатии клавиш "влево" и "вправо":
IF KEYDOWN(203) THEN ang = ang + 5
IF KEYDOWN (205) THEN ang = ang - 5
Выходим, если нажата клавиша ESC:
IF KEYDOWN (1) THEN EXIT
RENDERWORLD
FLIP
FOREVER
Анимация (7.5 мин)
Этот и следующий разделы довольно сложны для восприятия и главным образом направлены на демонстрацию возможностей языка.
Также, можно загрузить анимированную модель:
a = LOADANIMMESH(файл)
Каждый такой файл содержит одну последовательность фаз движения (скажем, бег или прыжок). Можно наложить на этот же объект еще одну последовательность фаз с помощью команды:
a = LOADANIMSEQ(объект, файл)
Чтобы анимировать модель, нужно задать параметры анимации с помощью команды:
ANIMATE объект [,режим] [,скорость] [,последовательность] [,количество промежуточных фаз]
Типы анимации:
1 - зацикленная анимация (по достижении конца последовательности, переходим в начало)
2 - пинг-понг (по достижении конца последовательности, прокручиваем ее назад, затем снова и снова)
3 - прокрутить один раз с начала до конца
Чем больше скорость, тем быстрее происходит анимация и наоборот
Чем больше количество промежуточных фаз, тем плавней переход от одной фазы к другой.
И в заключение, необходимо добавить команду UPDATEWORLD перед RENDERWORLD, чтобы обновить форму анимированных объектов.
Добавление анимации в программу (15 мин)
Изменим введенный кусок программы:
Загружаем анимационную последовательность номер 0 - модель робота, смотрящая по сторонам:
robot = LOADANIMMESH("C:\media\standing.3ds")
Добавляем анимационную последовательность номер 1 - бегущая модель робота:
LOADANIMSEQ robot, "C:\media\running.3ds"
SCALEENTITY robot, 0.4, 0.4, 0.4
rx# = 10
rz# = 0
ang = 90
REPEAT
POSITIONENTITY robot, rx#, -8, rz#
ROTATEENTITY robot, 0, ang + 90, 0
POINTENTITY cam, robot
IF KEYDOWN(200)
Если нажата клавиша "вверх" и робот стоит на месте, то задаем анимационную последовательность 1 (бег), тип анимации - зацикленная (1), скорость - 0.5, количество промежуточных фаз - 10
IF ANIMSEQ(robot) = 0 THEN ANIMATE robot, 1, 0.5, 1, 10
rx# = rx# + COS(ang) * 0.5
rz# = rz# + SIN(ang) * 0.5
ELSE
Если клавиша "вверх" не нажата и робот бежит, то задаем анимационную последовательность 0 (стоять на месте), тип анимации - пинг-понг (2), скорость - 1, количество промежуточных фаз - 10
IF ANIMSEQ(robot)=1 THEN ANIMATE robot, 2, 1, 0, 10
END IF
IF KEYDOWN(203) THEN ang = ang + 5
IF KEYDOWN (205) THEN ang = ang - 5
IF KEYDOWN(1) THEN EXIT
Обновляем анимированную модель:
UPDATEWORLD
RENDERWORLD
FLIP
FOREVER
Физическая модель прыжка (15 мин)
Это задание выходит за рамки временного интервала урока, поэтому его лучше провести отдельно.
Теперь добавим возможность прыжка. Для этого необходимо ввести еще одну переменную - ry#, а также приращение dy#:
ry# = -8
dy# = 0
Затем, вводим условие: если нажата клавиша "пробел" и робот стоит на земле (т.е. координата ry# = -8), то задаем импульс -приращение, равное 2
IF KEYDOWN(57) THEN
IF ry# = -8 THEN dy# = 2
END IF
Прибавляем к переменной ry# приращение:
ry# = ry# + dy#
Но, т. к. на робота должна действовать гравитация, мы должны периодически уменьшать приращение на 0.1:
dy# = dy# - 0.1
Причем, координата робота ry# не должна быть меньше -8 (робот не должен опускаться ниже плоскости), поэтому введем следующее условие:
IF ry# < -8 THEN ry# = -8: dy# = 0
Поменяем также фиксированную координату -8 в команде POSITIONENTITY на ry#. Измененный модуль выглядит теперь вот так:
robot = LOADANIMMESH( IMSEQ(robot)=1 THEN ANIMATE robot, 2, 1, 0, 10
END IF
IF KEYDOWN(203) THEN ang = ang + 5
IF KEYDOWN (205) THEN ang = ang - 5
IF KEYDOWN(1) THEN EXIT
UPDATEWORLD
RENDERWORLD
FLIP
FOREVER
Урок 7 – спрайты, поверхности
"Проволочный каркас" (5 мин)
В Blitz3D существует режим отображения, который называется "проволочный каркас". В нем изображаются только контуры элементарных фигур - треугольников. Этот режим включается командой:
WIREFRAME 1
Попробуйте посмотреть в этом режиме последнюю созданную программу.
Этот режим наглядно демонстрирует структуру объектов.
Спрайты (5 мин)
Спрайт - это двумерный рисунок в трехмерном пространстве. Классический спрайт всегда повернут в сторону камеры и меняет размеры в зависимости от расстояния до нее. Любой точечный рисунок можно сделать спрайтом:
a = LOADSPRITE(файл)
Спрайт масштабируется с помощью специальной команды:
SCALESPRITE спрайт, SX, SY
Программа "Звездное небо" (10 мин)
Эта программа похожа на программу создания леса.
Изменим программу с роботом (эти строки нужно добавить после строк текстурирования). Загружаем спрайт:
star = LOADSPRITE("C:\media\star.jpg")
Увеличиваем его размеры в 3 раза:
SCALESPRITE star, 3, 3
Создаем цикл, размещающий случайным образом 100 спрайтов над лесом:
FOR x = 1 TO 100
star2 = COPYENTITY(star)
POSITIONENTITY star2, RND(-120, 120), RND(20, 50), RND(1, 240)
NEXT
Трехмерная поверхность (10 мин)
Трехмерную поверхность можно представить, как листок бумаги в клетку, у которого мы можем задавать высоты точек, лежащих на пересечении линий. Еще, представьте клетчатую сетку, в каждое пересечение брусьев которой впаян штырек. Штыри имеют разные высоты, и если мы накинем на них ткань, то она будет лежать на них некоторой поверхностью.
Этот рисунок желательно продемонстрировать учащимся.
Создается поверхность с помощью команды:
a = CREATETERRAIN(размер [,род])
Параметр «размер» определяет, на сколько клеток делится поверхность по длине и ширине. Он, так же, как и размер текстуры, должен быть степенью двойки. Высоту определенной точки поверхности задает команда:
MODIFYTERRAIN поверхность, x, z, высота
x и z должны лежать в пределах от 0 до размера поверхности - они определяют точку поверхности. Высота должна лежать в интервале [0, 1]. А вот эта команда включает затенение поверхности:
TERRAINSHADING поверхность, 1
Программа, выводящая на экран поверхность воды с рябью (25 мин)
Сделаем заголовок программы:
GRAPHICS3D 640, 480
cam = CREATECAMERA()
POSITIONENTITY cam, 64, 64, -16
ROTATEENTITY cam, 45, 0, 0
l = CREATELIGHT()
ROTATEENTITY l, 0, 45, 45
Создадим поверхность:
t = CREATETERRAIN(64)
Включим затенение поверхности:
TERRAINSHADING t, 1
Загрузим текстуру воды и увеличим ее размер в 16 раз, затем привяжем текстуру к поверхности.
water = LOADTEXTURE("C:\media\water.jpg")
SCALETEXTURE water, 16, 16
ENTITYTEXTURE t, water
Увеличим размеры поверхности (особенно высоту):
SCALEENTITY t, 2, 20, 2
Создадим бесконечный цикл:
REPEAT
Здесь, в этих циклах будут задаваться высоты для каждой из точек поверхности:
FOR x = 0 TO 64
FOR z = 0 TO 64
Вкратце можно описать формулу, по которой задаются точки так: синус расстояния от средней точки поверхности до данной плюс приращение умножается на расстояние.
r# = SQR((x - 32) * (x-32) + (z - 32) * (z - 32)) / 16
MODIFYTERRAIN t, x, z, SIN(r# * 360 + k) / 2 / (r# + 1) + .5
NEXT
NEXT
Добавим команды для визуализации, приращение переменной, условие выхода и закроем цикл:
RENDERWORLD
FLIP
k = k - 5
IF KEYDOWN(1) THEN EXIT
FOREVER
Создание холмистой поверхности (25 мин)
Эта программа показывает последовательное сглаживание поверхности, заданной случайным образом. Создадим заголовок, где будет создана камера, свет и текстурированная поверхность:
GRAPHICS3D 640, 480
cam = CREATECAMERA()
POSITIONENTITY cam, 64, 64, -16
ROTATEENTITY cam, 45, 0, 0
l = CREATELIGHT()
ROTATEENTITY l, 0, 45, 45
t = CREATETERRAIN(64)
TERRAINSHADING t, 1
grass = LOADTEXTURE( "C:\media\grass.jpg" )
SCALETEXTURE grass, 32, 32
ENTITYTEXTURE t, grass
SCALEENTITY t, 2, 60, 2
Делаем цикл из 10 шагов:
FOR n = 1 TO 10
Циклы по всем точкам поверхности:
FOR x = 0 TO 64
FOR z = 0 TO 64
На первом этапе- задаем высоты точек случайным образом:
IF n=1 THEN
MODIFYTERRAIN t, x, z, RND(0, 1)
Else
На следующих этапах устанавливаем для каждой точки значение высоты, равное среднему арифметическому между значениями высоты ее и соседних:
MODIFYTERRAIN t, x, z, (TERRAINHEIGHT(t, x - 1, z) + TERRAINHEIGHT(t, x, z - 1) + TERRAINHEIGHT(t, x, z) + TERRAINHEIGHT(t, x + 1, z) + TERRAINHEIGHT(t, x, z + 1)) / 5
END IF
NEXT
NEXT
Визуализируем сцену, ждем нажатия клавиши и закрываем цикл:
RENDERWORLD
FLIP
WAITKEY
NEXT
Урок 8 – Чтение данных, построение моделей
Операторы READ и DATA (7.5 мин)
Часто бывает так, что нужно переработать в цикле много однородных данных. Для этого существуют операторы READ и DATA. Оператор READ читает значения задаваемых переменных из списка DATA. Синтаксис:
READ переменная1, переменная2, ...
DATA значение1, значение2, ...
Наберем небольшую программу:
FOR n = 1 TO 5
READ a
PRINT a
NEXT
DATA 1, 10, 19, 125, 563
Команда "READ читает одно значение из списка DATA и заносит его в переменную затем команда "PRINT выводит переменную a на экран. В цикле этот процесс происходит 5 раз. Еще можно читать строки, а также писать в операторе несколько переменных через запятую. В операторе READ важно помнить, какой тип данных вы считываете.
Программа, выводящая фигуру из сфер, считывая их координаты (10 мин)
Инициализируем трехмерную сцену:
GRAPHICS3D 640,480
cam = CREATECAMERA()
l = CREATELIGHT()
Задаем цикл из 8 повторений:
FOR n = 1 TO 8
Создаем сферу:
a = CREATESPHERE()
Читаем два значения и заносим их в две переменные дробного типа:
READ x#, y#
Помещаем созданную сферу в точку, заданную считанными переменными:
POSITIONENTITY a, x#, y#, 5
Закрываем цикл и выводим сцену на экран:
NEXT
RENDERWORLD
FLIP
WAITKEY
Это данные для оператора READ - восемь раз по два значения
DATA -1.5, 2, -1, 3, 0, 3.5, 1, 3, 1.5, 2, 1, 1, 0, 0, 0, -2
Построение трехмерных фигур по треугольникам (17.5 мин)
До сих пор мы строили трехмерные сцены из объемных фигур. Но, во многих случаях требуется построить трехмерный объект, который формой отличается от них (взять хотя бы усеченный конус). Для этого в Blitz3D существуют команды построения объектов по элементарным частям - треугольникам. Сначала нужно создать пустую фигуру:
a = CREATEMESH([род])
Эта фигура состоит из поверхностей, каждая из которых имеет свои параметры (текстуру, цвет и т. д.). Поэтому, далее мы создаем поверхность для заданной фигуры:
a = CREATESURFACE(фигура)
Теперь можно добавлять к ней треугольники. Для этого, вначале, нужно найти координаты вершин и внести их в поверхность. Первая введенная вершина имеет индекс 0, следующая - 1 и т. д. Это делается с помощью команды:
ADDVERTEX поверхность, x, y, z, u, v
x, y, z – координаты вершины в пространстве, u, v – координаты на текстуре. Текстурные координаты нужны, чтобы правильно наложить текстуру на объект – они задают соответствие между вершинами в пространстве и точками двумерного рисунка текстуры. Текстура зациклена, то есть бесконечно простирается во все стороны, повторяясь, как плитки паркета. Координаты u = 0 и v = 0 задают угол такой плитки, а u = 0.5 и v = 0.5 – середину. Таким образом, длина "плитки” текстуры по вертикали и горизонтали равна 1ед независимо от ее разрешения.
Следующий шаг – задание самих треугольников. Они задаются командой:
ADDTRIANGLE поверхность, вершина1, вершина2, вершина3
Вершины задаются индексами. Необходимо отметить, что на самом деле такой треугольник имеет только одну сторону. Представим, что он спроецирован на экран. Треугольник изображается тогда, когда его вершины расположены в порядке по часовой стрелке – это значит, он повернут видимой стороной к камере. Если же вершины треугольника расположены против часовой стрелки, значит, он невидим в данный момент и изображать его не нужно. Для обеспечения корректного освещения предназначена следующая команда:
UPDATENORMALS фигура
Создание модели меча (45 мин)
Сначала полезно построить чертеж и найти координаты вершин.
Создаем заголовок:
GRAPHICS3D 640,480
cam = CREATECAMERA()
POSITIONENTITY cam, 0, 0, -30
l = CREATELIGHT()
ROTATEENTITY l, 0, 45, 45
Загрузим текстуры:
wood = LOADTEXTURE("c:\media\wood.jpg")
steel = LOADTEXTURE("c:\media\steel.jpg",1 + 8 + 64)
Дополнительный параметр во второй строке означает то, что текстура является сферической картой отражений. Это особый тип текстуры, который создает иллюзию зеркальности объекта. Создаем две пустые фигуры и накладываем на них текстуры steel (сталь) и wood (дерево):
m1 = CREATEMESH()
ENTITYTEXTURE m1, steel
m2 = CREATEMESH(m1)
ENTITYTEXTURE m2, wood
Так как порядок действий для оформления фигур один и тот же, а в программе необходимо создать две фигуры, то удобнее будет сделать это в цикле. Оператор IF-THEN задает первую фигуру для оформления в первом шаге цикла, а вторую – во втором.
FOR n=1 TO 2
IF n = 1 THEN
m = m1
ELSE
m = m2
END IF
Создаем поверхность, привязанную к фигуре:
s = CREATESURFACE(m)
Считываем количество вершин:
READ vq
Цикл по всем вершинам:
FOR nn = 1 TO vq
Считываем координаты вершины:
READ x#, y#, z#
Добавляем вершину к поверхности (координаты текстуры возьмем случайные) и закрываем цикл:
ADDVERTEX s, x#, y#, z#, RND(1), RND(1)
NEXT
Считываем кол-во треугольников
READ tq
Цикл по всем треугольникам:
FOR nn = 1 TO tq
Считываем индексы вершин:
READ v1, v2, v3
Добавляем треугольник, закрываем цикл:
ADDTRIANGLE s, v1, v2, v3
NEXT
Обеспечение корректного освещения:
UPDATENORMALS m
NEXT
Теперь вернемся к основной программе. Создадим две фигуры с адресами m1 и m2 и текстурами steel и wood. Обратите внимание на то, что родительский объект фигуры m1 равен 0, то есть не существует.
m1 = READMESH(0, steel)
m2 = READMESH (m1, wood)
Создадим ручку меча – цилиндр:
cyl = CREATECYLINDER(20, 1, m1)
POSITIONENTITY cyl, 0, -3, 0
SCALEENTITY cyl, 1, 2, 1
ENTITYTEXTURE cyl, wood
Перекладина гарды меча:
cube = CREATECUBE(m1)
POSITIONENTITY cube, 0, -0.5, 0
SCALEENTITY cube, 3, 0.5, 1
ENTITYTEXTURE cube, wood
Далее идет цикл с командами управления вращением меча с клавиатуры:
REPEAT
IF KEYDOWN(200) THEN xa = xa + 1
IF KEYDOWN(208) THEN xa = xa - 1
IF KEYDOWN(203) THEN ya = ya + 1
IF KEYDOWN(205) THEN ya = ya - 1
ROTATEENTITY m1, xa, ya, 0
IF KEYDOWN(1) THEN EXIT
RENDERWORLD
FLIP
FOREVER
Данные рекомендуется найти по чертежу, привлекая к поиску учеников.
Данные (9 вершин лезвия):
DATA 9
DATA -2, 0, 0
DATA 0, 0, -0.5
DATA 2, 0, 0
DATA 0, 0, 0.5
DATA -2, 20, 0
DATA 0, 19, -0.5
DATA 2, 20, 0
DATA 0, 19, 0.5
DATA 0, 22, 0
12 треугольников лезвия:
DATA 12
DATA 0, 4, 1
DATA 4, 5, 1
DATA 4, 8, 5
DATA 8, 6, 5
DATA 5, 6, 2
DATA 5, 2, 1
DATA 0, 3, 4
DATA 3, 7, 4
DATA 3, 2, 7
DATA 2, 6, 7
DATA 7, 8, 4
DATA 7, 6, 8
10 вершин концов гарды:
DATA 10
DATA -5, -2, 0
DATA -3, 0, -1
DATA 3, 0, -1
DATA 5, -2, 0
DATA 3, -1, -1
DATA -3, -1, -1
DATA -3, 0, 1
DATA 3, 0, 1
DATA 3, -1, 1
DATA -3, -1, 1
8 треугольников концов гарды:
DATA 8
DATA 0, 1, 5
DATA 0, 9, 6
DATA 0, 6, 1
DATA 0, 5, 9
DATA 4, 3, 8
DATA 2, 3, 4
DATA 7, 3, 2
DATA 8, 3, 7
Урок 9 – массивы, взаимодействие объектов
Массивы (10 мин)
Далее массивы понадобятся для хранения адресов, координат, приращений.
Одномерный массив можно представить, как полоску клетчатой бумаги, в каждой клетке которой записано какое-л значение. Пример:
задаются командой:
DIM имя_массива (количество_элементов)
Примеры:
DIM A(7), DIM Name$(5), DIM K#(256)
Числовой массив изначально заполнен нулями, строковой – пустыми строками.
Массивы также бывают двумерными, трехмерными и т. д.:
Для доступа к элементу массива необходимо указать имя и в скобках номер, например A(2), A(5), Name$(4). Для двумерного массива нужно указать два номера, для трехмерного – три и т. д.
Пример:
DIM K(3, 3)
K(1, 2) = 5
K(3, 1) = 4
PRINT K(1, 1)
PRINT K(1, 2)
Программа, заполняющая массив – таблицу умножения (5 мин)
DIM A(10, 10)
FOR X = 1 TO 10
FOR Y = 1 TO 10
A(X, Y) = X * Y
NEXT
NEXT
Задание: вывести элементы массива, соответствующие умножению 5 на 7 и 3 на 9 (5 мин)
PRINT * 7 = + A(5, 7)
PRINT * 9 = + A(3, 9)
Обработка массива объектов (20 мин)
В предыдущих программах уже создавались множества однотипных объектов, но дальше в программе с ними не происходило никаких изменений. Адрес этих объектов терялся, так как мы, создавая новый объект в цикле, присваивали его адрес одной и той же переменной. Для сохранения этих адресов в памяти воспользуемся массивами.
Напишем программу, которая перемещает в пространстве 100 звезд по разным траекториям. Сначала – заголовок. Здесь создается камера и загружается спрайт:
GRAPHICS3D 640,480
cam = CREATECAMERA()
POSITIONENTITY cam, 0, 0, -20
star = LOADSPRITE("C:\MEDIA\STAR.JPG")
Теперь необходимо разобраться с физической моделью программы. Изначально, 100 звезд размещаются в пространстве случайным образом. Каждая звезда имеет приращения по каждой из координатных осей, которые сначала равняются нулю, но изменяются, в зависимости от положения звезды относительно начала координат. То есть, если какая-либо координата положительна, то приращение уменьшается, если отрицательна – увеличивается. Это приводит к тому, что звезда будет кружиться вокруг начала координат по изогнутой траектории, которую называют кривой Лиссажу.
Создадим три массива. Первый будет содержать адреса спрайтов, второй – их координаты, третий – приращения. Так как координат всего три, а звезд – 100, то второй и третий массивы будут иметь размерность 100 x 3. Звезда n будет иметь адрес addr(n), располагаться в точке с координатами x = c#(n, 1), y = c#(n, 2), z = c#(n, 3) и иметь приращения dx = dc#(n, 1), dy = dc#(n, 2), dz = dc#(n, 3)
DIM addr(100)
DIM c#(100, 3)
DIM dc#(100, 3)
В следующем цикле создается 100 звезд
FOR n = 1 TO 100
addr(n) = COPYENTITY(star)
FOR nn = 1 TO 3
Каждая из трех координат приравнивается к случайному значению от –8 до 8.
C#(n, nn) = RND(-8, 8)
NEXT
NEXT
Далее следует бесконечный цикл, в котором для каждой из 100 звезд изменяются координаты и приращения, а также происходит визуализация трехмерной сцены:
REPEAT
В двух вложенных циклах к каждой координате каждой звезды прибавляется ее приращение. Затем в зависимости от знака координаты, приращение изменяется (если с#(n, nn) < 0, то SGN(с#(n, nn)) = -1 и приращение увеличивается на 0.005 и наоборот). Затем спрайт звезды помещается в точку, заданную координатами.
FOR n = 1 TO 100
FOR nn = 1 TO 3
c#(n, nn) = c#(n, nn) + dc#(n, nn)
dc#(n, nn) = dc#(n, nn) - 0.005 * SGN(c#(n, nn))
NEXT
POSITIONENTITY addr(n), c#(n,1), c#(n,2), c#(n,3)
NEXT
IF KEYDOWN(1) THEN EXIT
RENDERWORLD
FLIP
FOREVER
Взаимодействие объектов (15 мин)
В большинстве случаев, когда программа оперирует массивом объектов, встает вопрос об их взаимодействии. Наиболее часто встречаемый вариант – столкновение объектов. Когда два или более материальных объекта пытаются занять одно и то же пространство, нужен способ изменить их траекторию (другие варианты – уничтожить один из них, остановить оба объекта и т. д.). Этот случай называется столкновением или коллизией. Blitz3D может автоматически реагировать на столкновения, используя один из нескольких стандартных методов.
Чтобы активизировать механизм реагирования на столкновения нужно вначале задать тип сталкиваемых объектов с помощью команды:
ENTITYTYPE объект, тип
Это нужно для того, чтобы затем определить, какие объекты с какими и как должны сталкиваться. Тип – это число. Задавая один и тот же тип для разных объектов, вы определяете их, как группу участников столкновений. Теперь нужно задать механизм столкновения командой:
COLLISIONS тип движущегося объекта, тип неподвижного объекта, метод определения столкновения, реакция
Данная команда определяет столкновение, если объект первого типа движется и пытается занять пространство второго, неподвижного. Если двигаются оба объекта, то сначала первый из них надвигается на второй, затем второй на первый.
Методы столкновения: 1 - сфера со сферой, 2 – сфера с многогранником, 3 – сфера с параллелепипедом. То есть, движущийся объект всегда виртуально представлен сферой, то есть вне зависимости от его формы он будет реагировать на столкновения, как сфера. Можно задавать радиус этой сферы:
ENTITYRADIUS объект, радиус сферы
Реакция на столкновение может быть двух типов: 1 – остановка объекта, 2 – скольжение объекта вдоль неподвижного.
И в заключение, необходимо дать команду UPDATEWORLD, чтобы проверить столкновения и соответственно отреагировать.
Для следующей программы понадобятся функции определения текущих координат объекта
ENTITYX(объект) – координата X
ENTITYY(объект) – координата Y
ENTITYZ(объект) – координата Z
Программа, создающая нагромождение шаров (20 мин)
Создадим заголовок:
GRAPHICS3D 640,480
cam = CREATECAMERA()
l = CREATELIGHT()
ROTATEENTITY l, 45, 45, 0
Создадим и оттектурируем плоскость:
grass = LOADTEXTURE("C:\MEDIA\GRASS.JPG")
SCALETEXTURE grass, 16, 16
p = CREATEPLANE()
POSITIONENTITY p, 0, -5, 0
ENTITYTEXTURE p, grass
Зададим тип плоскости, равным 1, тип шаров будет равным 2:
ENTITYTYPE p, 1
Шары (2) могут сталкиваться с плоскостью (1), которая определяется, как многогранник(2), при этом они будут останавливаться (1):
COLLISIONS 2, 1, 2, 2
Шары (2) могут сталкиваться с другими шарами (2), которые определяются, как сферы(1), при этом они будут скользить(2):
COLLISIONS 2, 2, 1, 2
Когда переменная s равна 0, это означает, что нужно создать новый шар:
s = 0
Бесконечный цикл:
REPEAT
IF s = 0 THEN
Создаем шар, если s = 0, задаем его тип (2) и радиус сферы столкновения (1):
s = CREATESPHERE()
ENTITYTYPE s, 2
ENTITYRADIUS s, 1
Задаем случайное местоположение шара на высоте 12:
POSITIONENTITY s, RND(-5,5), 12, RND(10,20)
END IF
Заносим текущие координаты шара в три переменные:
sx# = ENTITYX(s)
sy# = ENTITYY(s)
sz# = ENTITYZ(s)
Шар перемещается вниз под воздействием гравитации:
MOVEENTITY s, 0, -0.3, 0
Проверяем столкновения:
UPDATEWORLD
Если координаты шара не изменились, то он прочно застрял и нужно бросать новый шар:
IF sx# = ENTITYX(s) AND sy#=ENTITYY(s) AND SZ# = ENTITYZ(s) THEN s = 0
Завершаем цикл, визуализируем сцену:
IF KEYDOWN(1) THEN EXIT
RENDERWORLD
FLIP
FOREVER
Заключение
Основная цель данного спецкурса - заинтересовать людей этим перспективным направлением в программировании и показать его возможности. Базовые навыки, данные здесь, конечно, не могут полностью охватить все аспекты (особенно математические) создания комплексной программы трехмерного моделирования, для научного эксперимента и других целей. Но, проведенные занятия дадут импульс заинтересованным людям для дальнейшего изучения языка Blitz3D (возможно, трехмерных технологий других, более близких им языков), что позволит им в будущем стать специалистами в этой области, использовать знания в применении к другим научным дисциплинам.
Спецкурс был проведен в Естественно-Математическом Лицее №1 г. Южно-Сахалинска. Ученики успешно освоили программу данного курса. В ходе занятий у учеников возникало множество вопросов, на которые были даны исчерпывающие ответы. Все программы были набраны, отлажены и запущены. Материалы этого спецкурса можно рекомендовать к использованию при факультативном изучении данного раздела информатики, при необходимости корректируя структуру уроков.
Памятка(1)
Сочетания клавиш:
Shift-Ctrl - переключение шрифта с английского на русский и обратно
Shift+курсорные стрелки - выделить фрагмент текста
Ctrl-Ins - копировать выделенный фрагмент в буфер
Shift-Ins - копировать выделенный фрагмент из буфера на место курсора
Переменные:
A - целая
A# - дробная
A$ - строковая
Команды:
WAITKEY - ждать нажатия клавиши
Режим экрана:
GRAPHICS3D ширина, длина, [глубина цвета] [,режим] - установка режима экрана.
WIREFRAME 1 - "проволочный каркас"
Создание объектов:
a = CREATECUBE([род]) - создать куб
a = CREATESPHERE([детализация] [,род]) - создать сферу
a = CREATECYLINDER([детализация] [,наличие оснований] [,род]) - создать цилиндр
a = CREATECONE([детализация] [,наличие основания] [,род]) - создать конус
a = CREATECAMERA([род]) - создать камеру
a = CREATELIGHT([тип] [,род]) - создать источник освещения
a = CREATEPIVOT([род]) - создать пустой объект
a = CREATEPLANE([род]) - создать плоскость
Визуализация:
RENDERWORLD - отобразить мир на экранный буфер
FLIP - копировать содержимое экранного буфера на экран
Управление объектами:
POSITIONENTITY объект, X, Y, Z - задать координаты объекта
ROTATEENTITY объект, RX, RY, RZ - задать угол поворота объекта
SCALEENTITY объект, SX, SY, SZ - задать масштаб объекта
COLORENTITY объект, красный, зеленый, синий - задать цвет объекта
ENTITYALPHA объект, коэффициент прозрачности - задать прозрачность объекта
a = COPYENTITY (объект) - скопировать объект
POINTENTITY камера, объект - навести камеру на объект
Текст:
PRINT - вывести значение выражения на экран
A$=INPUT$([приглашение]) - задать переменную, введя строку с клавиатуры
Ц
Категория: Blitz 3D |
Просмотров: 4142 |
Добавил: ДядяВолк (11.08.2010)
| Рейтинг: 5.0/1
Источник: http://quadrathell.cn.ua/ | |
HTML ссылка на материал: BB ссылка на материал: |
Всего комментариев: 0 | |