forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ (http://forum.boolean.name/forumdisplay.php?f=15)
-   -   Создаём свой FPS (first person shooter) (http://forum.boolean.name/showthread.php?t=15)

impersonalis 20.02.2006 21:45

Вложений: 2
Квази-интеллект
Немного усложним поведение ботов - чтобы игра не была такой "пресной".
Сделаем из бота агр-моба (см LA2).
Сценарий следующий:
Цитата:

Бот шатается по уровню туда-сюда, пока мимо него не промчится игрок. Как только происходит это событие, бот переключается на игрока (со всеми последствиями). В случае если игрок отрывается на безопасное расстояние от преследователя - бот переходи снова к мироному шатанию по уровню.

Нам понадобиться ещё одно поле в типе бота - хендл пивота-вейпоинта.
Код:

Type bot
        Field entity
        Field time
        Field Survivability
        Field point
End Type

Правим функцию создания бота:
Код:

b\point=CreatePivot()
PositionEntity b\point,x,y,z
Return True

Ну и теперь програмим квази-интеллект:
Код:

Function update_bot()
        Rdist#=15
        v#=0.01
        For a.bot=Each bot
        ;=
 If a\time=0 a\time=MilliSecs()
 new_time=MilliSecs()
 delta_t=new_time-a\time
 a\time=new_time
        ;=
 If EntityDistance(user,a\entity)<Rdist#
        PointEntity a\entity,user
 Else
        If EntityDistance(a\entity,a\point)<2
  PositionEntity a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
        EndIf
        PointEntity a\entity,a\point
 EndIf
        ;===========
 MoveEntity a\entity,0,0,v#*delta_t
 TranslateEntity user,0,-G#*delta_t,0
        Next
End Function

Rdist# отвечает за расстояние, на котором бот переключается на игрока.
Рассмотрим подробнее:
Код:

If EntityDistance(user,a\entity)<Rdist#
Если расстояние до игрока меньше критического - время действовать.
Код:

PointEntity a\entity,user
"наводка" на игрока.
Если же игрока рядом нет, то
Код:

If EntityDistance(a\entity,a\point)<2
Бот подошёл к контрольной тчке достаточно близко - пора её сменить
Код:

PositionEntity a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
в любом случае - наводим бота на точку:
Код:

PointEntity a\entity,a\point
А дальше - дело техники :)

impersonalis 21.02.2006 01:03

Квази-интеллект2
Слегка погонял ботов и понял, что чего-то не хватает.
Подправим алгоритм поведения:
Цитата:

Если бот получил урон от выстрела он начинает двигаться в строну выстрела. Причём игрок, если выстрел

был совершён с дальнего расстояния, может успеть смениь локацию.

Код:

Function update_shot()
        v#=0.1
        max_dist#=1000
        For a.shot=Each shot
        ;=
 If a\time=0 a\time=MilliSecs()
 new_time=MilliSecs()
 delta_t=new_time-a\time
 a\time=new_time
 vs#=v*delta_t
        ;=
 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
        bhandle=EntityName(bot_h)
        bc.bot=Object.bot(bhandle)
        bc\Survivability=bc\Survivability-16
 ;=
        PositionEntity bc\point,EntityX(user,1),EntityY(bc\point,1),EntityZ(user,1)
 ;=
        If bc\Survivability<=0
  Delete bc
  FreeEntity bot_h
  create_bot(EntityX(user)+Rnd(-100,100),2,EntityZ(user)+Rnd(-100,100))
        EndIf
 EndIf
        Next
End Function

Как видите - дописали ВСЕГО одну строчку,
Цитата:

PositionEntity bc\point,EntityX(user,1),EntityY(bc\point,1),Entit yZ(user,1)

но какой эффект =)
И ещё кое-что: пусть бот становится красным, если он "навёлся" на игрока.
Код:

Function update_bot()
        Rdist#=15
        v#=0.01
        For a.bot=Each bot
        ;=
 If a\time=0 a\time=MilliSecs()
 new_time=MilliSecs()
 delta_t=new_time-a\time
 a\time=new_time
        ;=
 If EntityDistance(user,a\entity)<Rdist#
        PointEntity a\entity,user
        EntityColor a\entity,255,0,0
 Else
        EntityColor a\entity,255,255,255
        If EntityDistance(a\entity,a\point)<2
  PositionEntity

a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
        EndIf
        PointEntity a\entity,a\point
 EndIf
        ;===========
 MoveEntity a\entity,0,0,v#*delta_t
 TranslateEntity user,0,-G#*delta_t,0
        Next
End Function


Guest 13.03.2006 17:42

Очень крутая статья все просто и ясно, лучше нигде не втречал, спасибо!

impersonalis 13.03.2006 18:34

Всегда пожалуйста. Будут вопросы - обращайтесь =)

impersonalis 20.07.2006 00:40

Re: Создаём свой FPS (first person shooter)
 
MANIAK_dobrii первёл данную работу на английский язык:
english-version

impersonalis 16.08.2006 15:15

Re: Создаём свой FPS (first person shooter)
 
Благодаря GoodWin (http://www.boolean.name/showthread.php?p=15571) нарыл баг в коде, который сказывается при использовании уровня с ра3личными высотами. Короче говоря, код создания выстрела должен быть такой:
Код:

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
        EntityType s\entity,SHOTT
        RotateEntity s\entity,pitch#,yaw#,roll#,1
        Return True
End Function

Для тех кто не понял:
команда позиционирования объекта
Код:

PositionEntity s\entity,x#,y#,z#,1
должна идти до того, как мы поставим ему тип коллизии:
Код:

EntityType s\entity,SHOTT
Иначе объект просто нельзя будет переместить в указанную точку.
Глюк обидный и вызван только моим недосмотром =(

TARAPUPENKO 17.08.2006 02:24

Re: Создаём свой FPS (first person shooter)
 
А как сделать здоровье персонажу и отнятие здоровья при прикосновении бота к игроку?

impersonalis 17.08.2006 03:11

Re: Создаём свой FPS (first person shooter)
 
Завтра (имеется в виду - т.н. "логическое завтра") отвечу - сегодня спать хочется.

GoodWin 17.08.2006 15:23

Re: Создаём свой FPS (first person shooter)
 
Цитата:

А как сделать здоровье персонажу и отнятие здоровья при прикосновении бота к игроку?
Вот попробуйте....

1) это моя тема
2) выложить просто переправленный аттач моджет каждый - для этого есть рубрики по 2д и 3д. ФАК подразумевает объяснения, тем более что
3)в коде много изменений без которых можно обойтись

imper

ладно, а так пойдет:
назначим еще одну переменную отвечающую за кол-во жизни у игрока
Global user, live
добавим в функцию создания игрока следующую строку
live=100
user=CreateSphere()
k#=3
ScaleEntity user,k#,k#,k#
теперь необходимо обработать прикосновение бота к игроку
изменим функцию
update_bot()
добавим следующие строки кода:
a\time=new_time
;=
If EntityCollided (a\entity,USERT); проверякм есть ли колизия между ботои и игроком
live=live-1; если есть то уменьшаем кол-во жизни
If live<=0; если кол-во жизни игрока 0 или меньше
FreeEntity user_h; удаляем игрока и снова его
create_user(0,100,0);создаем
EndIf
ElseIf

EntityDistance(user,a\entity)<Rdist#
PointEntity a\entity,user
Else
If EntityDistance(a\entity,a\point)<2
PositionEntity a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
EndIf
PointEntity a\entity,a\point
EndIf

красным новые строки которые необходимо добавить...

и конечно-же... идея реализации полность принадлежит Имперсоналису, за что ему огромное спасибо...
P.S. извини, что отнял у тебя возможность помочь людям

impersonalis 17.08.2006 20:33

Re: Создаём свой FPS (first person shooter)
 
Смертный герой
Сегодня прикрутим показатель жизни игроку.
Как всегда код будет максимально простым - чтобы показать прицип работы. Конечная реализация зависит от вас.
В глобал:
[highlight=blitzbasic]
Global user_H
[/highlight]
в функцию create_user(x#=0,y#=10,z#=0)
[highlight=blitzbasic]
user_H=100
[/highlight]
в MAIN LOOP:
[highlight=blitzbasic]
Text 10,40,"H="+user_H
[/highlight]
Теперь опишем систему нанесения урона пользователю.
В функции update_bot() пишем:
[highlight=blitzbasic]
Function update_bot()
Rdist#=15
v#=0.01
For a.bot=Each bot
;=
If a\time=0 a\time=MilliSecs()
new_time=MilliSecs()
delta_t=new_time-a\time
a\time=new_time
;=
If EntityDistance(user,a\entity)<Rdist#
PointEntity a\entity,user
EntityColor a\entity,255,0,0
Else
EntityColor a\entity,255,255,255
If EntityDistance(a\entity,a\point)<2
PositionEntity a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
EndIf
PointEntity a\entity,a\point
EndIf
;===========новое
player=EntityCollided(a\entity,USERT)
If player<>0
user_H=user_H-1
EndIf
;======конец нового
MoveEntity a\entity,0,0,v#*delta_t
TranslateEntity user,0,-G#*delta_t,0
Next
End Function
[/highlight]
Если бот столкнулся с объектом, у которого стоит тип коллизии USERT, то убавить игроку жизнь на единицу.
Запустите и убедитесь в недостаточности этой конструкции. Жизнь уменьшается при каждом вызове функции, т.е. если у вас 60 ФПС, то за секунду прикосновения к вам бота у вас онимется 60 единиц здоровья.
Приступим.
[highlight=blitzbasic]
Type bot
Field entity
Field time
Field Survivability
Field point
Field last_damage_time
End Type
[/highlight]
Здесь будем хранить время последнего "удара".
Подправим функцию обеновления бота:
[highlight=blitzbasic]
;===========
player=EntityCollided(a\entity,USERT)
If player<>0
user_H=user_H-1
Else
a\ last_damage_time=0
EndIf
;======
[/highlight]
и далее в блоке If player<>0
[highlight=blitzbasic]
If a\last_damage_time=-1
a\last_damage_time=MilliSecs()
EndIf
[/highlight]
Если мы фиксируем акт соприкосновения первый раз (так сказать "локально" - т.е. в прошлом обновлении коллизии не было, а перед этим соприкосновений могло быть лююбое кол-во), то сохраняем в поле время, прошедшее с начала соприкосновения (а далее - время, с последнего обновления события, влекующего сосприкосновение - т.е. время прошлого "удара"). Вообще говоря, факт коллизии будет зафиксирован при вызове UpdateWorld(), т.е. время, прошедешее с акта коллизии до обработки этого факта в функции обновления бота весьма мало. Но всё же, не "пренебрежимо мало", особенно если частота UpdateWorld и функций обновления бота сильно разняться.
Но для данного примера это не критично (в описанном выше случае надо или логику вызвать вместе с UpdateWorld или искать иные пути - зависит от конкретики реализации стабилизации и логики мира)
[highlight=blitzbasic]
If MilliSecs()-a\last_damage_time>1000
user_H=user_H-1
a\last_damage_time=MilliSecs()
EndIf
[/highlight]
Ну и как завершающий штрих - сделаем силу урона произвольной (из диапазона):
[highlight=blitzbasic]
Function update_bot()
Rdist#=15
v#=0.01
For a.bot=Each bot
;=
If a\time=0 a\time=MilliSecs()
new_time=MilliSecs()
delta_t=new_time-a\time
a\time=new_time
;=
If EntityDistance(user,a\entity)<Rdist#
PointEntity a\entity,user
EntityColor a\entity,255,0,0
Else
EntityColor a\entity,255,255,255
If EntityDistance(a\entity,a\point)<2
PositionEntity a\point,EntityX(a\point)+Rnd(-40,40),EntityY(a\point),EntityZ(a\point)+Rnd(-40,40)
EndIf
PointEntity a\entity,a\point
EndIf
;===========
player=EntityCollided(a\entity,USERT)
If player<>0

If a\last_damage_time=-1
a\last_damage_time=MilliSecs()
EndIf
If MilliSecs()-a\last_damage_time>1000
user_H=user_H-Rand(1,7)
a\last_damage_time=MilliSecs()
EndIf
Else
a\ last_damage_time=-1
EndIf
;======
MoveEntity a\entity,0,0,v#*delta_t
TranslateEntity user,0,-G#*delta_t,0
Next
End Function


[/highlight]

impersonalis 18.08.2006 03:08

Re: Создаём свой FPS (first person shooter)
 
Вложений: 2
Вот - код и все ресурсы к нему. В коде GoodWin (спс. за старание) я не нашёл временной паузы между нанесением поврежденй игроку - весьма обидное упущение. В моей заметке это есть :@
ATTENTION! Если вы скачивали сегодня уже этот архив, то перекачайте - в коде была допущена некритичная (но всё же!) неточность.

GoodWin 18.08.2006 10:29

Re: Создаём свой FPS (first person shooter)
 
Думаю следующий урок будет "научим Бота стрелять!"
всем это будет интересно и мне тоже....
ждемс....

Цитата:

В коде GoodWin (спс. за старание) я не нашёл временной паузы между нанесением поврежденй игроку - весьма обидное упущение
в вопросе
Цитата:

А как сделать здоровье персонажу и отнятие здоровья при прикосновении бота к игроку?
о необходимости временной паузы ни слова не было... хотя ты все равно прав...признаю...

impersonalis 19.08.2006 01:48

Re: Создаём свой FPS (first person shooter)
 
Боевая система
Сделаем несколько типов оружия. Модифицируем систему.
[highlight=blitzbasic]
Type shot
Field entity
Field dist#
Field time
Field class_id%;здесь будет хранится инфа о классе снаряда(патрона)
End Type
[/highlight]
Визуализация снаряда зависит от его класса
[highlight=blitzbasic]
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#,class%=1)
s.shot=New shot
s\class_id=class
Local shot_sprite_handle=shot_spriteS(s\class_id)
s\entity=CopyEntity(shot_sprite_handle)
PositionEntity s\entity,x#,y#,z#,1
EntityType s\entity,SHOTT
RotateEntity s\entity,pitch#,yaw#,roll#,1
Return True
End Function
[/highlight]
shot_spriteS - это будет наш массив с образцами спрайтов
[highlight=blitzbasic]
Global pricel=LoadImage("pricel.bmp")

Dim shot_spriteS(2);инициализация
For i=0 To 1;загрузка
shot_spriteS(i)=LoadSprite("sprite"+i+".bmp")
Next

Global orient_sprite=LoadSprite("orient.bmp")
[/highlight]
А вот это - нафик
[highlight=blitzbasic]
Function create_world()
light=CreateLight()
RotateEntity light,90,0,0

HideEntity shot_sprite; уже не катит :)
[/highlight]
Скрывать будем сразу после загрузки:
[highlight=blitzbasic]
For i=0 To 1
shot_spriteS(i)=LoadSprite("sprite"+i+".bmp")
HideEntity shot_spriteS(i)
Next
[/highlight]
Так теперь переименуйте файл со спрайтом выстрела в sprite0 и найдите ещё один (отличный от имеющегося) спрайт - назовите его sprite1.
Подправим функцию обновления игрока:
[highlight=blitzbasic]
If MouseHit(2) And MilliSecs()-last_shot_time>shot_delay
user_gun=FindChild(GUN,"END")
create_shot(EntityX(user_gun,1),EntityY(user_gun,1 ),EntityZ(user_gun,1),EntityPitch(camera),EntityYa w(user),0)
last_shot_time=MilliSecs()
EndIf
If MouseHit(1)
user_gun=FindChild(GUN,"END")
create_shot(EntityX(user_gun,1),EntityY(user_gun,1 ),EntityZ(user_gun,1),EntityPitch(camera),EntityYa w(user),0,1)

EndIf
[/highlight]
В зависимости от того что нажато (ЛКМ или ПКМ), производится выстрел из 1ого или 2ого оружия.
Уже можно псмотреть результаты работы.
Далее.
И вот тут начинаешь задумываться: у различного оружия - разлиные характеристики (глубокая мысль).
Надо как-то оценивать дальность стрельбы, урон, особенности траектории и прочее... Эх - создаём ещё один информационный тип:
[highlight=blitzbasic]
Type SHOT_TYPE
Field sprite
Field damage
Field max_dist
Field v#
End Type
[/highlight]
Самое мерзкое (так делать не надо!) описываем в коде характеристики оружия.
В реальных играх это должно хранится в конфигурационных файлах и загружаться специальной функцией.
[highlight=blitzbasic]
Dim shot_S.SHOT_TYPE(2)

For i=0 To 1
shot_S(i)=New SHOT_TYPE
Next

shot_S(0)\sprite=LoadSprite("sprite0.bmp")
HideEntity shot_S(0)\sprite
shot_S(0)\damage=95
shot_S(0)\max_dist=100
shot_S(0)\v=0.3

shot_S(1)\sprite=LoadSprite("sprite1.bmp")
HideEntity shot_S(1)\sprite
shot_S(1)\damage=10
shot_S(1)\max_dist=1000
shot_S(1)\v=0.1
[/highlight]
Характеристики зависят от конкретики игры ( можно хоть мат.дисперсию величины повреждения записать).
Не забудьте удалить старый код - с массивом под спрайты.
[highlight=blitzbasic]
Function create_Shot(x#,y#,z#,pitch#,yaw#,roll#,class%=1)
s.shot=New shot
s\class_id=class
s\entity=CopyEntity(shot_S(s\class_id)\sprite)
PositionEntity s\entity,x#,y#,z#,1
EntityType s\entity,SHOTT
RotateEntity s\entity,pitch#,yaw#,roll#,1
Return True
End Function
[/highlight]
ну и правим обновление снарядов:
[highlight=blitzbasic]
Function update_shot()

For a.shot=Each shot
;=
If a\time=0 a\time=MilliSecs()
new_time=MilliSecs()
delta_t=new_time-a\time
a\time=new_time
vs#=shot_S(a\class_id)\v*delta_t
;=
MoveEntity a\entity,0,0,vs#
a\dist#=a\dist#+vs#
Local copy_a_class_id=a\class_id

bot_h=EntityCollided(a\entity,BOTT)
If a\dist#>shot_S(a\class_id)\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
bhandle=EntityName(bot_h)
bc.bot=Object.bot(bhandle)
bc\Survivability=bc\Survivability-shot_S(copy_a_class_id)\damage
;=
PositionEntity bc\point,EntityX(user,1),EntityY(bc\point,1),Entit yZ(user,1)
;=
If bc\Survivability<=0
Delete bc
FreeEntity bot_h
create_bot(EntityX(user)+Rnd(-100,100),2,EntityZ(user)+Rnd(-100,100))
EndIf
EndIf
Next
End Function
[/highlight]
Запускаем - играем.
ГГ... Теперь даже тактика есть: заманить противника на себя из слабого быстроперезаряжаемого оружия а потом, вблизи, замочить из СуперПушки с одного залпа =)

impersonalis 19.08.2006 01:54

Re: Создаём свой FPS (first person shooter)
 
Вложений: 4
Я так смотрю - архив качают :-)
А значит мои коды не лишены смысла - это приятно.

В архиве - модифицированный код со всеми ресурсами B)

Тарас Шевченко 19.08.2006 14:57

Re: Создаём свой FPS (first person shooter)
 
Для полноценности надо сделать HUD.


Часовой пояс GMT +4, время: 21:53.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot