Пушистый, если воскрешение или гальванизацию не используешь, то не-героев можешь смело вычёркивать в момент смерти, а не момент разложения, фактической разницы для твоих целей не будет никакой.
Дарин, это была отсылка к "Kung Fury", который оказался весьма успешен не в последнюю очередь из-за крайне гиперболизированых абсурдных моментов, как, например, ЛАЗЕРАПТОРЫ.
А тебе я бы посоветовал в первую очередь подумать над приятной геометрией уровней или, если так хочется лабиринтов, над реализацией карты.
Пушистый, у тебя в карте используется воскрешение или гальванизация?
Алсо количество объектов считают так: объект появился - добавили +1 к счётчику, объект умер - вычли -1 из счётчика, а не странными костылями.
Тем не менее, не вижу ощутимого преимущества в решении через цикл, там растёт стак вызовов, здесь (офк не в wc, а в целом) растёт потребление памяти.
многие люди в качестве примера того что такое рекурсия
TBH, никогда не читал статей или примеров про рекурсию. Мне интересна алгоритмика (и то меньше, чем архитектура ПО), но специальность у меня совершенно не "программист", хоть джун, хоть не джун.
Предлагаю завершать офтоп, вечером в блоге закину другой пример, аж интересно.
То есть сам список как объект не обязательно описывать, ИМО. Вообще, я не вполне уверен в теме, так что буду рад исправлениям и пояснениям, если они уместны. Код на JASS, но логика вполне понятна и отлично переносится в цпп. Трахаться с указателями по памяти влом, нет IDE под рукой.
Разумеется, можно запариться и сделать через цикл, но это будет довольно-таки перегруженный и тяжело воспринимаемый код, как по мне.
Разумеется, да, только далеко не всегда целесообразно так делать. DracoL1ch:
Ну вот из псевдокода по IsUnitInGroup
Так лол, сишные компиляторы всегда переводят хвостовую рекурсию в плоскую итерацию, ЕМНИП.
Минут через несколько вкину пример, в котором, на мой взгляд, применение рекурсии весьма оправдано. Время программиста всегда дороже времени процессора \о/
Очевидное преимущество в том, что юнита можно заменить на что угодно и оно будет работать как надо. Кроме того, если стак обрабатывается таймером с высоким периодом, то массив будет показывать себя заметно лучше в плане быстродействия, пруф, бенчмарк.
Если группа - это связанный список, то "под капотом" почти всех функций из Groups API используются рекурсивные алгоритмы, и чем больше в группе юнитов, тем медленнее они работают.
А код из статьи Скорпа можно было оставить и без подобной переработки.
Можно добавить, что использование кейворда return допустимо также в функциях, которые ничего не возвращают, при таком использовании исполнение функции будет прервано при достижении строки с return. Как правило, используется совместно с условным оператором в теле цикла.
Во-первых, существует GetSpellTargetX() и GetSpellTargetY(), а во-вторых, не пользуйтесь точками.
В памяти игры существует пресозданная таблица локейшнов, используемый для реализации поиска пути и ещё каких-нибудь сервисных нужд, и подавляющее число нативных функций, которые возвращают location, не создают эту самую локацию из воздуха, а делают копию локейшна из таблицы. Реальный алгоритм того, какую именно локацию получаешь на выходе скрыт, технически его можно выяснить, но для практических нужд это не имеет смысла.
Теория такова: при открытии меню квестов в одиночной игре происходит пауза игры, которая может и вызывать лаг. При первой паузе алгоритм хешируется и дальнейших лагов не вызывает, чем и объясняется описанное поведение. В сетевой же игре пауза, очевидно, не ставится.
Немного позанимался вычиткой без особого пристрастия, результаты ниже. Обращал внимание только на фактические ошибки, неоднозначные формулировки и некоторые стилистические моменты, грамотность не вычитывал.
Про статью определённо могу сказать, что как минимум подход к написанию более, чем достойный. Из персонального фидбэка могу назвать только лирические вставки не по теме (например, про "такой подход - путь к деградации") со ссылками лурк-стайл (в таблице далее - ещё и многократно повторяющиеся), что не очень вяжется с претенциозностью (в самом лучшем смысле) остальной статьи. Кстати, в этой таблице посредством приведения аналогов из Си прямо указано, чем по факту являются типы.
Собственно, фидбэк
WarCraft III написан на языке программирования С - это язык низкого уровня.
Си - это всё-таки язык высокого уровня, если придерживаться строгой классификации. На нём действительно можно писать на низком уровне абстракции, но, тем не менее, Си был создан как компилируемый язык, что по факту исключает возможность называть его языком низкого уровня.
Так как он основывается на работе с событиями, это событийно-ориентированный язык программирования.
Предложение сформулировано таким образом, что читателю остаётся непонятно, про Си идёт речь, или про JASS. Если первое, то замечу, что Си - процедурный язык программирования, и нативного функционала работы с событиями (event subscription) в нём нет вовсе. Ближайший родственный язык, в котором в нативно присутствует функционал СОП - C#.
Эти переводчики называют трансляторами. Если они при переводе проверяют, может ли выполниться каждый отдельно взятый кусочек программы, их называют интерпретаторами (очень напоминает процесс синхронного устного перевода с одного языка на другой). Если они осуществляют сборку без проверки её работоспособности, их называют компиляторами.
Интерпретатор считывает исходный код программы и выполняет его, причём преобразование исходного кода в бинарный и выполенение выполняется построчно (исполняют полученный скрипт, не изменяя его). Компиляторы же полностью переобразовывают исходный код программы в бинарный, который целевая система может выполнять самостоятельно (создают исполняемый файл). Подавляющее большинство компиляторов при работе производит поиск ошибок в коде, выдавая их списком после завершения компиляции.
Если говорить в отношении "чистого" JASS, то это скриптовый язык, и, следовательно, он именно интерпретируемый. Для избежания разночтений поясняю: в архиве карты файл скрипта хранится в неизменном виде, выполняется целевой системой (JASS VM) дословно и построчно, и, само собой, ни в какой машинный код не преобразуется. Существует способ реализации в JASS чего-то вроде ассемблерных вставок (принудительного исполнения определённым образом сохранённого в скрипте байт кода), но это совсем другая история.
Советую в соответствии с этим замечанием пересмотреть некоторые формулировки в статье, чтобы не сбивать читателей с толку. В отношении JASS, возможно, это значения не имеет, но сам по себе момент достаточно принципиальный, и неверное его понимание в будущем может выстрелить читателю в колено.
Встроенное средство в World Editor занимается компиляцией JASS.
Исключительно проверкой кода, причём, насколько мне известно, посредством запуска внутриигрового интерпретатора. Остальное разобрано выше.
На такие ошибки, как бесконечные циклы или десинхронизация код не проверяется.
Не рекомендовал бы ставить подобные примеры в один ряд: причиной появления бесконечные циклов почти всегда является ошибка в коде или алгоритме, а причиной появления десинхронизации служит исключительно неосведомлённость картодела о механике синхронизации игровых данных ввиду некоторых неочвидных особенностей её работы.
Подобные недочёты компилятора World Editor широко использовались взломщиками.
Не указано, какие "подобные недочёты" имеются в виду. Если это про ошибки из предыдущего абзаца, то замечу, что RB работал из-за совершенно иного недочёта разработчиков игры и был весьма топорно заткнут в патче 1.24. Популярный сейчас Memory Hack технически эксплуатирует ту же самую ошибку.
RB в далёком прошлом, не вижу смысла о нём вообще упоминать. Кроме того, не вполне понятно, как это упоминание соотносится с названием спойлера, в котором находится: "Краткий ликбез о типах и переводах языков программирования".
Структуру кода на JASS под силу понять даже новичку в программировании.
Не согласен, понятность кода зависит только от того, как он написан, независимо от ЯП (разумеется, если это не ASM).
Обработка команд языка движком игры - тайна за семью печатями.
Абсолютно нет, всё давно разобрано по винтикам, доходило даже до абсурда: та самая ошибка в работе JASS VM, которая позволяла исполнять произвольный код на машине игрока, была окончательно исправлена только после того, как парень с хайва написал им письмо с указанием, где именно и каким образом её стоит исправлять, с огромным описанием технических деталей.
Недостатки
Отсутствие поддержки работы с памятью
Она условно есть, просто появилась случайно
Реальная необходимость работать напрямую с памятью в WarCraft не для хака функционала, который "забыли" добавить в нативки отсутствует => это сложно считать недостатком, скорее просто характеристикой
trackable - особый случай, но он не касается игрового интерфейса
Практически единственное адекватное применение trackable - как раз-таки создание альтернативного внутриигрового UI.
После небольшого опыта работы с JASS у меня появилось такое подозрение, что в JASS переменные - это не сами области памяти, а ссылки на эти области
Так и есть, поскольку JASS-скрипт исполняется через VM.
>Обнуление <...> используется для того, чтобы показать, что в переменной никакого значения не хранится, при этом память, выделенная под переменную, не освобождается
Освобождается при смерти потока, но только при условии, что переменной не задано значение. Базовые типы прямо наследуются от типов из Си, поэтому с ними работает его сборщик мусора, и обнулять их не требуется (в статье Скорпа были уточнения на этот счёт).
В общем, массив - это несколько переменных, объединённых в таблицу в одной переменной для удобства.
ЕМНИП, там принципиально различается подход к использованию памяти, это не только удобство.
Это действие также называется инициализацией переменной.
Крайне советую разбить пример кода на
local integer myInteger
и
set myInteger = 0
чтобы пояснить разницу между объявлением переменной и её инициализацией. Технически, в JASS это практически одно и то же, но концептуально это разные вещи. Кроме того, кейворд local имеет смысл только после введения в контекст понятия "функция", так как вне её оно не может быть использовано.
Также имя переменной должно быть уникальным <...> переменная и функция не может иметь одно и то же имя
Уточнение - только в одном неймспейсе, в противном случае будет использоваться переменная с наименьшей областью видимости. Тут могу ошибаться, так как не использую "чистый" редактор. В моей сборке код из-под ката прекрасно сохраняется.
код
globals
integer Test=0
endglobals
function TestFunc takes nothing returns nothing // Если поменять название на "Test", то возникает конфликт с локалкой, но не с глобалкой.
local integer Test=12
endfunction
То есть, глобальная переменная может иметь одинаковое имя с функцией. Ну и да, опять-таки, слово "функция" используется раньше пояснения, что это такое. Читатель-то не компилирует, а интерпретирует текст, построчно. =)
Такие функции часто называют "нативками" в честь приставки native, используемой для таких функций.
Native - родной, функции называют так в силу того, что они предоставляются вместе с языком на правах базовых, и их фактическая реализация находится на более низком уровне абстракции.
И серьёзно, 11я ссылка на одну и ту-же статью в википедии. Мне как читателю стало понятно личное отношение автора к проприетарному софту ещё на таблице, и даже там повторения было избыточными.
Постоянная функция
ЕМНИП, константы в JASS - это именно константы, а не константные функции. Могу ошибаться.
Помните, что после возврата значения исполнение функции останавливается.
Лучше написать "прерывается", так как остановка может подразумевать продолжение исполнения в дальнейшем.
Сравнивает два значения одинаковых типов.
Можно вынести перед таблицей и не повторять для каждого элемента.
В целом - весьма здорово написано, видно, что автор вложил довольно-таки много труда, надеюсь, что мой фидбек поможет сделать статью ещё лучше.
» WarCraft 3 / JASS: группа или массив?
» WarCraft 3 / Момент полного удаления боевой единицы из игры
» Дневник Сильваны / Первая запись
» Гномья графомания / DTH: новая геймдевопотуга
» WarCraft 3 / Момент полного удаления боевой единицы из игры
Алсо количество объектов считают так: объект появился - добавили +1 к счётчику, объект умер - вычли -1 из счётчика, а не странными костылями.
Ред. Clamp
» WarCraft 3 / JASS: группа или массив?
» WarCraft 3 / Способы реализации дорожного трафика
» WarCraft 3 / JASS: группа или массив?
Ред. Clamp
» WarCraft 3 / JASS: группа или массив?
» WarCraft 3 / Способы реализации дорожного трафика
» Гномья графомания / DTH: новая геймдевопотуга
Ред. Clamp
» WarCraft 3 / JASS: группа или массив?
» WarCraft 3 / JASS: группа или массив?
DracoL1ch:
Время программиста всегда дороже времени процессора \о/
» WarCraft 3 / JASS: группа или массив?
» WarCraft 3 / Момент полного удаления боевой единицы из игры
Ред. Clamp
» WarCraft 3 / JASS: группа или массив?
Ред. Clamp
» WarCraft 3 / Момент полного удаления боевой единицы из игры
» WarCraft 3 / Выбор Юнита по Строке
» WarCraft 3 / JASS: Курс молодого бойца
» WarCraft 3 / Лаг при первом открытии меню Задания
Ред. Clamp
» WarCraft 3 / Почему Target point of ability being cast не на своем месте?
» WarCraft 3 / Лаг при первом открытии меню Задания
» WarCraft 3 / Патч 1.28.2
Ред. Clamp
» WarCraft 3 / JASS: Курс молодого бойца
Если говорить в отношении "чистого" JASS, то это скриптовый язык, и, следовательно, он именно интерпретируемый. Для избежания разночтений поясняю: в архиве карты файл скрипта хранится в неизменном виде, выполняется целевой системой (JASS VM) дословно и построчно, и, само собой, ни в какой машинный код не преобразуется. Существует способ реализации в JASS чего-то вроде ассемблерных вставок (принудительного исполнения определённым образом сохранённого в скрипте байт кода), но это совсем другая история.
Советую в соответствии с этим замечанием пересмотреть некоторые формулировки в статье, чтобы не сбивать читателей с толку. В отношении JASS, возможно, это значения не имеет, но сам по себе момент достаточно принципиальный, и неверное его понимание в будущем может выстрелить читателю в колено.
RB в далёком прошлом, не вижу смысла о нём вообще упоминать. Кроме того, не вполне понятно, как это упоминание соотносится с названием спойлера, в котором находится: "Краткий ликбез о типах и переводах языков программирования".
Освобождается при смерти потока, но только при условии, что переменной не задано значение. Базовые типы прямо наследуются от типов из Си, поэтому с ними работает его сборщик мусора, и обнулять их не требуется (в статье Скорпа были уточнения на этот счёт).
И серьёзно, 11я ссылка на одну и ту-же статью в википедии. Мне как читателю стало понятно личное отношение автора к проприетарному софту ещё на таблице, и даже там повторения было избыточными.