понедельник, 23 июля 2012 г.

iOS. Разработка игры iTennis.


screenshot_011


 Откройте Xcode и выберите View Based Application.

screenshot_01

Назовите приложение iTennis.

Скопируйте на свой компьютер картинки, необходимые для создания игры, которые находятся в этом архиве.

iTennis_Images.zip

Распакуйте данный архив и перенесите картинки в папку Resources вашего проекта iTennis. После этого ваш проект в Xcode примет вид, как на картинке.

screenshot_02

Теперь вы готовы приступить к написанию кода игры.

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

Откройте файл iTennisViewController.h и добавьте в него следующий код:

screenshot_05

Теперь вы готовы приступить к созданию интерфейса.

Дважды кликните на файл iTennishViewController.xib для того, чтобы открыть его в Interface Builder.

На видео показано как необходимо расположить элементы интерфейса на экране.

После того, как установите все соединения, закройте Interface Builder и вернитесь в Xcode.

В Xcode вам необходимо прописать несколько констант. Для этого откройте файл iTennisViewController.m и добавьте туда следующий код:

screenshot_06

Первые две константы используются для сохранения состояния игры. Мы используем их для того, чтобы определить то, что в данный момент происходит на экране: запущена ли в данные момент игра или поставлена на паузу.

Поскольку игра происходит на плоском поле, то следующие две переменные хранят в себе скорость движения мяча по координатам X и Y. Данные переменные необходимы для определения вектора скорости движения мяча по на экране.

Последняя линяя кода синтезирует переменные для создания для них методов установщиков и получателей.

Теперь давайте добавим метод viewDidLoad.

screenshot_07

В этом методе мы сперва поставим игру на паузу. Это необходимо для того, чтобы игра не стартовала сразу, как только экран загрузится.

Далее мы создаем вектор скорости движения мяча по полю.

Вы можете по изменять константы скорости движения мяча для того, чтобы заставить мяч летать быстрее или медленнее.

Наконец, мы создаем таймер NSTimer. Первый параметр таймера - это временной шаг. Мы устанавливаем шаг времени равным 0.05 секунды. Изменение этого параметра будет влиять на скорость течения всей игры. Далее мы устанавливаем цель, которая говорит таймеру, где именно расположена функция, которая будет вызываться на каждом шаге работы таймера. И следующий параемтр - это сама функция, которая будет вызываться при срабатывании таймера. Проще говоря вы просто говорите таймеру вызывать метод self.gameLoop каждые 0.05 секунды. На параметр userInfo не обращайте внимания. Последний парамет repeats заставляет таймер повторно перезапускаться.

Теперь давайте созданим основной игровой метод gameLoop:

screenshot_08

В этом методе мы сперва проверяем состояние нашей игры: запущена он или стоит на паузе, поскольку мы не хотим, чтобы мяч двигался по экрану во время паузы.

Если игра не запущена или стоит на паузе, то мы показываем на экране метку tapToBegin. Эта метка была определена нами ранее. Она сообщает игроку о том, что он должен коснуться экрана для начала игры.

Если игра запущена, то мы начинаем двигать мяч согласно его вектору скорости.

Следующие несколько линий кода отвечают за проверку столкновения мяча с границами экрана. Если мяч коснется границы экрана, то мы изменим его вектор скорости на обратной для того чтобы он смог отскочить. Без этих линий кода мяч бы улетел далеко за границы экрана.

Последний фрагмент кода, который мы должны добавить на данном этапе - это метод touchesBegan:

screenshot_09

Мы будем использовать этот метод для запуска игры, если она будет поставлена на паузу. После активации данного метода будет спрятана метка tapToBegin и  запущена игра. В конечном итоге мы добавим код управления ракеткой именной в этот метод.

Наконец, для очистки памяти добавьте метод dealloc:

screenshot_10

Теперь необходимо добавить механизм взаимодействия с пользователем. Все, что нам необходимо сделать - это сдвинуть ракетку в место, куда пользователь коснулся экрана.

Откройте файл iTennisViewController.m и добавьте в него следующий код:

screenshot_01

Здесь мы перезаписываем методы, отвечающие за обработку прикосновений пользователя к экрану, которые активируются тогда, когда пользователь проводит по экрану пальцем.

Сперва мы добавили условие "else if" в метода tochesBegun, который просто передает все события в метод touchesMoves, если игра уже запущена.

Первые две линии внутри метода touchesMoves просто обнаруживают место прикосновения пользователя к экрану. Далее нам необходимо создать новую точку CGPoint с координатой X прикосновения пальца пользователя к экрану и координатой Y положения желтой ракетки игрока. К сожалению, Objective-C не позволит просто так написать racquet_yellow.center.x = location.x, из-за того, что CGPoint недоступна для изменений.

Наконец, центр ракетки устанавливается в новое положение.

Теперь необходимо заняться определением столкновений.
В файле iTennisViewController.m внутри метода gameLoop добавьте следующий код:

screenshot_011

Эпл предоставила нам метод CGRectIntersectsRect, который позволяют проверить столкновение объектов. Когда мяч сталкивается с ракеткой, мы изменяем координату Y вектора скорости на обратную. Следующее предложение необходимо для того случая, когда мяч может застрять за ракеткой, без возможности выбраться из этой ловушки. Поэтому мы должны быть уверены, что вектор скорости мяча изменится на обратный только в случае, если он окажется перед ракеткой. Обратите внимание на то, что функция NSLog не нужна для игра. Она используется только для отладки.

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

Сперва нужно задать константу, определяющую то, как быстро будет двигаться ракетка компьютерного игрока.

Добавьте в файл iTennisViewController.m следующий код:

picture-2

Чем больше будет значение данной константы, тем быстрее будет двигаться компьютерный игрок и тем лучше он будет играть. Если значение константы будет слишком велико, то компьютерный игрок будет непобедим.

Теперь добавьте следующий код над кодом, определяющим столкновения объектов:

picture-3 
Следующее выражение if необходимо для добавления сложности для компьютерного игрока. Оно просто проверяет: находится ли мяч на части корта компьютерного игрока. Компьютерный игрок не будет двигаться и реагировать, если мяч не на его части поля.

Следующее выражение if проверяет на сколько отлична координата X центар мяча от координаты X центра ракетки. Если мяч справа от ракетки компьютерного игрока, то координата X ракетки компьютерного игрока возрастает на значение kCompMoveSpeed. Если мяч слева от ракетки компьютерного игрока, то координата X ракетки компьютерного игрока убывает на значение kCompMoveSpeed. Теперь становится понятно как изменение переменной kCompMoveSpeed влияет на мастерство компьютерного игрока.

Теперь вы можете нажать Build and Go, для того, чтобы скомпилировать игру и опробовать её в действии.

Теперь необходимо вывести игровой счет на экран.
Сперва определим пару переменных и один метод:

picture-4

Числовые переменные будут хранить очки, получаемые игроками. Так же мы добавили метод reset, который будет устанавливать мяч в центр экрана для начала игры.

Теперь нужно прописать еще одну переменную:

picture-5

Данная переменная устанавливает количество очков, которые должны заработать игроки для победы.

Теперь добавим проверку на случай, если компьютерный игрок выиграет очко.

После кода искусственного интеллекта компьютерного игрока добавьте следующие строки кода:

picture-6

Здесь производится простая проверка: прошел ли мяч через верх или наз экрана. Если мяч прошел через верх экрана, то очки игрока увеличиваются на 1. Если мяч прошел через низ экрана, то очки компьютерного игрока увеличиваются на 1. После увеличения числа очков мы запускаем метод reset, к который передаем значение BOOL (true или false), означающее, что игра окончена. В данном случае это равносильно следующей линии кода:

if(player_score_value >= kScoreToWin) ) [self reset:YES]; }else{[self reset:NO];}

Теперь давайте в файле iTennisViewController.m пропишем метод reset:

 picture-7

В этом методе прежде всего мы ставим игру на паузу. В этом случае на экран выводится метка "Tap to Begin". Далее мы размещаем мяч по центру экрана.
Если в метод reset был передан аргумент YES (true), то нам необходимо сделать следующие вещи. Сперва мы определяем кто победил: компьютер или человек. Далее мы обновляем метку и выводим в ней сообщение о победителе. И наконец мы обнуляем очки игроков для возможности начала новой игры. Если это не новая игра, то мы должны заменить метку методом tapToBegin для вывода сообщения "Tap to Begin" на экран для того, чтобы убрать с экрана сообщение о том кто из игроков победил. Наконец мы обновляем на экране метки с изображением очков игроков.

Теперь нажмите Build and Go для того, чтобы скомпилировать игру iTennis  поиграть в неё.

После этого можно заняться созданием заставочного экрана, которой будет плавно затеняться, переходя в главное меню игры.

Загрузите эту картинку и добавьте её в папку resources вашего проекта.

splash
Теперь необходимо добавить новый View Controller, который будет содержать заставочный экран игры. Добавьте новый файл под названием SplashViewController в ваш проект, являющийся подклассом UIViewController. Отметьте так же галочку "Also create SplashViewController.h".

screenshot_01

Далее необходимо изменить AppDelegate для того, чтобы можно было загрузить это view controller вместо main view controller. Для этого откройте файл iTennisAppDelegate.h и измените его код на этот:

screenshot_02

В данном варианте мы просто заменили iTennisViewController на SplashViewController.

Далее откройте файл iTennisAppDelegate.m и измените его код на этот:

screenshot_03

Здесь мы опять заменили iTennisViewController на SplashViewController. Сделано это для того, чтобы мы могли загрузить сразу заставочный экран вместо главного меню. Единственное отличие здесь состоит в том, что мы создали новое окружение для SplashViewController. Нам не нужно было делать этого для iTennisViewController, потому что он загружался из nib-файла и наша программа делала это за нас. Но поскольку теперь мы создаем SplashViewController программно без nib-файла, то нам нужно инициализировать его.

Далее давайте определим Splash View. Откройте файл SplashViewController.h
и добавьте в него следующий код:

screenshot_04

Здесь располагается NSTimer, который используется для отображения заставочного экрана на некоторое время перед его затенением для перехода в главное меню игры. Далее располагается UIImageView, который выводит картинку на заставочный экран. Наконец, идет iTennisViewController, который мы заменили в AppDelegate. Мы будем загружать его из нашего заставочного экрана.

Теперь откройте файл SplashViewController.m и добавьте в него следующий код:

screenshot_05

Здесь просто синтезируются установщики и получатели для всех наших переменных.

Теперь добавьте следующий код в метод loadView:

screenshot_07 
Поскольку мы загружаем наш view программно без nib-файла, то надо создать view. Так мы берем фрейм, в котором выполняется наша программа и из него создаем новый view. Затем мы устанавливаем SplashViewController этому новому view. Мы создаем фрейм для того, чтобы просто сказать приложению создать view с размерами 320x480. Далее мы создаем splashImageView из картинки Splash.png. Нам так же необходимо создать для других картинок. Думайте о фрейме, как о неком контейнере, куда будут помещаться картинки. Далее мы добавляем imageview в main view, который сразу его отобразит.


Затем мы инициализируем наш view main controller, передавая его в nib, из котрого он был загружен.

Далее мы устанавливаем alpha transparency: 0.0. Это делает контроллер полностью невидимым. Наконец, мы добавляем его в наш view. Заметьте, что он размещается поверх splashimageview, где он остается невидимым благодаря alpha transparency: 0.0.

Наконец, мы запускаем таймер, который будет отображать заставочный экран в течении 2-х секунд, перед тем как вызвать затемняющий метод.

Теперь давайте добавим затемняющий метод:

screenshot_08

Данный метод просто затемняет view, затем он вызывает метод finishedFading. После затемнения отображается экран главного меню.

Убедитесь в том, что вы удалили заставку из superview, иначе у вас будет неверный переход.

Нажмите Build and Go для того, чтобы увидеть переход от заставочного экрана в главное меню вашей игры.

В игре мы будем использовать 2 вида звука: один для звука отскока мяча и один для обозначения момента, когда один из игроков получает очко.

Вам необходимо будет скачать эти звуковые файлы:

clapping-crowd-studio-01
tennis-volley-01

Обратите внимание на то, что оба файла имеют расширение .caf
Такой тип должен быть у всех ваших аудио-файлов для того, чтобы их мог воспроизвести iPhone. Хорошо, что Эпл предлагает специальную утилиту для конвертации аудио-файлов в этот формат. Для конвертации вам нужно будет открыть консоль терминала и ввести туда:

/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}

где {INPUT} - это путь к вашему исходному аудио-файлу, а {OUTPUT} - это путь в папку, куда сконвертированный итоговый файл будет сохранен с раширением .caf

Скопируйте айдио-файы в папку Resources внутри вашего проекта. Вы также можете добавить подпаку под названием Audio для удобства организации файлов в вашем проекте. Не забудьте отметить галочку для копирования файлов в нужную папку проекта.

screenshot_01

Поскольку теперь мы работаем с аудио-файлами, то нам необходимо добавить соотвествующий фреймворк в наш проект. Лучший способ найти нужный фреймворк на вашем Mac - это воспользоваться встроенным поиском. Кликните правой кнопкой мыши на папке Frameworks в вашем проекте и выберите Add > Existing Frameworks. (Убедитесь, что у вас стоит галочка на Computer для поиска по всему компьютеру.) В появившемся поле поиска наберите AudioToolbox.framework и выберите нужный фреймворк среди найденных результатов.

screenshot_02

После того, как вы выберете нужный фреймворк нажмите на кнопку Add для того, чтобы добавить его в проект.

Теперь откройте файл iTennisViewController.h и добавьте в него следующий код:

screenshot_11

Сперва мы импортируем заголовок AudioServices.h, который необходим для вызова функций проигрывания аудио-файлов Далее мы объявляем 2 переменные с типом SystemSoundID. Это просто две переменные типа Integer. Вы можете объявить их как Integer, но тогда компилятор сделает вам предупреждение.

Далее откройте файл iTennishViewController.m и добавьте в него следующий код для синтезирования методов установщиков и получателей для новых переменных:

screenshot_09

Теперь давайте инициализируем наши звуковые объекты. Найдите метод viewDidLoad и добавьте в него следующий код:

screenshot_12

Первая линия данного кода получает путь до аудио-файла. Следующая линия конвертирует путь в CFURLRef. Наконец, мы загружаем аудио-файл и присваиваем ему soundID. Обратите внимание, что мы передаем &clappingFileID, который передается по ссылке и позволяет методу AudioServicesCreateSystemSoundID изменять данную переменную. Тоже самое мы делаем для загрузки звука volley.

Проигрывание звуковых файлов выглядит достаточно просто. Для этого просто вызывается метод AudioServicesPlaySystemSound, которому передается soundID того аудио-файла, который вы хотите проиграть. Для того, чтобы проиграть звук аплодисментов, когда кто-то получает очко просто добавьте этот код в ваш метод reset.
screenshot_14

Обратите внимание, что мы передаем clappingFileID для обозначения того, что мы хотим проиграть звук аплодисментов.

Теперь добавьте следующий код в gameLoop для того, чтобы ракетка звучала, когда кто-то ударяет ей по мячу:

screenshot_15

Теперь кликните Build and Go и проверьте работу звука в игре. 

На этом данное обучение завершается.

Полный пример программы вы можете скачать здесь.

Комментариев нет:

Отправить комментарий