|
FAQ Туториалы и часто задаваемые вопросы |
04.09.2005, 06:02
|
#1
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
page # 0
Всем привет!
По опыту знаю: большинство хочет сразу после просмотра сэмплов сесть и написать FPS. И не просто какой-нибудь: УБЕЙ_ИХ_ВСЕХ_2010, а что-нибудь революционно-инновационное – с крутейшей графикой, умнейшим ИИ, и возможностью сетевой игры на разных протоколах и в разных игровых режимах, с абсолютной нелинейностью сюжета, причём всё это будет требовать смехотворно мало ресурсов. Если Вы именно такой пользователь THEN goto основы. Так как начинать с подобного рода программ – отбивать себе всякое желание программить на Блитце – попишите пока тетрисы, змейки и проч.
начало статьи (с иллюстрациями, безвозвратно канувшими в Лету, благодаря очередному переезду):
http://blitzetcetera.org/index.php/С...Person_Shooter
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
Последний раз редактировалось impersonalis, 25.01.2008 в 23:14.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
04.09.2005, 06:03
|
#2
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
подготовка
Итак… FPS… конечно же 3D! Запускаем компилятор и смело вбиваем
Graphics3D 800,600,32
SetBuffer BackBuffer()
чуть ниже организовываем цикл, это будет главный цикл программы MAIN LOOP. Оформляйте его любыми операторами цикла, я, лично, сделаю так:
While Not KeyHit(1)=1
Wend
end
тут всё должно быть ясно как день:
цикл крутится пока Не ПрерываниеОтКнопки (Escape)
команда END в данном случае – чистый формализм: после инструкции WEND у нас в коде ничего нет, таким образом, после выхода из цикла программа и так завершится. Но всё же я настоятельно рекомендую не пренебрегать подобными формальностями!
Уже можно давить F5 – и любоваться … космосом… без звёзд…
Теперь займёмся камерой… даже - лучше сразу игроком
Опять же: я настоятельно рекомендую заключать подобные знаковые участки кода в тела функций. Поэтому где-нибудь повыше напишем:
Function create_user()
End Function
Если Вы затрудняетесь определить: «где же это самое то место» - в принципе Блитцу всё равно, но я настоятельно рекомендую объявлять все функции перед главным циклом (а так как это не С++, то и писать тела функций там же), а поскольку в функции будут использоваться команды работы с 3d-объектами объявить их надо после строчек
Graphics3D 800,600,32
SetBuffer BackBuffer()
Надеюсь, с местом определились.
Теперь передаваемые в функцию аргументы… Думаю, удобно будет задавать ими место появления игрока. С другой стороны, практически всегда у нас он появляется в 0,h#,0 – в центре карты на небольшом расстоянии от земли, поэтому пишем следующее:
Function create_user(x#=0,y#=1,z#=0)
End Function
Теперь подумаем о физической модели игрока… В масштабах этого манула, позволительно допустить: игрока никто не видит, и камера как в FPS. Значит не стоит отвлекаться на фактический внешний вид игрока. У нас должна быть точка опоры и над ней (на некотором расстоянии) камера. А это, имхо, самый простой и надёжно работающий способ решения:
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
набираем мы в функции. Сам пользователь – это будет сфера (та самая точка) к которой прикреплена камера : в координатах 0,1,-0.5 относительно сферы. Камера прикрепляется сразу после создания, т.к. ей задан родитель (парент) в качестве аргумента. Затем происходит её позиционирование, и затем позиционирование самого игрока.
Запускаем… И снова темнота :sad
А как по-вашему: у нас есть описание действия «создать игрока» и пустой цикл.
Для начал надо вызвать функцию создания перед главным циклом:
Затем: ну да – в памяти мы создали и сферку и камеру – а дальше то что? Как минимум надо это всё обработать как геометрические объекты и отрисовать в BackBuffer . Добавим в главном цикле команду:
Ещё одна неувязочка: на экране находится при двойной буферизации FrontBuffer, а менять содержимое буферов мы будем командой
После такой перекройки программа должна выглядеть примерно так:
Graphics3D 800,600,32
SetBuffer BackBuffer()
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
create_user()
While Not KeyHit(1)=1
RenderWorld()
Flip
Wend
End
Снова запускаем – и опять темнота… :surpr Но на самом деле всё рисуется – сфера которую вы не видите, потому что «не можете наклонить голову» и… всё – больше в мире пока ничего нет.
Нам нужна земная твердь. И обязательно текстурка для неё. Ведь компьютер без дополнительных инструкций строит идеальные видео образы – абсолютно ровную поверхность земли (на самом деле мелкие неровности пока тоже ничего бы не дали – нет освещения – которое и позволяет видеть объёмную картину мира , без света всё будет казаться «плосокватым») так что вы просто увидите светлый прямоугольник занимающий часть экрана. Для примера – стандартная Блитц-текстура:
Опять же прибегая к упрощениям – земля будет в виде бесконечной ровной поверхности – создадим её плэйном:
затем загрузим текстурку
tertex=LoadTexture("terrain1.jpg")
и наложим её на поверхность
EntityTexture terrain,tertex
ну и для профилактики очистим память из под текстуры – она нам больше не понадобиться:
Ах да всё это должно быть набрано после инициализации графики но перед циклом.
И ещё немного подумав, объединим вызов ф-ции создания игрока и создание мира в одну функцию:
Graphics3D 800,600,32
SetBuffer BackBuffer()
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
create_world()
While Not KeyHit(1)=1
RenderWorld()
Flip
Wend
End
Та-дам! Запускаем, наслаждаемся :D
ПРОДОЛЖЕНИЕ СЛЕДУЕТ
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:03
|
#3
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
кодим-кодим
Для практики: закомментируем команду текстурирования террайна и посмотрим на выполнение:
Graphics3D 800,600,32
SetBuffer BackBuffer()
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
;EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
create_world()
While Not KeyHit(1)=1
RenderWorld()
Flip
Wend
End
Как я и обещал, видим светлый прямоугольник отхапавший часть экрана. :grins Раскомментируем строчку обратно.
Кстати о комментариях: не стоит ими пренебрегать но и объяснять всё подряд не стоит. :o
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
;создание игрока
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
;функции закончились :)
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
RenderWorld()
Flip
Wend
;----------------------------
End
Надеюсь, вы уже обучили Блитц понимать русский язык? Только по секрету:
http://community.boolean.name/index.php?act=ST&f=4&t=25
Не стоит так же пренебрегать грамотным форматированием кода:
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
;создание игрока
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
;функции закончились :)
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
RenderWorld()
Flip
Wend
;----------------------------
End
Вот…
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо impersonalis за это полезное сообщение:
|
|
04.09.2005, 06:06
|
#4
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Озираемся и бегаем
Так-с-с : на поверхность посмотрели – пора двигаться дальше. Будем учить игрока двигаться:
;обновление игрока
Function update_user()
End Function
Так получается, что к глазам игрока (камере) и его ногам (сфере) будут обращаться вне функции создания игрока. А значит надо сделать хендлы камеры и сферы глобальными. Для этого подготовим для их хранения глобальные переменные:
Global user
Global camera
Теперь это уже не локальные переменные функции create_user, а глобальные всей программы.
Игрока мы будем обновлять на каждой итерации главного цикла, поэтому сразу допишем вызов соответствующей функции:
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
;создание игрока
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
;обновление игрока
Function update_user()
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
;функции закончились :)
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
RenderWorld()
Flip
Wend
;----------------------------
End
Так… перейдём к программированию движений: для удобства объявим в нашей функции переменную, отвечающую за смещения по осям (никто не мешает вам сделать разную скорость для движения вперёд, назад и шагов влево-вправо)
и кодируем движения нашей сферки (напомню: на ней укреплена камера)
If KeyDown(203)=1 *Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 *Then MoveEntity user,V#,0,0
If KeyDown(200)=1 *Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 *Then MoveEntity user,0,0,-V#
Запустим… результат, конечно зависит от производительности вашей машины, но, думаю, он не будет сильно разнится: при движении земля жутко мельтишит под ногами, так что невозможно даже оценить – в какую сторону мы сейчас двигаемся. Для устранения этого надо или понизить коэффициент скорости, или (что мы и сделаем ) растянуть текстурку:
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10;вот тута новое
EntityTexture terrain,tertex
мир по-прежнему имеет весьма сомнительный вид, но уже лучше, чем было :grins
Теперь займёмся обзорами местности.
Будем вращать камеру вверх-вниз в зависимости от смещения мыши по Y-оси и влево-вправо от смещения по X-оси.
Угу: как же ну смотрю я вправо… ещё вправо… опа: курсор упёрся в правый край экрана и всё :sungl . Значит после оценки изменений мы должны вернуть мышь на исходную – самое логичное, в центр экрана. Получить текущий размер экрана в пикселях по X и по Y можно функциями
GraphicsWidth()
GraphicsHeight()
соответственно. Т.е. задвинуть мышь в центр экрана:
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
А снять перемещение мыши – измерив её скорость по осям:
MouseYSpeed()
MouseXSpeed()
Но вот ещё загвоздка: если мы будем крутить только камеру, то получается: мы развернули камеру влево и нажали кнопку ВПЕРЁД, но наша опора то как стояла, так и стоит неразвёрнутой – в результате смотрим вбок и прём вперёд, а надо бы идти, туда куда смотрим. С другой стороны вращать только основу мы не можем по схожей причине: Уставились мы в небо и нажали ВПЕРЁД и наша основа полетела тоже в небо (даже если мы включим гравитацию, эффект останется – модуль скорости будет равен проекции вектора скорости на поверхность т.е. если мы задерём голову вверх – cos(90)=0 и мы не сможем двигаться).
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
т.е. после доработок:
Function update_user()
V#=0.5
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 *Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 *Then MoveEntity user,V#,0,0
If KeyDown(200)=1 *Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 *Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
End Function
Ндя… :o неприятный осадок всё же остался: как это можно так задрать голову, что увидеть происходящее за спиной и ниже и сделать 360 градусный проворт головы?!
Модифим – теперь камера не будет превышать указанный нами угол вверх и вниз:
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 *Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 *Then MoveEntity user,V#,0,0
If KeyDown(200)=1 *Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 *Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
End Function
ABS-модуль
EntityPitch# ( entity[,global] ) – угол вращения в плоскости Y0Z, т.е. вокруг оси X
SGN – функция-знак
Если что не понятно - ставим курсор на функцию и кликаем 2 раза F1.
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
;создание игрока
Function create_user(x#=0,y#=1,z#=0)
user=CreateSphere()
camera=CreateCamera(user)
PositionEntity camera,0,1,-0.5
PositionEntity user,x#,y#,z#
End Function
;обновление игрока
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 *Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 *Then MoveEntity user,V#,0,0
If KeyDown(200)=1 *Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 *Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10
EntityTexture terrain,tertex
FreeTexture tertex
create_user()
End Function
;функции закончились :)
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
RenderWorld()
Flip
Wend
;----------------------------
End
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:08
|
#5
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
"честная" физика
Так-с приступим к добавлению гравитации. Объявим где-нибудь в глобале переменную ускорения
свободного падения
Обратите внимание на идентификатор const (константа) и тип переменной (#-с плавающей
точкой).
Теперь надо реализовать контроль за отрывом от поверхности...
Это можно сделать 2 способами через просчёт столкновений (Collisions) и через "пики"
(Pick). С одной стороны, так как Collisions обрабатывается дольше, сложнее в коде... и
самое главное так или иначе автоматически производит response - один из 3-х методов
обработки столкновения:
1: stop
2: slide1 - full sliding collision
3: slide2 - prevent entities from sliding down slopes
С другой стороны обрабатывать это будет проще... впал в раздумья... короче делаем через
collision.
Добавим в глобал константы типов
Const USERT=1;for user
Const TERRT=2;for terrain
Переходим в Create_user() и делаем следующее.
Переходим в Create_world() и делаем следующее.
и после вызова create_user()
Collisions USERT,TERRT,2,3
в главном цикле допишем
и наконец в update_user() нацарапем
;физика
TranslateEntity user,0,-G#,0
/сразу предупреждаю физиков: это не окончательный вараинт кода/
И мы смело двигаем пользователя вниз ф-цией TranslateEntity.
TranslateEntity отличается от MoveEntity безразличем к пространственной ориентации самой
модели. Пример: если объект перевернуть "на голову", то команда move вниз приведёт к
движению этого объекта вверх, Translate же будет двигать объект вниз.
Перейдём в create_user() и подправим кое-что:
Function create_user(x#=0,y#=10,z#=0)
PositionEntity camera,0,2,-0.5
Можно запускать! В начале текста я немного занизил высоту камеры относительно "ног", что
сейчас и исправил. Теперь, между прочим, стала заметна сфера. Вернёмся к ф-ции создания:
user=CreateSphere()
EntityAlpha user,0
Этим мы задали нулевую "альфу" для сферы - т.е. сделали её полностью прозрачной.
Термины "полностью прозрачный" и "невидимый" здесь не одно и то же. Если первый сводится к
изменению альфы (и объект просто не видим для камер), то второй реализуется командой
HideEntity (и объект убирается из процедуры рендера движка). Но об этом как-нибудь в другой раз.
Как очевидно, код:
TranslateEntity user,0,-G#,0
не совсем то, что нам нужно. Хотя вблизи земли разницы никакой нет (допустимые
приближения). Вообще, здесь гравитация (вернее её подобие) нужна не столько для симуляции реалистичной физики, сколько для "прижимания" игрока к земле.
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
Const G#=1
Const USERT=1;for user
Const TERRT=2;for terrain
;создание игрока
Function create_user(x#=0,y#=10,z#=0)
user=CreateSphere()
EntityAlpha user,0
camera=CreateCamera(user)
PositionEntity camera,0,2,-0.5
PositionEntity user,x#,y#,z#
EntityType user,USERT
End Function
;обновление игрока
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 Then MoveEntity user,V#,0,0
If KeyDown(200)=1 Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
;физика
TranslateEntity user,0,-G#,0
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10
EntityTexture terrain,tertex
FreeTexture tertex
EntityType terrain,TERRT
create_user()
Collisions USERT,TERRT,2,3
End Function
;функции закончились
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
UpdateWorld()
RenderWorld()
Flip
Wend
;----------------------------
End
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:09
|
#6
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Конечно, ничто кроме фантазии программиста не ограничивает возможности языка - так что, никто не мешает Вам, немного поразмыслив, реализовать настоящую модель гравитации.
Обратите внимание: я стараюсь заменять конструкции типа x/2 на x*0.5 - это связано со спецификой обработки этих мат.операций процессором (спросите у SubZer0)
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:16
|
#7
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Прицел
Тихо - не ржите:
Тыкс загрузим картинку прицела в глобале
Global pricel=LoadImage("pricel.bmp")
назначаем начало координат картинки в её центре
А это
DrawImage pricel,MouseX(),MouseY()
нужно вписть в главном цикле... вот не скажу где
Если вы использовали мой прицел, то увидите, что отображается он несовсем как хотелось бы.
Установим Mask-цвет - белый:
Global pricel=LoadImage("pricel.bmp")
MidHandle pricel
MaskImage pricel,255,255,255
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:21
|
#8
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Так: немного подправим код для удобства:
внесём прицел в функцию создания перса, м немного морфируем физ. модель игрока. Теперь уже понятно почему и когда мы крутим камеру и основание. И теперь для удобства просчёта коллизий камеру поместим в центр прозрачной сферы.
И ещё
CameraRange camera,0.1,100
установит минимальный и максимальный радиусы рендеринга
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
Const G#=1
Const USERT=1;for user
Const TERRT=2;for terrain
Global pricel=LoadImage("pricel.bmp")
;создание игрока
Function create_user(x#=0,y#=10,z#=0)
MidHandle pricel
MaskImage pricel,255,255,255
user=CreateSphere()
k#=3
ScaleEntity user,k#,k#,k#
EntityRadius user,k#
camera=CreateCamera(user)
CameraRange camera,0.1,100
PositionEntity user,x#,y#,z#
EntityType user,USERT
End Function
;обновление игрока
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 Then MoveEntity user,V#,0,0
If KeyDown(200)=1 Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
;физика
TranslateEntity user,0,-G#,0
End Function
;создание игрового мира
Function create_world()
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10
EntityTexture terrain,tertex
FreeTexture tertex
EntityType terrain,TERRT
create_user()
Collisions USERT,TERRT,2,3
End Function
;функции закончились
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
UpdateWorld()
RenderWorld()
DrawImage pricel,MouseX(),MouseY()
Flip
Wend
;----------------------------
End
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:26
|
#9
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Выстрелы
Global shot_sprite=LoadSprite("sprite.bmp")
это будет спрайт выстрела.
В создании мира добавим
скрыв таким образом загруженный спрайт.
Создадим функцию порождения выстрела
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#)
End Function
6 аргументов описывают вектор выстрела: з координаты и углы вращения по осям
Создадим тип выстрела:
Type shot
Field entity
End Type
Далее...
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#)
s.shot=New shot
s\entity=CopyEntity(shot_sprite)
PositionEntity s\entity,x#,y#,z#,1
RotateEntity s\entity,pitch#,yaw#,roll#,1
Return True
End Function
В первой строке при помощи опереатора NEW создаём новый элемент типа shot.
Теперь через S мы можем обратиться к любому полю данного элемента типа shot.
s\entity - обращаемся к полю entity вновь созданного элемента. Сохраняем туда handle копии спрайта. Далее позиционируем вновь созданный (скопированный) спрайт и разворачиваем его. Последний аргумент 1 (true) означает, что действия будут выполнятся относительно мировых координат и осей.
Function update_shot()
vs#=1
For a.shot=Each shot
MoveEntity a\entity,0,0,vs#
Next
End Function
For a.shot=Each shot - на первый взгляд, заковыпистая конструкция. Такой цикл будет помещать по очереди в переменную а хендлы всех элементов указанного типа (в данном случае shot). Таким образом данный цикл продвинет все спрайты выстрелов на vs# вдоль оси Z.
Добавляем update_shot() в главный цикл.
Добавим строку
If MouseHit(1) create_shot(EntityX(user),EntityY(user),EntityZ(user),EntityPitch(camera),EntityYaw(user),0)
В ф-цию обновления игрока.
Уже можно посмотреть в действии:
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:28
|
#10
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Собственно, текстура спрайта (спрайт):
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:29
|
#11
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
вот так будут улетать вдаль спрайты. Слово далеко относится к неопределённой логике. Ограничим расстояние полёта.
добавим ещё одно поле в тип. И обработаем его:
Function update_shot()
vs#=1
max_dist#=1000
For a.shot=Each shot
MoveEntity a\entity,0,0,vs#
a\dist#=a\dist#+vs#
If a\dist#>max_dist#
FreeEntity a\entity
Delete a
EndIf
Next
End Function
будем накапливать всоответствующем поле пройденное "снарядом" расстояние, и если оно больше максимального, то: очистим память, занимаемую спрайтом, затем удалим этот элемент типа. В том, что всё работает как надо Вы можите убедиться поэкспериментировав со значением max_dist# и сделав кучу выстрелов (после исчезновения выстрелов фпс возвращается в стабильное состояние).
в глобал.
Collisions SHOTT,TERRT,2,1
в создание мира
EntityType s\entity,SHOTT
в создании выстрела.
Если запустить программу теперь, то можно наблюдать забавный эффект - поверхность стала уловителем выстрелов:
Обновим условие в цикле обработки выстрелов
If a\dist#>max_dist#
FreeEntity a\entity
Delete a
ElseIf EntityCollided(a\entity,TERRT) < > 0
FreeEntity a\entity
Delete a
EndIf
Теперь при столкновении текущего спрайта с объектом, у которого коллизионный тип (а не "обычный" тип - как shot) TERRT, происходит удаление выстрела.
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
Const G#=1
Const USERT=1;for user
Const TERRT=2;for terrain
Const SHOTT=3;for shot
Global pricel=LoadImage("pricel.bmp")
Global shot_sprite=LoadSprite("sprite.bmp")
Type shot
Field entity
Field dist#
End Type
;создание игрока
Function create_user(x#=0,y#=10,z#=0)
MidHandle pricel
MaskImage pricel,255,255,255
user=CreateSphere()
k#=3
ScaleEntity user,k#,k#,k#
EntityRadius user,k#
camera=CreateCamera(user)
CameraRange camera,0.1,100
PositionEntity user,x#,y#,z#
EntityType user,USERT
End Function
;обновление игрока
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 Then MoveEntity user,V#,0,0
If KeyDown(200)=1 Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
If MouseHit(1) create_shot(EntityX(user),EntityY(user),EntityZ(user),EntityPitch(camera),EntityYaw(user),0)
;физика
TranslateEntity user,0,-G#,0
End Function
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#)
s.shot=New shot
s\entity=CopyEntity(shot_sprite)
EntityType s\entity,SHOTT
PositionEntity s\entity,x#,y#,z#,1
RotateEntity s\entity,pitch#,yaw#,roll#,1
Return True
End Function
Function update_shot()
vs#=1
max_dist#=1000
For a.shot=Each shot
MoveEntity a\entity,0,0,vs#
a\dist#=a\dist#+vs#
If a\dist#>max_dist#
FreeEntity a\entity
Delete a
ElseIf EntityCollided(a\entity,TERRT) < > 0
FreeEntity a\entity
Delete a
EndIf
Next
End Function
;создание игрового мира
Function create_world()
HideEntity shot_sprite
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10
EntityTexture terrain,tertex
FreeTexture tertex
EntityType terrain,TERRT
create_user()
Collisions USERT,TERRT,2,3
Collisions SHOTT,TERRT,2,1
End Function
;функции закончились
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
update_shot()
UpdateWorld()
RenderWorld()
DrawImage pricel,MouseX(),MouseY()
Flip
Wend
;----------------------------
End
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:30
|
#12
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Кодим-кодим
На ряду с описанными в хелпе функциями, для работы с типами, есть и недокументированные команды Object и Handle, которые облегчают программирование доступа к конкретному элементу типа. Об этом в другой раз.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:32
|
#13
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
коварные боты
Итак, оружие есть - надо и поохотиться )
Создадим тип для ботов
Type bot
Field entity
End Type
Далее как обычно:
Function create_bot(x#,y#,z#)
b.bot=New bot
b\entity=CreateSphere()
PositionEntity b\entity,x#,y#,z#
Return True
End Function
Для простоты визуализация бота будет сведена отображению на экране сферы.
Function update_bot()
v#=0.3
For a.bot=Each bot
PointEntity a\entity,user
MoveEntity a\entity,0,0,v#
Next
End Function
Тут всё ясно как день. За исключением, быть может, команды PointEntity entity,target[,roll#] . Так как основы создания искусственного
интеллекта на базе нейроподобных сетей здесь рассматривать не имеет смысла. А ур-ий, по которым бот, так или иначе, будет за вами двигаться,
можно придумать достаточно много, то ограничимся результатом работы самой простой (в исполнении Блитца) команды. После её выполнения объект
entity будет развёрнут "лицом" (т.е. в сторону положительного направления Z-оси) к объекту target. Это допустимо, так как в нашем случае
действие происходит на плоскости.
Не забываем про главный цикл программы
Чуть не забыл (куда это добавлять - должно быть уже очевидно, если нет - в конце я прилагаю исходный код всей программы):
Collisions BOTT,TERRT,2,3
Collisions BOTT,USERT,2,3
Collisions BOTT,BOTT,2,3
Collisions USERT,BOTT,2,3
Collisions SHOTT,BOTT,2,1
а в функции создания мира
Можно запустить и посмотреть. Как видно, на некотором расстоянии от игрока, бот остановится и начнёт совершать непонятные движения - это он
наткнулся на прозрачную сферу, которой окружён игрок.
Перепишем ф-цию обновления выстрелов:
Function update_shot()
vs#=1
max_dist#=1000
For a.shot=Each shot
MoveEntity a\entity,0,0,vs#
a\dist#=a\dist#+vs#
bot_h=EntityCollided(a\entity,BOTT)
If a\dist#>max_dist#
FreeEntity a\entity
Delete a
ElseIf EntityCollided(a\entity,TERRT) < > 0
FreeEntity a\entity
Delete a
ElseIf bot_h < > 0
FreeEntity a\entity
Delete a
For q.bot=Each bot
If q\entity=bot_h
FreeEntity bot_h
Delete q
Exit
EndIf
Next
EndIf
Next
End Function
Фууу... меня очень угнетает цикл с перебором всех ботов в поисках записи о подбитом, но объяснять как это можно сделать проще, а главное
быстрее здесь не буду (есть небольшой трюк с использованием недокументированных команд и именами объектов). И чтобы превратить игру в
бесконечно долгую, перепишем условие уничтожения бота:
FreeEntity bot_h
Delete q
create_bot(EntityX(user)+Rnd(-100,100),2,EntityZ(user)+Rnd(-100,100))
Exit
Теперь за каждого убитого бота около игрока (в радиусе 100) будет "респиться" новый бот.
Причём сколько было ботов при загрузке - такое их кол-во и будет поддерживаться в игре.
Перепишем функцию создания мира:
c_bot=Input("input Amount")
For i=1 To c_bot
create_bot(Rnd(-100,100),2,Rnd(-100,100))
Next
При загрузке будет запрос на ввод кол-ва ботов.
Попробуйте указать 20 и ничего не делайте - вскоре боты заблокируют вас полностью.
Понаблюдайте за обработкой коллизий.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:33
|
#14
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Даже если Вы работаете с типами впервые, рассмотренного здесь вполне достаточно, чтобы реализовать "жизни" для ботов и зарезервировать поля для хранения промежуточных результатов работы ИИ.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
04.09.2005, 06:39
|
#15
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Для придания объёма (это надо было ещё вначале сделать) я добавил в create_world() создание и ротацию света:
light=CreateLight()
RotateEntity light,90,0,0
;инициализация графики
Graphics3D 800,600,32
SetBuffer BackBuffer()
Global user
Global camera
Const G#=1
Const USERT=1;for user
Const TERRT=2;for terrain
Const SHOTT=3;for shot
Const BOTT=4;for bot
Global pricel=LoadImage("pricel.bmp")
Global shot_sprite=LoadSprite("sprite.bmp")
Type shot
Field entity
Field dist#
End Type
Type bot
Field entity
End Type
;создание игрока
Function create_user(x#=0,y#=10,z#=0)
MidHandle pricel
MaskImage pricel,255,255,255
user=CreateSphere()
k#=3
ScaleEntity user,k#,k#,k#
EntityRadius user,k#
camera=CreateCamera(user)
CameraRange camera,0.1,100
PositionEntity user,x#,y#,z#
EntityType user,USERT
End Function
;обновление игрока
Function update_user()
V#=0.5
u#=70;предельный угол
TurnEntity camera,MouseYSpeed(),0,0
TurnEntity user,0,-MouseXSpeed(),0
If KeyDown(203)=1 Then MoveEntity user,-V#,0,0
If KeyDown(205)=1 Then MoveEntity user,V#,0,0
If KeyDown(200)=1 Then MoveEntity user,0,0,+V#
If KeyDown(208)=1 Then MoveEntity user,0,0,-V#
MoveMouse GraphicsWidth()*0.5,GraphicsHeight()*0.5
If Abs(EntityPitch#(camera))>u# RotateEntity camera,u#*Sgn(EntityPitch#(camera)),0,0
If MouseHit(1) create_shot(EntityX(user),EntityY(user),EntityZ(user),EntityPitch(camera),EntityYaw(user),0)
;физика
TranslateEntity user,0,-G#,0
End Function
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#)
s.shot=New shot
s\entity=CopyEntity(shot_sprite)
EntityType s\entity,SHOTT
PositionEntity s\entity,x#,y#,z#,1
RotateEntity s\entity,pitch#,yaw#,roll#,1
Return True
End Function
Function update_shot()
vs#=1
max_dist#=1000
For a.shot=Each shot
MoveEntity a\entity,0,0,vs#
a\dist#=a\dist#+vs#
bot_h=EntityCollided(a\entity,BOTT)
If a\dist#>max_dist#
FreeEntity a\entity
Delete a
ElseIf EntityCollided(a\entity,TERRT) < > 0
FreeEntity a\entity
Delete a
ElseIf bot_h < > 0
FreeEntity a\entity
Delete a
For q.bot=Each bot
If q\entity=bot_h
FreeEntity bot_h
Delete q
create_bot(EntityX(user)+Rnd(-100,100),2,EntityZ(user)+Rnd(-100,100))
Exit
EndIf
Next
EndIf
Next
End Function
Function create_bot(x#,y#,z#)
b.bot=New bot
b\entity=CreateSphere()
EntityType b\entity,BOTT
PositionEntity b\entity,x#,y#,z#
Return True
End Function
Function update_bot()
v#=0.3
For a.bot=Each bot
PointEntity a\entity,user
MoveEntity a\entity,0,0,v#
Next
End Function
;создание игрового мира
Function create_world()
light=CreateLight()
RotateEntity light,90,0,0
HideEntity shot_sprite
terrain=CreatePlane()
tertex=LoadTexture("terrain1.jpg")
ScaleTexture tertex,10,10
EntityTexture terrain,tertex
FreeTexture tertex
EntityType terrain,TERRT
create_user()
c_bot=Input("input Amount")
For i=1 To c_bot
create_bot(Rnd(-100,100),2,Rnd(-100,100))
Next
Collisions USERT,TERRT,2,3
Collisions SHOTT,TERRT,2,1
Collisions BOTT,TERRT,2,3
Collisions BOTT,USERT,2,3
Collisions BOTT,BOTT,2,3
Collisions USERT,BOTT,2,3
Collisions SHOTT,BOTT,2,1
End Function
;функции закончились
;--------------------------------
create_world()
;MAIN LOOP
While Not KeyHit(1)=1
update_user()
update_shot()
update_bot()
UpdateWorld()
RenderWorld()
DrawImage pricel,MouseX(),MouseY()
Flip
Wend
;----------------------------
End
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 07:45.
|