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

  • Официальное уведомление администрации CustomGames.RU
    В связи с масштабным техническим сбоем в инфраструктуре прежнего хостинг-провайдера (Beget), работа форума CustomGames.RU была оперативно перенесена на новую серверную площадку и развёрнута из резервной копии базы данных.

    • Безопасность данных: учётные записи и данные пользователей находятся в полной безопасности. Все пароли и защищаемые параметры хранятся исключительно в криптографически зашифрованном (хэшированном) виде — никаких критических инцидентов для аккаунтов пользователей не произошло.
    • Временные технические ограничения: на этапе синхронизации файлового хранилища часть статических материалов (пользовательские аватары и архивные вложения) временно недоступна. По мере получения доступа к файловым архивам все материалы будут восстановлены в полном объёме.

EndBringer

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

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

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

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

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

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

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

P.S. Я джва года хочу такую игру.
Какое такое плохое зло я тебе сделал....
Ты утрируешь, причём очень сильно. Я понимаю твой посыл, но можно было либо задать уточняющие вопросы, в том случае если ты зашёл ответить с целью помочь/подсказать а не порофлить, либо написать чтобы какие - то пункты я расписал подробнее.
Да и в целом не понимаю в чём смысл отвечать с целью порофлить, ты же не хотел меня как - то задеть или типа того, ты просто пошёл скопипастил текст чела. Ради чего?) Мой вопрос не решился, и я уверен что ты сейчас не лежишь на полу от смеха со своего ответа. Никто из нас не получил то что хотел
 
берешь цикл в цикле.
в нём кол-во волн и кол во крипов в волне
также таблицу с модифаерами, из которой будешь выбирать рандомом и аплаить.
в жс отправляешь название крипа и модифаера, там локализуешь, меняешь юнита в сцене и всё такое.
добавить сюда ещё таймер который выводится в дотовское время через хак например, или ещё панельку добавить.
за то время что ты тут пишешь поэмы можно половину как минимум сделать было
 
берешь цикл в цикле.
в нём кол-во волн и кол во крипов в волне
также таблицу с модифаерами, из которой будешь выбирать рандомом и аплаить.
в жс отправляешь название крипа и модифаера, там локализуешь, меняешь юнита в сцене и всё такое.
добавить сюда ещё таймер который выводится в дотовское время через хак например, или ещё панельку добавить.
за то время что ты тут пишешь поэмы можно половину как минимум сделать было
Большое спасибо, ну половину бы я точно не сделал, ибо максимум что я с "кодом" в кастомках делал это вставлял ключи в локализацию и соответственно писал её.
 
Поскольку у тебя она будет уникальной (и наверняка требовать таймер для волн или слушатель убийств), нужно создать отдельный объект (назовём его менеджером волн).
Какие свойства у него будут? Что он должен делать?
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
Поскольку у тебя она будет уникальной (и наверняка требовать таймер для волн или слушатель убийств), нужно создать отдельный объект (назовём его менеджером волн).
Какие свойства у него будут? Что он должен делать?
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
Там у меня правда код с ошибками был.. Щас подправил, какие увидел, да и доработать его надо, чтобы он был полностью работоспособным.
 
  • Нравится
Реакции: EndBringer
Реклама: