Tower Defense и система спавна волн крипов по раундам.

EndBringer

Самый "везучий" кастомкодел
17 Мар 2019
70
16
steamcommunity.com
Привет всем умельцам, хотелось бы услышать ваши мнения, алгоритмы или предложения как можно осуществить систему, которую я распишу чуть ниже:
Итак, система. Каждый раунд выходит волна крипов, причём выходит не строго заготовленная волна для раунда с номером N, а абсолютно рандомная (скорее всего из списка), при этом волна может получить какие либо особенности, к примеру: Крипов выходит в 2 раза больше, при этом они слабее чем обычно; получают антимагию; получают физимун; получают скорость передвижения (короче модифаеры как я понял).

ПРИ ЭТОМ! В интерфейсе написаны волны на 6 раундов вперед, то бишь рандом или типа того просчитал случайные вариации моделек, дал им случайный тип брони, возможно дал случайный модифаер и т.п. и вывел это в нужное место для того чтобы игроки хоть как - то могли планировать своё строительство, исходя из того какие волны будут дальше.

Комменты по типу "да лол, чё там делать" не принимаются :D
Интересует именно правильность построения процесса, с чего начать и чем закончить, почему именно так.
Возможно у кого то есть кусочки кода которые не жалко будет подбросить бомжику (мне)

p.s. хотелось бы в идеале чтобы система оставалась гибкая и имела как можно больше настроек и путей кастомизации
+ Спасибо всем кто ответит, а за более подробные описания с приведением примеров, скринов или других облегчающих понимание информации вещей - приглашаю за ширму, желательно в ногом виде)
 

ZLOY

Администратор
Команда форума
27 Июн 2016
953
182
Здраствуйте. Я, Кирилл. Хотел бы чтобы вы сделали игру, 3Д-экшон суть такова... Пользователь может играть лесными эльфами, охраной дворца и злодеем. И если пользователь играет эльфами то эльфы в лесу, домики деревяные набигают солдаты дворца и злодеи. Можно грабить корованы... И эльфу раз лесные то сделать так что там густой лес... А движок можно поставить так что вдали деревья картинкой, когда подходиш они преобразовываются в 3-хмерные деревья[1]. Можно покупать и т.п. возможности как в Daggerfall. И враги 3-хмерные тоже, и труп тоже 3д. Можно прыгать и т.п. Если играть за охрану дворца то надо слушаться командира, и защищать дворец от злого (имя я не придумал) и шпионов, партизанов эльфов, и ходит на набеги на когото из этих (эльфов, злого…). Ну а если за злого… то значит шпионы или партизаны эльфов иногда нападают, пользователь сам себе командир может делать что сам захочет прикажет своим войскам с ним самим напасть на дворец и пойдет в атаку. Всего в игре 4 зоны. Т.е. карта и на ней есть 4 зоны, 1 - зона людей (нейтрал), 2- зона императора (где дворец), 3-зона эльфов, 4 - зона злого… (в горах, там есть старый форт…)

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

P.S. Я джва года хочу такую игру.
 

EndBringer

Самый "везучий" кастомкодел
17 Мар 2019
70
16
steamcommunity.com
Здраствуйте. Я, Кирилл. Хотел бы чтобы вы сделали игру, 3Д-экшон суть такова... Пользователь может играть лесными эльфами, охраной дворца и злодеем. И если пользователь играет эльфами то эльфы в лесу, домики деревяные набигают солдаты дворца и злодеи. Можно грабить корованы... И эльфу раз лесные то сделать так что там густой лес... А движок можно поставить так что вдали деревья картинкой, когда подходиш они преобразовываются в 3-хмерные деревья[1]. Можно покупать и т.п. возможности как в Daggerfall. И враги 3-хмерные тоже, и труп тоже 3д. Можно прыгать и т.п. Если играть за охрану дворца то надо слушаться командира, и защищать дворец от злого (имя я не придумал) и шпионов, партизанов эльфов, и ходит на набеги на когото из этих (эльфов, злого…). Ну а если за злого… то значит шпионы или партизаны эльфов иногда нападают, пользователь сам себе командир может делать что сам захочет прикажет своим войскам с ним самим напасть на дворец и пойдет в атаку. Всего в игре 4 зоны. Т.е. карта и на ней есть 4 зоны, 1 - зона людей (нейтрал), 2- зона императора (где дворец), 3-зона эльфов, 4 - зона злого… (в горах, там есть старый форт…)

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

P.S. Я джва года хочу такую игру.
Какое такое плохое зло я тебе сделал....
Ты утрируешь, причём очень сильно. Я понимаю твой посыл, но можно было либо задать уточняющие вопросы, в том случае если ты зашёл ответить с целью помочь/подсказать а не порофлить, либо написать чтобы какие - то пункты я расписал подробнее.
Да и в целом не понимаю в чём смысл отвечать с целью порофлить, ты же не хотел меня как - то задеть или типа того, ты просто пошёл скопипастил текст чела. Ради чего?) Мой вопрос не решился, и я уверен что ты сейчас не лежишь на полу от смеха со своего ответа. Никто из нас не получил то что хотел
 

Дикий Пёс

Друзья CG
28 Июн 2017
411
96
Проект
Petri Reborn
берешь цикл в цикле.
в нём кол-во волн и кол во крипов в волне
также таблицу с модифаерами, из которой будешь выбирать рандомом и аплаить.
в жс отправляешь название крипа и модифаера, там локализуешь, меняешь юнита в сцене и всё такое.
добавить сюда ещё таймер который выводится в дотовское время через хак например, или ещё панельку добавить.
за то время что ты тут пишешь поэмы можно половину как минимум сделать было
 

EndBringer

Самый "везучий" кастомкодел
17 Мар 2019
70
16
steamcommunity.com
берешь цикл в цикле.
в нём кол-во волн и кол во крипов в волне
также таблицу с модифаерами, из которой будешь выбирать рандомом и аплаить.
в жс отправляешь название крипа и модифаера, там локализуешь, меняешь юнита в сцене и всё такое.
добавить сюда ещё таймер который выводится в дотовское время через хак например, или ещё панельку добавить.
за то время что ты тут пишешь поэмы можно половину как минимум сделать было
Большое спасибо, ну половину бы я точно не сделал, ибо максимум что я с "кодом" в кастомках делал это вставлял ключи в локализацию и соответственно писал её.
 

Zachary Greenburg

Пользователь
18 Июл 2020
41
14
Поскольку у тебя она будет уникальной (и наверняка требовать таймер для волн или слушатель убийств), нужно создать отдельный объект (назовём его менеджером волн).
Какие свойства у него будут? Что он должен делать?
1. Ну, 100% это должен быть тейбл.
2. Он должен хранить какие-то данные. А какие?
Из того, что я посмотрел, мне сразу подумалось туда запихнуть:
  • Тейбл очереди с волнами (элементы - таблицы с данными волн)
  • Данные текущей волны
3. Он должен чё-то делать. А чё?
Ну во-первых он должен эту очередь создавать.
Для этого для удобства парсим через LoadKeyValues(filename) в локальную переменную наш файл с волнами. Делаем метод для создания одного элемента очереди с примерным алгоритмом:
  • Выбрали рандомное объявление волны из переменной
  • Копируем его глубоким копированием, чтобы в последствии не затронуть исходные данные (исходники deepcopy есть в файлах Лабининта Аганима в utility_functions.lua)
  • Пихаем в конец очереди
Типо так:
Lua:
local WaveDefs = LoadKeyValues()

function Manager:AddWave()
    local rand = <какой-то код для рандомизации rand, идентификатора волны>
    rand = deepcopy(WaveDefs[rand]) -- копируем её данные
    table.insert(Manager.queue, rand) -- вставляем в очередь
end
В самом же объявлении волны учти следующее:
  • Есть (де)баффы для всей волны? Да - делаем для них таблицу.
  • Обязательно делаем в элементе таблицу, куда занесём данные для каждого моба отдельно (так, например, можно будет дать ограм доп. сопротивление эффектам на волне, а каким-то троллям - хасту; можно будет контролировать макс. кол-во каждого моба волны по-отдельности, приоритет их спавна и другие печеньки)
То есть чё-то такого плана:
KV:
"9l_BOJlHA_BCEM_XAHA"
{
    "boosters"
    {
        "modifiers"
        {
            "01" "modifier_haste"
            ...
        }
    }
    "units_data"
    {
        "npc_dwakon_gorinych"
        {
            "max_count" "10"
            "modifiers"
            {
                "01" "magic_immunity"
                ...
            }
        }
        ...
    }
}
Ещё он должен её чистить.

Теперь, когда у тебя есть очередь, ты можешь легко её отсылать на клиент через CustomNetTables каждый раз, когда ты её меняешь.

Процесс вызова волны - самое интересное!
Пускай у нас будет метод Manager:StartNext(wave). Он создаёт таблицу-трекер уже созданных мобов и таймер, который через определённые промежутки создаёт мобов и заносит их в неё. Здесь очень пригодится "замыкание". Типо так:
Код:
function Manager:StartNext(wave)
    local tracker = {}
    Timers:CreateTimer(wave.interval, function()
        -- замыкание работает на аргументы функции
        for unit_name, unit_info in pairs(wave.units_list) do
            if #tracker[unit_name] < unit_info.max_spawns then -- здесь замыкание
                -- можно добавить цикл для спавна мобов группами или добавить баффов/вещей
                local mob = CreateUnitByName()
                --[[
                И здесь замыкание: мы заносим именно в ту таблицу, которая была объявлена для процесса спавна именно этой волны.
                Даже если вызвать Manager:StartNext(wave) ещё раз, то мы будем ссылаться на всё ту же, нужную нам таблицу, а не ту, которая будет уже для другой волны.
                ]]
                table.insert(tracker[unit_name], mob)
                return wave.interval -- замыкание
            end
        end
    end)
end
При большом желании можно даже стартовать сразу несколько волн.

Как можно определять, спавнить ли волну:
1) В глобальном таймере (тот же самый MyAddon:OnThink()) пытаться стартануть следующую волну из очереди через условный метод Manager:TryStartNext(), который будет проверять, заспавнились ли все мобы в нужном количестве и - при желании - убиты ли они все?
2) Либо поставить слушатель на убийства, который будет делать то же самое.
Я обычно делаю первым способом. Даже интервалы в 5 секунд не особо заметны.
 
Последнее редактирование:
  • Влюблен
Реакции: EndBringer

EndBringer

Самый "везучий" кастомкодел
17 Мар 2019
70
16
steamcommunity.com
Поскольку у тебя она будет уникальной (и наверняка требовать таймер для волн или слушатель убийств), нужно создать отдельный объект (назовём его менеджером волн).
Какие свойства у него будут? Что он должен делать?
1. Ну, 100% это должен быть тейбл.
2. Он должен хранить какие-то данные. А какие?
Из того, что я посмотрел, мне сразу подумалось туда запихнуть:
  • Тейбл очереди с волнами (элементы - таблицы с данными волн)
  • Данные текущей волны
3. Он должен чё-то делать. А чё?
Ну во-первых он должен эту очередь создавать.
Для этого для удобства парсим через LoadKeyValues(filename) в локальную переменную наш файл с волнами. Делаем метод для создания одного элемента очереди с примерным алгоритмом:
  • Выбрали рандомное объявление волны из переменной
  • Копируем его глубоким копированием, чтобы в последствии не затронуть исходные данные (исходники deepcopy есть в файлах Лабининта Аганима в utility_functions.lua)
  • Пихаем в конец очереди
Типо так:
Lua:
local WaveDefs = LoadKeyValues()

function Manager:AddWave()
    local rand = <какой-то код для рандомизации rand, идентификатора волны>
    rand = deepcopy(WaveDefs[rand]) -- копируем её данные
    table.insert(Manager.queue, rand) -- вставляем в очередь
end
В самом же объявлении волны учти следующее:
  • Есть (де)баффы для всей волны? Да - делаем для них таблицу.
  • Обязательно делаем в элементе таблицу, куда занесём данные для каждого моба отдельно (так, например, можно будет дать ограм доп. сопротивление эффектам на волне, а каким-то троллям - хасту; можно будет контролировать макс. кол-во каждого моба волны по-отдельности, приоритет их спавна и другие печеньки)
То есть чё-то такого плана:
KV:
"9l_BOJlHA_BCEM_XAHA"
{
    "boosters"
    {
        "modifiers"
        {
            "01" "modifier_haste"
            ...
        }
    }
    "units_data"
    {
        "npc_dwakon_gorinych"
        {
            "max_count" "10"
            "modifiers"
            {
                "01" "magic_immunity"
                ...
            }
        }
        ...
    }
}
Ещё он должен её чистить.

Теперь, когда у тебя есть очередь, ты можешь легко её отсылать на клиент через CustomNetTables каждый раз, когда ты её меняешь.

Процесс вызова волны - самое интересное!
Пускай у нас будет метод Manager:StartNext(wave). Он создаёт таблицу-трекер уже созданных мобов и таймер, который через определённые промежутки создаёт мобов и заносит их в неё. Здесь очень пригодится "замыкание". Типо так:
Код:
function Manager:StartNext(wave)
    local tracker = {}
    Timers:CreateTimer(wave.interval, function()
        -- замыкание работает на аргументы функции
        for unit_name, unit_info in pairs(wave.units_list) do
            if #tracker[unit_name] < unit.max_spawns then -- здесь замыкание
                -- можно добавить цикл для спавна мобов группами или добавить баффов/вещей
                local mob = CreateUnitByName()
                --[[
                И здесь замыкание: мы заносим именно в ту таблицу, которая была объявлена для процесса спавна именно этой волны.
                Даже если вызвать Manager:StartNext(wave) ещё раз, то мы будем ссылаться на всё ту же, нужную нам таблицу, а не ту, которая будет уже для другой волны.
                ]]
                table.insert(tracker[unit_name], mob)
                return wave.interval -- замыкание
            end
        end
    end)
end
При большом желании можно даже стартовать сразу несколько волн.

Как можно определять, спавнить ли волну:
1) В глобальном таймере (тот же самый MyAddon:OnThink()) пытаться стартануть следующую волну из очереди через условный метод Manager:TryStartNext(), который будет проверять, заспавнились ли все мобы в нужном количестве и - при желании - убиты ли они все?
2) Либо поставить слушатель на убийства, который будет делать то же самое.
Я обычно делаю первым способом. Даже интервалы в 5 секунд не особо заметны.
Спасибо большое (づ。◕‿‿◕。)づ
 
  • Нравится
Реакции: Zachary Greenburg

vulkantsk

Супермодератор
Команда форума
21 Июн 2017
1,137
195
www.dotabuff.com
Проект
Roshan defense

Zachary Greenburg

Пользователь
18 Июл 2020
41
14
Там у меня правда код с ошибками был.. Щас подправил, какие увидел, да и доработать его надо, чтобы он был полностью работоспособным.
 
  • Нравится
Реакции: EndBringer
Реклама: