Создание игр для мобильных телефонов - Майкл Моррисон
Шрифт:
Интервал:
Закладка:
Наблюдение переменных
Наблюдение – это методика, которая подразумевает отслеживание наблюдаемых переменных кода. Наблюдаемая переменная – это переменная, изменение значения которой вы можете наблюдать в отладчике. Конечно, если программа запущена с обычной скоростью, то наблюдение за переменными не поможет. Однако если вы наблюдаете за ними при пошаговом выполнении кода, вы сможете четко понять, что происходит в программе. Очень часто вы можете заметить, что значения тех или иных переменных изменяются непредсказуемо или принимают значения, которые в контексте созданного кода бессмысленны. Этот тип проникновения в исполнение кода может помочь вам найти ошибки. Пошаговое выполнение кода в сочетании с наблюдением переменных – это стандартный подход к поиску ошибок с помощью отладчика.
Использование точек останова
Другая фундаментальная техника поиска ошибок – это использование точек останова. Точка останова – это строка кода, которая прерывает выполнение программы. Чтобы понять пользу точек останова, представьте, что вас интересует строка, расположенная в середине программного кода. Чтобы добраться до этой строки, вам понадобится пройти половину программы по шагам. Но вы можете поставить в строке точку останова и запустить программу на выполнение. Программа будет выполняться до тех пор, пока ее работу не прервет точка останова. В этом случае программа останавливается, и вы оказываетесь в нужной точке кода. Теперь вы можете наблюдать переменные и даже пошагово выполнить программу. Вы также можете назначить несколько точек останова в ключевых местах программы, что очень удобно для последовательной отладки кода.
Стратегии отладки игр
Хотя инструменты отладки прошли длинный путь от зари программирования, основная часть работы по устранению ошибок и по сей день лежит на ваших плечах. Думайте об отладчиках и стандартных методиках отладки как о средствах, с помощью которых можно обнаружить ошибки, а не как о единственном средстве защиты от ошибок. Для устранения ошибок необходим значительный багаж знаний, практики, инструментов отладки и даже немного удачи.
Отладку можно сравнить с охотой: вы знаете, что где-то есть проблема, и должны найти ее. Поэтому вы должны подходить к отладке с определенной стратегией. Стратегии отладки могут быть разделены на две основные группы – предотвращение ошибок и определение ошибок. Давайте рассмотрим обе стратегии и увидим, как их можно совместно использовать, чтобы с легкостью исправлять ошибки.
Предотвращение ошибок
Предотвращение ошибок направлено на исключение их появления до того, как они могут проявиться. Предотвращение ошибок может показаться вполне очевидным, потому что это действительно так. Однако большое число программистов не использует этой стратегии при написании кода, а занимаются отладкой в конце. Помните, что стратегия предотвращения ошибок более трудоемкая работа, чем отладка. Я полностью поддерживаю эту стратегию как предварительный этап борьбы с ошибками.
Предотвращение ошибок и их устранение можно сравнить с вакцинацией и лечением болезни, после того, как вы ей заразились. Конечно, лучше потерпеть укол, чем сражаться с заболеванием. Эта метафора, но она хорошо применима к реальности. Ошибки подобны болезням: когда вы думаете, что победили их, применять эту метафору к отладке опасно, так как ошибки в коде подобны болезни – только решить, что избавился от нее, как она вновь проявляется совершенно неожиданным образом.
Расставляйте скобки явно
Очень часто ошибки возникают из-за неправильной интерпретации приоритетов операций. Я и сам не раз полагал, что точно помню, какой приоритет у данного оператора, а потом оказывалось, что ошибся. Взгляните на следующий пример:
int a = 37, b = 26; int n = a % 3 + b / 7 ^ 8
Если у вас хорошая память и вы можете без тени сомнения сказать, чему равно значение выражения, то вы – счастливчик! Для остальных это весьма рискованная строка кода, потому что она может давать множество результатов в зависимости от порядка выполнения операторов. На самом деле она возвращает единственное значение, которое вычисляется в соответствии с правилами языка программирования Java. Программисты легко могут перепутать порядок выполнения операторов, который приведет к ошибке вычислений. Каково же решение? Выход из этой ситуации – использовать скобки, даже если в этом нет необходимости, таким образом вы сможете контролировать порядок выполнения действий. Ниже приведен тот же самый код, но уточненный скобками:
int a = 37, b = 26;
int n = ((a % 3) + (b / 7)) ^ 8;
Скрытые переменные классаДругая ошибка, которая свойственна объектно-ориентированному программированию игр – это сокрытые переменные класса. Сокрытые переменные могут «потеряться», если в производном классе есть новая одноименная переменная. Взгляните на код, приведенный в листинге 16.1. Он реализует два класса Weapon и Bazooka.
Листинг 16.1. Классы Weapon и Bazookaclass Weapon {
int power;
int numShots;
public Weapon() {
power = 5;
numShots = 10;
}
public void fire() {
numShots–; //Переменная numShots в классе Weapon определена
}
}
class Bazooka : extends Weapon {
int numShots; //Переменная numShots скрывает переменную numShots родительского класса Weapon
public Bazooka() {
super();
}
public blastEm() {
power–;
numShots -= 2; //Переменная numShots класса Bazooka увеличивается, в то время как сокрытая переменная numShots класса Weapon остается неизменной
}
}Класс Weapon определяет две переменные: power и numShots. Класс Bazooka, производный от класса Weapon, также содержит переменную numShots, которая замещает одноименную переменную родительского класса. Проблема с этим кодом заключается в том, что когда конструктор класса Bazooka вызывает конструктор класса Weapon (через функцию super()), инициализируется переменная numShots класса Weapon, a не класса Bazooka. При вызове метода blastEm() в классе Bazooka используется видимая переменная numShots, которая по умолчанию инициализируется нулем. Как вы, вероятно, можете представить, в более сложных классах подобные проблемы более серьезны.
Поэтому необходимо следить за тем, чтобы не скрывать переменные. Это не означает, что вы не должны их использовать, помните о риске, который влечет за собой использование таких переменных.
Обработка исключенийОдна из полезных стратегий предотвращения ошибок в Java – это обработка исключений. Эта методика основана на предотвращении появления неожиданных сообщений во время выполнения программы. Чтобы обработать «проблемный» код, его необходимо заключить в конструкцию try и обработать исключение командой catch. Событие «ошибка» по своей природе является исключением, а конструкция catch называется «обработчиком исключения».
Ниже приведен пример кода обработки исключений, который вы уже неоднократно встречали в книге:try {
//действия
}
catch (Exception e) {
System.err.println(e);
}В этом коде обрабатываемое исключение – это исключение типа Exception, общий тип для всех исключений. В некоторых случаях в ответ на возникшее исключение может понадобиться выполнить какие-нибудь действия, а не просто вывести сообщение об ошибке. Или вы можете никак не обрабатывать возникшее исключение, подобно тому, как это сделано в некоторых мидлетах в книге.
...Совет Разработчику
Java поддерживает стандартные устройства ввода/вывода, которые можно использовать для отображения отладочной информации. System.err – это стандартное «устройство» ошибок, которое можно использовать для вывода ошибок в специальном окне или в командной строке эмулятора J2ME. Метод println() выводит строку в стандартное устройство.
Мы обсудили лишь малую часть обработки ошибок во время выполнения программы (исключений). Я настоятельно рекомендую более глубоко познакомиться с исключениями и их обработкой. К счастью, об обработке исключений в Java написано достаточно много, поэтому у вас не возникнет трудностей с поиском этой информации.
Выявление ошибок
Даже если вы применяли стратегии предотвращения ошибок, тем не менее вам придется отладить ряд ошибок. Программисты часто допускают ошибки, а высокая сложность многих мобильных игр вызывает проблемы. Просто поймите, что вы не идеальны, и сфокусируйтесь на поиске и устранении ошибок. Необходимо не только применять методы предотвращения ошибок, но и научиться отслеживать неминуемые погрешности, которые проявятся при тестировании игры. Давайте рассмотрим несколько методик поиска ошибок.
Использование стандартного вывода
Одна из самых старых методик поиска ошибок – это вывод отладочной информации на одно из устройств. Этот подход, вероятно, покажется вам архаичным, и во многом это так, однако он поможет быстро вникнуть, что происходит в игре.
Использовать стандартный прием вывода очень просто, например, вызовите метод System.out.println() в любом месте кода. Вы можете использовать стандартный вывод для выполнения многих задач – от отслеживания значений переменных до выявления запускаемых методов – просто вызовите метод println(), когда это нужно. Остерегайтесь вызывать метод println() в цикле обновления, например, внутри метода update(), который управляет анимацией мидлетов. В этом случае метод println() может замедлить работу мидлета, поскольку вывод текста на экран – достаточно медленная операция.