Game Maker - создание игр | HellRoom Games
Март 26, 2025, 00:09:33 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
Новости:
 
   Начало   Game Maker Помощь Правила форума Поиск Календарь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создания AI (шутера)  (Прочитано 6410 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ярик
Активный участник
*****

Репутация: 21
Offline Offline

Награды:
За постоянность! [10 дней на форуме]
API: GameMaker Studio 2
Сообщений: 396



« : Февраль 05, 2020, 13:33:39 »

В этом уроке мы сделаем маленький шутер с использованием ИИ
Создаем проект и объекты:
ObjPlayer для игры
ObjBot будет использоваться как враг
ObjBlock будет препятствием
ObjBullet1 пуля для игрока
ObjBullet2 пуля для бота
Сделайте им спрайты

Теперь создаем комнату
В настройках комнаты



В видах комнаты:


Переходим к игроку
В create  
Код:
Spd=4 //скорость ходьбы
TimeAttack=0 //таймер, нужен для стрельбы
SpdAtack=4 //скорость стрельбы
Hp=100 //жизни игрока

global.DistSound=300 //на какой дистанции будет слышен звук
global.Sound=false //воспроизведения звук
global.SoundX=0 //где был воспроизведен звук
global.SoundY=0 //где был воспроизведен звук

Alarm[0]  
Код:
global.Sound=0 //мы обнулим переменную

Step
Код:
view_xview[0]=(x-(view_wview/2)) //камера будет следовать за игроком по x
view_yview[0]=(y-(view_hview/2)) //камера будет следовать за игроком по y
image_angle=point_direction(x,y,mouse_x,mouse_y) //игрок будет поворачиваться за мышкой
if Hp<=0 {instance_destroy()} //если у игрока "жизни" упадут до 0 то игрок уничтожится
if mouse_check_button(mb_left) {
    TimeAttack+=1
    if TimeAttack>SpdAtack {
        global.Sound=1 //был воспроизведен звук
        global.SoundX=x //записываем в переменную для того что бы бот смог понять где был звук
        global.SoundY=y //тоже
        alarm[0]=15
        var bulet;
        bulet=instance_create(x+lengthdir_x(15,image_angle),y+lengthdir_y(15,image_angle),ObjBullet1) //создаем пулю
        with (bulet) {
            motion_set(point_direction(x,y,mouse_x,mouse_y),35)
            image_angle=direction
        }
        TimeAttack=0 //обнуляем переменную
    }
}

//теперь переходим к ходьбе
if keyboard_check(ord("W")) {
    if not place_meeting(x,y-(Spd+5),ObjBlock) {
        y-=Spd
    }
}else{
    if keyboard_check(ord("S")) {
        if not place_meeting(x,y+(Spd+5),ObjBlock) {
            y+=Spd
        }
    }
}
if keyboard_check(ord("A")) {
    if not place_meeting(x-(Spd+5),y,ObjBlock) {
        x-=Spd
        }
}else{
    if keyboard_check(ord("D")) {
        if not place_meeting(x+(Spd+5),y,ObjBlock) {
            x+=Spd
        }
    }
}

Переходим к боту
У него в Create  
Код:
Move = mp_grid_create(0,0,room_width/32,room_height/32,32,32);  //создаем сетку
mp_grid_add_instances(Move,ObjBlock,0);  //создаем путь
Path = path_add();  //добавляем в переменную путь
path_speed=3 //скорость ходьбы

ViewDist=600 //дальность обзора
Hp=100 //жизни

StepCol=0 //идти тогда когда не виден игрок
TimeBullet=0 //таймер
SpdAtack=7 //скорость атаки

Alarm[0]  
Код:
StepCol=1

Step  
Код:
if instance_number(ObjPlayer)=1 { //если игрок жив
if Hp<=0 { //если жизни меньше и ровны нулю
    instance_destroy() //уничтожаемся
}else{
    if Hp>20 and Hp<50 { //если жизни больше 20 и меньше 50
        path_speed=2 //уменьшаем скорость с 3 на 2
    }
}
if !collision_line(x,y,ObjPlayer.x,ObjPlayer.y,ObjBlock,0,1) { //проверяем "виден ли игрок"
    if distance_to_object(ObjPlayer)<ViewDist { //если он близко
        image_angle=ScrAngle(ObjPlayer.x,ObjPlayer.y) //поворачиваемся к нему
        alarm[0]=45
        TimeBullet+=1 //прибавляем к переменной значений 1 "это у нас секундомер"
        if TimeBullet>SpdAtack { //если у секундомера значение равна SpdAtack
            var bulet;
            bulet=instance_create(x+lengthdir_x(15,image_angle),y+lengthdir_y(15,image_angle),ObjBullet2) //создаем пулю
            with (bulet) {
                motion_set(point_direction(x,y,ObjPlayer.x,ObjPlayer.y),35)
                image_angle=direction
            }
            TimeBullet=0 //обнуляем таймер
        }
        if distance_to_object(ObjPlayer)>(ViewDist-200) { //если игрок в поле зрения но далеко
            mp_grid_path(Move,Path,x,y,ObjPlayer.x,ObjPlayer.y,1) //создаем путь
            path_start(Path,path_speed, 0, 0); //идем по пути
        }else{
            path_end() //мы дошли до нормальной дистанции "останавливаемся"
        }
    }
}else{
if global.Sound=1 { //если звук был воспроизведен
    if point_distance(x,y,global.SoundX,global.SoundY)<global.DistSound { //если можем услышать звук
        if path_get_length(Path)<800 { //если этот звук по пути доносился близко
            mp_grid_path(Move,Path,x,y,global.SoundX,global.SoundY,1) //создаем путь
            path_start(Path,path_speed, 0, 0); //идем по пути
        }
    }
}
if StepCol=1 {//если переменная StepCol ровна 1
    mp_grid_path(Move,Path,x,y,ObjPlayer.x,ObjPlayer.y,1) //создаем путь
    path_start(Path,path_speed, 0, 0); //идем по пути
    StepCol=0
}else{
    image_angle=direction //изменять переменную на direction (direction равен тому куда идет ИИ)
    }
}
}

В объекте ObjBullet1 ставим события
Столкновения с ObjBlock и в нем действие уничтожения
Вне комнаты и в нем действие уничтожения
Столкновения с ObjBot в событие код:
Код:
other.Hp-=20 //урон
instance_destroy()


В объекте ObjBullet2 ставим события
Столкновения   с ObjBlock и в нем действие уничтожения
Вне комнаты   и в нем действие уничтожения
Столкновения с ObjPlayer в событие код:
Код:
ObjPlayer.Hp-=10 //10 это урон
instance_destroy()

НЕ ЗАБЫВАЕМ СОЗДАТЬ СКРИПТ ScrAngle
Код:
var I;
I=point_direction(x,y,argument0,argument1)
return I;

Этот урок сделан на гм8 (не lite)

Маленький примерчик для гм8.1 скачать
« Последнее редактирование: Март 26, 2020, 14:08:35 от ярик » Записан

А че как 2 числа сравнить то это быстрее?
Вот так >? Вот так < ? Или лучше вот так sign(0)
SilentPhil
Norland
GM Pro user
*

Репутация: 479
Offline Offline

Пол: Мужской
Награды:
Первое место на HellRoom Jam #7 [Hell in Your Fridge]500 сообщений!За постоянность! [50 дней на форуме]За лояльность! [+150 репутации]Настоящий игродел!Второе место на HellRoom Jam #6 [По следам Артакса]...
API: GameMaker Studio 2
Деятельность: GML, Pixel Art
Сообщений: 1363



WWW
« Ответ #1 : Февраль 05, 2020, 17:47:31 »

Ярик, не нужно же пояснять, что твоя статья плоха?
Записан

         
Да, на них можно кликать.
Fur
Абы-какой
GM Pro user
*

Репутация: 463
Offline Offline

Пол: Мужской
Награды:
3000 сообщений!За постоянность! [500 дней на форуме]Третье место на HellRoom Jam #9 [Flucoldache]За лояльность! [+300 репутации]Настоящий игродел!Боже мой, посмотрите на эту медальку! Первое место на HellRoom Jam #6
API: Game Maker 8.0 Lite
Деятельность: Бурная.
Сообщений: 3673


Лисяток тебе.


« Ответ #2 : Февраль 05, 2020, 18:20:31 »

Код:
//здесь наверно говнокод

Вся статья в трёх словах.

Цитировать
Нам надо создать стену,игрока и бота
Стена-ObjBlock
Игрок-ObjPlayer
Бот-ObjBot
И нарисуйте им спрайты.

После этого создадим комнату
В настройках комнаты ширина-1280, высота-640, скорость-60

В видах:
Использования видов-true
Видимый при старте-true
Вид в комнате к примеру ширина 1280, высота 640
Расположения на экране к примеру ширина 1280, высота 640

И после расставим в комнате блоки,игрока,бота
Да, ведь именно это я и хочу узнать в уроке про ИИ. Сетап комнаты.

Код:
Path_speed=2
Что за упоротый стиль именования переменных?

Код:
if distance_to_object(ObjPlayer)<600
Что за волшебные числа?

Код:
if mouse_check_button(mb_left)
Какого чёрта ввод игрока забыл в коде ИИ?

Код:
}else{
Клешни отрубить за такую ересь. C# кодстайл наше всё.

Как ИИ этот смех даже расценивать не стоит. Какое-то захардкоженное месиво без стейт машин. Завязывай уже. Хочешь помогать -- помоги себе сам для начала, и научись кодить.

Записан

В одной отдельно взятой фразе не должно быть больше миллиона муравьёв, пусть даже она — научного труда о муравьях.

Hyperflex
ярик
Активный участник
*****

Репутация: 21
Offline Offline

Награды:
За постоянность! [10 дней на форуме]
API: GameMaker Studio 2
Сообщений: 396



« Ответ #3 : Февраль 05, 2020, 19:36:08 »

SilentPhil, Конечно плоха


Цитировать
Path_speed=2
Что за упоротый стиль именования переменных?
Это не мой стиль это стиль гм

<Справка>
Цитировать
path_speed Скорость (пикселей за шаг), с которым будет следовать экземпляр. Используйте отрицательную скорость для обратного перемещения.

Цитировать
Какого чёрта ввод игрока забыл в коде ИИ?
Мне надо было в игроке этот код писать? ))

Цитировать
Что за волшебные числа?
Если что эти числа из страны ос.

Цитировать
Клешни отрубить за такую ересь. C# кодстайл наше всё.
Я не учил C# но звучит интересно

Цитировать
Хочешь помогать -- помоги себе сам для начала, и научись кодить.
Главное бот работает )
Записан

А че как 2 числа сравнить то это быстрее?
Вот так >? Вот так < ? Или лучше вот так sign(0)
SilentPhil
Norland
GM Pro user
*

Репутация: 479
Offline Offline

Пол: Мужской
Награды:
Первое место на HellRoom Jam #7 [Hell in Your Fridge]500 сообщений!За постоянность! [50 дней на форуме]За лояльность! [+150 репутации]Настоящий игродел!Второе место на HellRoom Jam #6 [По следам Артакса]...
API: GameMaker Studio 2
Деятельность: GML, Pixel Art
Сообщений: 1363



WWW
« Ответ #4 : Февраль 05, 2020, 20:02:26 »

Цитировать
Клешни отрубить за такую ересь. C# кодстайл наше всё.
Ну это уже ксенофобия, а не объективная критика ; )
Хотя пробелы между else и скобками я бы добавил.

К слову, чтобы мое первое сообщение не расценивалось как пассивная агрессия, добавлю немного полезной информации.

Стейт-машины - это круто и молодежно, особенно в создании ИИ. Смотри, как просто:
Заводим enum с состояниями нашего агента:
Код:
enum ENEMY_AI_STATES {
   IDLE,                // Агент в состоянии покоя - может ходить бесцельно ходить/бродить или еще что-нибудь делать
   MOVING_TO_TARGET,    // Агент пытается сократить дистанцию до цели чтобы начать стрельбу
   SHOOTING_AT_TARGET,  // Агент стреляет по цели пока позволяет дистанция
   TARGET_SEARCH,       // Агент идет туда, где в последний раз видел игрока
   RETREAT              // Агент пытается отступить
}
Переменную, в которой будет содержаться текущее состояние агента:
Код:
ai_state = ENEMY_AI_STATES.IDLE;
В событии шага врага теперь нужно обработать состояния стейт-машины и определить условия перехода между состояниями:
Код:
switch (ai_state) {
   case ENEMY_AI_STATES.IDLE:
        if (distance_to_target(player) < ENEMY_AI_VISIBILITY_DISTANCE) {
            ai_state = ENEMY_AI_STATES.MOVING_TO_TARGET;
            break;
        }
        // КОД СЛУЧАЙНОЙ ХОДЬБЫ
    break;

    case ENEMY_AI_STATES.MOVING_TO_TARGET:
        if (hp <= ENEMY_AI_RETREAT_HP_THRESHOLD) {
            ai_state = ENEMY_AI_STATES.RETREAT;
            break;
        } else if (distance_to_target(player) < ENEMY_AI_FIRE_DISTANCE) {
            ai_state = ENEMY_AI_STATES.SHOOTING_AT_TARGET;
            break;
        } else if (distance_to_target(player) > ENEMY_AI_VISIBILITY_DISTANCE) {
            ai_state = ENEMY_AI_STATES.TARGET_SEARCH;
            // ЗАПОМИНАЕМ КООРДИНАТЫ ИГРОКА - ЗДЕСЬ МЫ ВИДЕЛИ ЕГО В ПОСЛЕДНИЙ РАЗ
            break;
        }
        // КОД ДВИЖЕНИЯ К ЦЕЛИ
    break;

    case ENEMY_AI_STATES.SHOOTING_AT_TARGET:
        if (hp <= ENEMY_AI_RETREAT_HP_THRESHOLD) {
            ai_state = ENEMY_AI_STATES.RETREAT;
            break;
        } else if (distance_to_target(player) > ENEMY_AI_FIRE_DISTANCE) {
            ai_state = ENEMY_AI_STATES.SHOOTING_AT_TARGET;
            break;
        }
        // КОД СТРЕЛЬБЫ ПО ЦЕЛИ
    break;

    case ENEMY_AI_STATES.TARGET_SEARCH:

        if (distance_to_target(player_last_position) < NEAR_DISTANCE) {
            ai_state = ENEMY_AI_STATES.IDLE;
            // ДОШЛИ ДО ПОСЛЕДНИЙ КООРДИНАТ ИГРОКА, МОЖНО ВЕРНУТЬСЯ К БЕЗДЕЛЬЮ
            break;
        } else if (distance_to_target(player) < ENEMY_AI_VISIBILITY_DISTANCE) {
            ai_state = ENEMY_AI_STATES.MOVING_TO_TARGET;
            break;
        }
        // КОД ДВИЖЕНИЯ К ПОСЛЕДНИМ ЗАПОМНЕННЫМ КООРДИНАТАМ ИГРОКА
    break;

    case ENEMY_AI_STATES.RETREAT:
        if (hp > ENEMY_AI_RETREAT_HP_THRESHOLD) {
            ai_state = ENEMY_AI_STATES.IDLE;
            break;
        }
        // КОД ДВИЖЕНИЯ К БЛИЖАЙШЕЙ АПТЕЧКЕ
    break;
}

Это самая простейшая стейт-машина, но она куда понятнее, гибче и проще в поддержке и расширении, чем код из твоей статьи.

Цитировать
Цитировать
Цитировать
Что за волшебные числа?
Если что эти числа из страны ос.
Волшебные числа - это фразеологизм, обозначающий числа в коде, которые непонятно откуда взялись и что означают в отрыве от участка кода, в котором они расположены.
Спроси тебя через неделю, что означает 300 - сложно будет ответить.
А если вместо 300 будет написано ENEMY_AI_VISIBILITY_DISTANCE (это может быть макрос или переменная), то сразу понятно, что это дистанция видимости вражеского ИИ.

Добавлено: Февраль 05, 2020, 20:07:40
Цитировать
Цитировать
Какого чёрта ввод игрока забыл в коде ИИ?
Мне надо было в игроке этот код писать? ))

В таком случае нужно сделать какую-нибудь систему событий. Кто-то будет генерировать события, а кто-то их считывать. Можно, например, почитать про паттерн publisher-subscriber, но можно как-нибудь проще сделать.
Выстрел игрока должен генерировать событие звука в определенной позиции с определенной силой.
Враг должен быть подписан на события звуков и получив такое события, проверив до него расстояние (с учетом силы произведенного звука), уже среагировать.

Таким образом разделяются две разные сущности - управление игроком и реакция ИИ.
И становится возможным легкая реализация реакции ИИ на звук шагов, ударов по предметам, брошенным монеткам и т.д.
« Последнее редактирование: Февраль 05, 2020, 20:08:39 от SilentPhil » Записан

         
Да, на них можно кликать.
ярик
Активный участник
*****

Репутация: 21
Offline Offline

Награды:
За постоянность! [10 дней на форуме]
API: GameMaker Studio 2
Сообщений: 396



« Ответ #5 : Февраль 05, 2020, 20:08:48 »

А теперь я понял что такое волшебные числа, я написал волшебные числа из за того что лень было написать переменную, так то у меня в исходнике заместо волшебных чисел есть переменные.
Люди вы знали что я работаю на гм а не на гмс
И то я забыл про функцию switch, ща изменю мои говнокоды
Записан

А че как 2 числа сравнить то это быстрее?
Вот так >? Вот так < ? Или лучше вот так sign(0)
SilentPhil
Norland
GM Pro user
*

Репутация: 479
Offline Offline

Пол: Мужской
Награды:
Первое место на HellRoom Jam #7 [Hell in Your Fridge]500 сообщений!За постоянность! [50 дней на форуме]За лояльность! [+150 репутации]Настоящий игродел!Второе место на HellRoom Jam #6 [По следам Артакса]...
API: GameMaker Studio 2
Деятельность: GML, Pixel Art
Сообщений: 1363



WWW
« Ответ #6 : Февраль 05, 2020, 20:14:00 »

А теперь я понял что такое волшебные числа, я написал волшебные числа из за того что лень было написать переменную, так то у меня в исходнике заместо волшебных чисел есть переменные.
Люди вы знали что я работаю на гм а не на гмс
И то я забыл про функцию switch, ща изменю мои говнокоды

ГМ устарел чуть более, чем полностью.

В таком случае вместо enum можно использовать переменные
Код:
ENEMY_AI_STATES_IDLE = 0;
ENEMY_AI_STATES_MOVING_TO_TARGET = 1;
и т.д.

Но лучше перейти на что-то более свежее, где есть enum'ы, макросы внутри кода и др.
Записан

         
Да, на них можно кликать.
ярик
Активный участник
*****

Репутация: 21
Offline Offline

Награды:
За постоянность! [10 дней на форуме]
API: GameMaker Studio 2
Сообщений: 396



« Ответ #7 : Февраль 05, 2020, 20:17:53 »

Денек нет для покупки гмс
Записан

А че как 2 числа сравнить то это быстрее?
Вот так >? Вот так < ? Или лучше вот так sign(0)
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

HellRoom Games © 2006-2012 All Rights Reserved
Powered by SMF 1.1.21 | SMF © 2013, Simple Machines
Страница сгенерирована за 0.102 секунд. Запросов: 28.