WarCraft 3: Ищем баги сами

» Раздел: Триггеры и объекты

Ищем баги сами

Думаю, ни для кого не секрет, что отладка алгоритма, как правило, занимает времени не меньше, чем само его написание. Тем более многие триггерщики, с которыми я сталкивался, вообще не знают, как самостоятельно найти ошибку. Ситуацию отягощает также отсутствие программы-отладчика для языка jass (напомню что триггеры - это всего лишь визуальная оболочка jass-кода).
В данной статье я намерен ознакомить читателя с методом отладочной печати, или попросту вывода DeBug сообщений. Вопрос "синтаксических" ошибок, возникающих при написании jass-кода, я рассматривать не буду (а в GUI они кажется вообще отсутствуют).
Итак, ниже я приведу достаточно примитивный триггер:
Он срабатывает при смерти юнита, и если юнит принадлежит Игроку 12 (в jass) или 13 (Нейтрально враждебный в GUI), то прибавляет к целочисленной переменной i_CreepsCounter (дословно счетчик крипов) уровень убитого монстра. Далее идет проверка, не достигла ли данная переменная значения 30, и если да, то данный триггер выключается, выводиться сообщение игроку, и через некоторое время объявляется победа.
Смысл его в том, что когда игрок убьет достаточно монстров (а то, насколько ценный монстр определяется по его уровню) объявить игроку победу. Вроде все правильно. Однако, сыграв несколько раз в карту и убивая нейтралов мы обнаружим, что победа не объявляется. И тут пришло время искать ошибку...
С чего начать? Для начала стоит посмотреть на наш триггер, возможно, вы сможете определить ошибку, просто внимательно просмотрев его. Однако такое возможно далеко не всегда т.к. в некоторых случаях приходится работать с куда более сложными алгоритмами, да и человек - не машина, он может просто проглядеть какую-либо ошибку.
Итак, мы точно знаем, что ошибка происходит именно в этом триггере. Мы можем сделать массу предположений, но как их проверить? Очень просто, мы будем выводить всего-навсего DeBug сообщения через действие Игра - Text Message. Начнем с того, запускается ли триггер вообще, несмотря на условие. Для этого я просто создам триггер, скопирую событие, а в действиях поставлю вывод сообщения:
Сразу скажу, что я пишу длинные сообщения только для того, что бы было яснее человеку, читающему статью, на практике же проще ввести несколько символов, главное -чтобы вам было понятно, из какого именно куска триггера вызвано сообщение.
* hint если бы у меня в триггере было несколько событий, я бы тестировал каждое из них отдельно.
Запускаем игру, и видим, что при каждом убийстве нейтрального крипа на экране появляется наше сообщение, а это значит, что событие работает нормально, и ошибка находится в остальной части триггера.
* hint если бы ошибка находилась именно в событии, то мне пришлось бы просто найти другое.
Дальше, стоит проверить, выполняется ли условие, для этого я добавляю действие вывода сообщения уже в свой триггер:
* hint очень важно как-либо выделять то, что данная операция предназначена для поиска ошибок, т.к. их потом придется удалять, и если они никак не выделены, то придется снова вникать в алгоритм, чтобы понять, что относится к основному алгоритму, а что е DeBug'у
* hint если бы у меня было несколько условий - я бы тестировал каждое из них отдельно в том стороннем триггере (это позволит узнать, какое из них когда возвращает правду, а когда ложь), вот так:
Вернемся к нашему примеру (мы уже узнали, что условие также работает успешно) - очевидно ошибка где то в действии триггера. Тут у нас имеется условный оператор, действия, находящиеся в котором, сработают, когда переменная будет равна 30. Ее мы сейчас и проверим. Теперь мы будем выводить на экран не логические значения (либо алгоритм выполняется и сообщение выводится, либо он не выполняется и соответственно сообщение не выводиться) а значения нашей переменной:
* hint также мы можем выводить значения кроме переменных целочисленных (integer) также реальных (real), строчных (string - их даже не надо преобразовывать), логических (boolean - для их вывода стоит использовать условный оператор if, написав в условии <переменная> равно Да, а в действие вывод сообщения)
Запустив карту и убив в ней крипа, мы заметим и наши сообщения, к примеру ... 21, 23, 24, 27, 29, 32, 36 ... Смотрим на наше условие, и видим, что оно будет выполнено в случае, только если игрок "выполнит план по убийствам крипов", в случае же если он его "перевыполнит", то победы ему невидать. Это несправедливо, исправляем триггер:
* hint если вы одновременно выводите сообщения о значениях нескольких переменных, желательно использовать функцию сложения строк, в первой части которой указать намек на то, значение какой именно переменной вы выводите.
* hint не забывайте по окончанию проверок удалять все debug элементы.
Ну вот, теперь победа объявляется всегда, когда игрок наберет достаточно очков. Еще раз повторю, что пример достаточно примитивный (придумать не примитивный, но применимый к триггерам я не смог) но вполне четко описывает данный метод. По сути мы можем только догадываться, о чем думает компьютер (какие значения в данный момент имеют переменные и какие инструкции он в данный момент исполняет), но мы можем попросить его рассказать нам об этом с помощью DeBug сообщений ;)

То же самое, только в jass'е

Все вышеизложенное имеет также применение и при написании скриптов на jass. Лично я предпочитаю писать следующим образом:
...
 call MyFunc(i_my, .0, ...
 set i_my=i_my+i_some+...
//
** call BJDebugMsg("i_my "+I2S(i_my)+"   i_some "+I2S(i_some))**
//
 call DoSomething()
...
Т.е. во-первых я выделяю DeBug просто комментариями (ой, насколько это удобней делать на jass, в редакторе триггеров ввод комментариев сделан просто жутко), во-вторых использую функцию BJDebugMsg(string) - наверное единственная true BJ function ;)
Имеется еще несколько преимуществ, к примеру, мы можем "отключить" выполнение какой-либо инструкции/инструкций, сделав ее комментарием (еще Sergey писал про это):
...
 call SomeFunc(i_my, ...
 set x=x+...
**// call DoSemething() // temporarily off**
 set i_my=i_my+1
...
А также мы можем вывести на экран integer-значение handle обьекта, это также иногда бывает весьма полезно:
function H2I takes handle h returns integer
 return GetHandleId(h)
endfunction

...
 call DoSomething(12, ...
//
** call BJDebugMsg(I2S(H2I(u_myUnit))+" "+I2S(H2I(d_myDestructable)))**
//
...

Заключение

И всё-таки, возможно, ваш алгоритм все-таки не будет работать именно так, как вы хотите - именно из-за того, что действие, которое вы используете, просто так устроено, а других подходящих нет, тогда... Если того, что бы вы хотели, нет в common.j (список всех native функций, грубо говоря, все возможные триггерные действия) - то стандартными средствами вы никак не добьетесь желаемого результата. Нет, конечно можно сторонней программой попробовать, но это уже немного другой разговор ;)
Помните, DeBug - не всегда интересное и простое занятие, часто оно может стать утомительным и монотонным, в таких случаях крайне рекомендую - сделайте небольшой перерыв, проветрите комнату, сделайте зарядку, и с новыми силами в бой!
Вроде все, статья хоть и простая, но, думаю, весьма полезная.

Просмотров: 11 863

» Лучшие комментарии


Ferrum #1 - 9 лет назад 1
Полезная статья, для чайников ;)
Zzлой #2 - 9 лет назад -1
Я чайник, но ничего не понял ^_^
Слова больно умные
Holm #3 - 9 лет назад 2
По моему, статья вполне простая, так как её смог понять даже я. ^^
Timon2008 #4 - 9 лет назад 0
У меня чайник кипит. Made in china== сделано для чайников :)))
and_y87 #5 - 9 лет назад 3
Гы... , я так с пелёнок проверяю если что не пашет =)
Sargeras #6 - 9 лет назад 5
Отредактировано. Исправлены орфографические, грамматические ошибки + ошибки оформления.
Сам я не нашёл в этой статье ничего особенного. Все опытные триггерщики и jass'еры так делают, но новичкам статья - в самый раз.
FaB0SS #7 - 9 лет назад 1
Статья стопудово для чайников, они токо такие (простые) примеры понимают.
И то не все роздупляются ;)
А вообще пример можно было и посложнее придумать.
Deviator #8 - 9 лет назад -4
  • Я сам всё отлично проверяю и если ошибки есть - я их нахожу. В таких статьях не нуждаюсь, ибо они не для моего уровня (я не говорю, что статья плохая, просто она не для меня). Но так глупо находить ошибки... Лично я сделав триггерный спелл, после сразу же проверяю его в карте и если что-то не работает, я просто запоминаю то место, где триггер отказался работать вот и всё... Но с этими "дебагами" жизнь только сложней станет...
ADOLF #9 - 9 лет назад 3
Для начала стоит посмотреть на наш триггер, возможно, вы сможете определить ошибку, просто внимательно просмотрев его
цитата из статьи + бывают случаи, когда просто просмотром ошибку определить невозможно...
вообще то дебаг ой как нужен, это не моя выдумка, а опыт многих поколений прграмистов...
Deviator #10 - 9 лет назад -4
  • Да ну его... у меня карта около 5 минут сохраняется, если каждый триггер проверять этими "дебагами" я с ума сойду... Самый мой безотказный способ я описал в предыдущем посте...
RAiT #11 - 9 лет назад 2
если ты не нашёл ошибку, что ты будешь её искать целый день... (если у тебя такого никогда не бывало, то значит ты не делал сложных тригегров=\) Проще вписать дебаг, и сохранить (пусть 10 минут).
Полезная статья, хотя я думаю большинство тригерщиков это знают.
BioAleks #12 - 8 лет назад 0
Полезная статья, хоть и для чайников но и другим пригодитса
Rewenger #13 - 8 лет назад 2
Имхо, до такого несложно додуматься самостоятельно, но большинству субъектов из "Академия - форум для вопросов" оно бы не помешало.
И чем больше и нагруженней карта, тем больше необходимость в дебагах, ибо никогда не знаешь, что у тебя откажет...
Dechimo #14 - 5 лет назад 0
Полезная статья
я тоже чайник -_-
pAxsIs #15 - 5 лет назад (отредактировано ) 2
Программирую на Pascal и С++ (для своего уровня развитию очень даже хорошо)
И не использовать debug - это как не проверять прожарилось ли мясо, думаю любители шашлыка не любят непрожаренное мясо :D, потому что конечный результат из твоих рассчетов может совпасть с требуемым, а если где-то утечка или вобще не то условие, которое опять же по случайности привело к желаемому результату, то ты об этом не узнаешь, а если узнаешь, то только после многократных тестированний и то не факт (участвовал в конкурсе лучших программистов северо-запада моего возраста, и знаете у меня в тестировании было 98 совпадений из 100 возможных в программе, а это уже означает, что программа не годна). Так что на своем опыте знаю, что лучше 1 раз все хорошенько проверить(конечно через debug), чем 100 раз протестировать :)
and_y87 #16 - 4 года назад 1
в GUI debug я не видел ни разу ))
в JASS так же ))
что вобщем то печальненько