|
Май
17
|
Часть 2 — взаимодействие с пользователем, простейший интеллект, логика игры.
В очередном уроке по программированию игр на iPhone рассмотрим основы взаимодействия с пользователем, простейшей интеллект и логику игры. Мы научимся обнаруживать простые столкновения, чтобы знать, когда мяч соприкасается с ракеткой. Идя навстречу многочисленным пожеланиям, я добавляю к урокам раздел “Задачи”, где буду давать дополнительные советы по освоению программирования. Итак, приступим. Для начала откройте код из первой части урока.
Взаимодействие с пользователем.
Первым делом приступим к реализации взаимодействия с пользователем. Все, что нам нужно, — перемещать точку нахождения ракетки X в точку Х касания экрана пользователем. Это крайне простая реализация, которую можно серьезно усовершенствовать (подробнее об этом в “Задачах” в конце урока). Откройте файл “iTennisViewController.m” и добавьте следующий код:
Как и в предыдущем уроке, подменяем метод “touchesMoved“, фиксируя момент, когда пользователь проводит пальцем по экрану. В метод “touchesBegan” я добавляю оператор “else if“, направляющий все события на “touchesMoved“, если игра запущена.
Первые две строки метода “touchesMoved” распознают точку касания экрана пользователем. Теперь нужно создать новый объект “CGPoint“, ориентируясь на точку касания Х и местонахождение желтой ракетки игрока Y. Objective-C не позволяет ограничиться утверждением типа “racquet_yellow.center.x = location.x“. Возможно, это объяснятся тем, что объект “CGPoint” является постоянным (нередактируемым).
Последним шагом, центру ракетки пользователя назначается новое положение.
Обнаружение столкновений.
Дополнение: предложенный читателем блога способ обнаружения столкновений оказался намного проще, поэтому я обновил код.
В метод “gameLoop” из файла “iTennisViewController.m” добавьте следующий код:
Apple предлагает весьма удобный метод проверки на предмет столкновения фреймов объектов — “CGRectIntersectsRect“. Мы просто соотносим его с фреймами мяча и ракетки. При ударе мяча о ракетку вектор его скорости Y нужно обратить. Следующий оператор “if” предотвращает ситуацию с “застрявшим” на ракетке мячом, который отскакивает взад–вперед и никуда не перемещается. Следовательно, вектор скорости мяча должен обращаться только в случае, если он находится перед любой из ракеток. (Примечание: “NSlog” не является обязательным элементом, он использовался лишь для отладки.)
Простой искусственный интеллект.
Следующим шагом попробуем наделить вашего компьютерного соперника по iTennis простейшим интеллектом. Многие даже не подозревают, насколько сложен искусственный интеллект приличного уровня. Я мог бы долго и скучно рассуждать о математике, философии, эвристике и тому подобном, но не стану, а вместо этого познакомлю с NOOB, крайне простым для понимания интеллектом игры. Принцип заключается в том, что компьютер будет “следить” за мячом и направляться к нему в попытке отбить. Приступим…
Для начала определим константу, описывающую скорость движения компьютерного игрока. К верхней части файла “iTennisViewController.m” добавим следующее определение:
После тестирования, величину определяющую скорость перемещения компьютерного игрока за мячом, можно будет откорректировать. Чем выше значение, тем “лучше” будет играть соперник (при достаточно высоком числе он станет непобедимым). Непосредственно под кодом обнаружения столкновения добавьте следующие строки:
Первый оператор “if” призван осложнить жизнь компьютеру, проверяя, находится ли мяч на “его” стороне корта. В противном случае компьютер не должен двигаться и реагировать на мяч. Этим моментом можно пренебречь, но с ним игра станет интереснее. Следующие операторы “if” проверяют на совпадение координаты центра мяча Х и координаты Х для центра ракетки. Если мяч находится справа от ракетки компьютера, координата Х для нее увеличивается методом “kCompMoveSpeed“. Если слева — уменьшается им же.
Думаю, теперь понятно, как изменение переменной “kCompMoveSpeed” влияет на качество игры компьютера…
Кнопкой “Build and Go” самое время проверить игру в действии. Как видим, компьютер исправно реагирует на мяч и практически постоянно его отбивает. Осталось еще немного, чтобы игра стала действительно интересной — счет!
Механизм игры: подсчет очков.
Теперь нам понадобится способ ведения счета. На самом деле, имеем дело с еще одним простым обнаружением столкновений — фиксируется факт удара мяча о заднюю стенку. Для начала зададим несколько переменных и метод. Откройте файл “iTennisViewController.h“. Добавьте выделенный фрагмент кода:
Для начисления очков игроку и компьютеру нам интересно целочисленное представление. Кроме того, потребуется функция “reset“, перемещающая мяч к центру экрана. Зададим еще одну переменную, добавив следующий код в верхнюю часть файла “iTennisViewController.m“.
Переменная достаточно прозрачна, но на всякий случай поясню, что она определяет необходимое для победы количество очков. Для ускорения процесса я сделал ее равной пяти. Теперь добавим проверку полученных пользователем или компьютером очков. Сразу после кода интеллекта внесите следующие строки:
Посмотрим на два первых оператора “if“. Они проверяют факт столкновения/прохождения мяча через верхнюю либо нижнюю часть экрана. Если мяч достигает верхней точки, увеличиваются очки игрока, если нижней — компьютера. Следующая строка для новичков в программировании будет посложнее. Мы обращаемся к функции “reset“, передавая ей некое выражение.
Согласно определению функции “reset“, она работает с величиной BOOL, определяющей факт окончания игры. Следовательно, возвращается истина либо ложь. При оценке выражения мы передаем “true” или “false“. Выражение “(player_score_value >= kScoreToWin)” будет расценено как ложное, если переменная “player_score_value” меньше пяти. Как только она достигнет пяти, выражение вернет “true” и обратится к функции “reset“.
Зачем это нужно? Для экономии строк и упрощения кода. Теперь нет необходимости делать это следующим образом “if(player_score_value >= kScoreToWin) ) [self reset:YES]; }else{[self reset:NO];}“. По-моему, оно того стоит.
Теперь дадим определение функции “reset“. К файлу “iTennisViewController.m” добавим следующий метод:
Для начала переведем игру в состояние паузы. Если помните, при этом на экран выводится сообщение “Tap to Begin“. Теперь перемещаем мяч в центр экрана. Если для переменной “newGame” получено значение “YES/true“, нужно будет предпринять несколько шагов. Первым делом определяем победителя, сопоставив счет компьютера и игрока. Следующим шагом обновляем сообщение “Tap to Begin“, уведомляя игрока о победителе. Можно добавить еще одну метку, но я предпочел воспользоваться имеющейся… И, наконец, обнуляем очки игрока и компьютера, поскольку начинается новая игра.
Если новая игра не подтверждена, восстанавливаем сообщение “tapToBegin“. Это необходимо на случай, если на экран выводилась надпись “Player/Computer wins!“. Не забудем обновить метки на экране с учетом нового счета. Можно начинать…
Щелкайте на кнопке “Build and Go” и вступайте в сражение с компьютером за звание победителя iTennis!
А вот и обещанные задания.
-
Доработайте взаимодействие с пользователем. При щелчке на экране ракетка должна не мгновенно оказываться в той же точке, а смещаться к ней.
- Доработайте обнаружение столкновений. При ударе мяча о ракетку скорость ракетки должна влиять на скорость (и направление) мяча в соответствии с базовыми законами физики.
- Добавьте к искусственному интеллекту элемент случайности: пусть он пытается “предугадать” направление мяча.
- Доработайте подсчет очков. Установите максимальное число на 15, 30 и т.д.
- Доработайте подсчет очков. Сделайте так, чтобы победа присуждалась только при разнице в 2 очка.
Вот пожалуй и все. Удачи!!! Кстати, если вы решите улучшить функционал приложения, добавить новые функции, или знаете как упростить код, то очень просим написать об этом в комментариях к уроку.
Для цитирования кода в комментариях используй тег:
1 2 3 | </strong> CODE <strong> |








Сентябрь 17th, 2009 at 12:56
А подскажите, где в коде описывается, что мяч должен отскакивать от ракетки при ударе об неё? ибо у меня мяч пролетает сквозь ракетку и касяк найти не могу.
Сентябрь 17th, 2009 at 23:58
Хм. Странно. Честно говоря не знаю где вы могли ошибиться.
Сентябрь 18th, 2009 at 06:49
Нашёл ошибку, тока не могу понять почему в этом ошибка, если сделать скорости
#define kBallSpeedX 10
#define kBallSpeedY 15
равными 8 и 9 соответственно, то всё нормально ) не могу объяснить почему так происходит.
P.S. Такое ощущение что из-за большой скорости мячик пробивает ракетку )) бред, но создаётся такое впечатление )
Сентябрь 18th, 2009 at 07:55
Я не программер блин, помочь не могу. Сходите на оригинальную статью и посмотрите комменты. Может найдете решение. Ссылка на оригинал в конце урока.
Сентябрь 11th, 2011 at 13:18
Скорость движения мячика регулируется расстоянием, на которое мячик перепрыгивает (kBallSpeedX и kBallSpeedY) за время заданное таймером NSTimer в методе viewDidLoad.
Да, на большой скорости мячик перепрыгивает ракетку, да и просто двигается рывками. Нужно сделать более частую прорисовку, не 0.05, а хотя бы 0.01, и уменьшаем kBallSpeedX и kBallSpeedY опять же в пять раз.
Теперь столкновения будут правильно учитываться и не будет рывков в движении мяча.