23 мар. 2011 г.

FBconnect Login/Logout

В данной статье будет код только на Objective-C, поэтому полезно знать как вызывать внешние методы из Unity или прочитать статью как это делать. 

Для работы с Facebook я использовал Facebook  iOS SDK.
1. Открываем в XCode проект, расположенный в папке src.
2. Перетаскиваем из него папку Facebook в свой проект.
3. В свойствах проекта в Header Search Path прописываем путь к папке src.
4. Подключаем CoreGraphics framework. 
5. В info.plst добавляем строку "URL Types", внутри "Item 0" создаем строку "URL Schemes" и присваеваем ключу "Item 0" значение fb[ID приложения]

Для того, чтобы запрашивать у пользователя Facebook из приложения доступ к тем или иным функциям, сначала нужно зарегистрировать его на FB. Идем сюда, нажимаем "Создать новое приложение" и заполняем соответствующую информацию.
Для данного примера нам понадобится ID приложения.

Создаем класс со свойством Facebook* fb.
Для логина и выхода используются следующие методы:

- (void)login 
{
    fb = [[Facebook alloc] initWithAppId:@"ID приложения"];
   // используются для проверки заогинен ли пользователь
    // возможно не самый лучший вариант, но другого не нашел
    fb.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"AccessToken"];
    fb.expirationDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"ExpirationDate"];
   // в данном случае пользователя спросят о том, согласен ли он, чтобы
    // наше приложение могло писать ему на стену сообщения без его ведома
    permissions =  [[NSArray arrayWithObjects: @"publish_stream", nil] retain];
   
    // и вызываем диалог для входа
    [fb authorize:permissions delegate:self];
}

- (void)fbDidLogin 
{
    // если пользователь успешно вошел, записываем в память соответствующую информацию.
// Это также необходимо для проверки залогинен ли пользоваетель
    [[NSUserDefaults standardUserDefaults] setObject:fb.accessToken forKey:@"AccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:fb.expirationDate forKey:@"ExpirationDate"];
}

- (void)logout 
{
    [fb logout:self];
[[NSUserDefaults standardUserDefaults] setObject:fb.accessToken forKey:@"AccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:fb.expirationDate forKey:@"ExpirationDate"];
}

// метод используется для проверки залогинен ли пользователь либо нет
- (BOOL)isSessionValid
{
return [fb isSessionValid];
}


Для работы на ранних версиях прошивок (у меня начная с 4.1) в класс Unity AppController.mm необходимо добавить метод:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
return [[socialNetworks facebook] handleOpenURL:url];
}

В следующем посте постараюсь описать, как без лишних диалогов оставлять публикации на стене пользователя. 

12 мар. 2011 г.

Вызов методов Objective-C из Unity


Если вы счастливый обладатель Pro версии как я, то сделать это довольно просто. Давайте рассмотрим как добавить диалог, предлагающий пользователю проголосовать за наше приложение. Конечно, данный диалог можно без проблем реализовать средствами Unity, но цель данной статьи продемонстрировать вызов из Unity методов Objective-С.

В скрипте внутри Unity пишем:

[System.Runtime.InteropServices.DLLImport("__Internal")]
extern public static void showRateDialog();

И затем в нужном месте вызываем данный метод, например:

if(GUI.Button(buttonRect, "Show Rate Dialog"))
{
    showRateDialog();
}

Делаем Build, открываем проект в XCode, создаем класс 
RateDialog UIViewController <UIAlertViewDelegate>, внутри которого описываем метод, показывающий диалог:

- (void) showDialog(){
    [[[UIAlertView alloc] 
      initWithTitle:@"Like This App?" 
      message:@"Please rate it in the App Store!" 
      delegate:self 
      cancelButtonTitle:@"No Thanks" 
      otherButtonTitles:@"Rate It!", 
      nil] 
     show];
}

Чтобы обработать событие нажатия кнопки "Rate It!" описываем следующий обработчик:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == 1) { 
        NSURL *url = [NSURL URLWithString:@"YOUR_URL"]; 
        [[UIApplication sharedApplication] openURL:url]; 
    } 
}

Таким образом, при нажатии на кнопку "Rate It!", откроется Safari со страницей YOUR_URL.
Внутри данного класса или в любом другом месте описываем наш метод:

void showRateDialog(){
    [[RateDialog alloc] init].showDialog();
}

В ближайшее время напишу как к игре добавить интеграцию с Facebook. Для этого как раз понадобится умение вызывать внешние методы.

Используемые статьи:

4 мар. 2011 г.

JellyFresh


Вот и появилась в AppStore наша первая игра. Пока это всего лишь Lite версия и выложили мы её в большей степени для того, чтобы посмотреть как происходит процесс Review игр в AppStore.
Игру можно скачать перейдя по данной ссылке.
Если появятся вопросы по реализации, не стесняйтесь задавать, с радостью отвечу.

21 февр. 2011 г.

Оптимизация игр на Unity (Pool, Coroutines)

Как оказалось, функции Instantiate и Destroy довольно затратные, поэтому, если в вашей игре порождается и уничтожается множество объектов, то используйте pool объектов.

Необходимое количество объектов генерируется при запуске игры и в нужный момент, отображается на сцене. Вместо того чтобы уничтожать объект, отключаете его поведение, либо просто меняете значение свойства active на false. Данный подход значительно ускоряет игру.

Также для повышения производительности рекомендуется использовать вместо Update так называемые Coroutines. Просто создаете функцию возвращающую IEnumerator (в C#), в которой располагается цикл, каждая итерация которого выполняется через определенные промежутки времени, которые можно задать написав yield return new WaitForSeconds(1.0f). Если пауза достаточно велика, то действия описанные в цикле будут выполняться реже, тем самым сберегая процессорное время.

17 февр. 2011 г.

Оптимизация игр на Unity для iPhone (продолжение)

Предрелизное состояние. Уже всё сделано, всё красиво. Запускаем на iPhone - появляются небольшие, но мешающие игровому процессу тормоза.
Стал читать статьи по оптимизации, нашел как использовать Profiler в Unity - очень полезный инструмент при оптимизации и iPhone internal profiler.

И смотря лог в Profiler'е обнаружил, что довольно часто вызывается сборщик мусора и на него уходит несколько миллисекунд процессорного времени. При этом никакие игровые объекты не уничтожались. Я стал читать про сборщик мусора (GC) в Unity и нашел ветку форума, где говорилось, что такое поведение встречается при использовании OnGUI. У меня как раз стояла единственная кнопочка, которую я отрисовывал в нем. После замены её на Plane, столь частый вызов GC прекратился и игровой процесс ускорился.

Но оптимизация на этом ещё не закончена. Вскоре напишу про что-нибудь ещё.

12 февр. 2011 г.

2D анимация. Sprite Manager.

Моей ошибкой при создании 2D объектов на Unity было представление, что ничего плохого не происходит если в коде поменять текстуру материала или поменять смещение и другие её параметры. Как оказалось при осуществлении этих действий Unity создает отдельный материал, что конечно же добавляет Draw Call.

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

Продолжив поиски я нашел прекрасный класс, который был написан пользователями Unity сообщества - Sprite Manager. Он очень удобен для создания большого количества объектов. И количество Draw Calls при его применении равно количеству разных материалов. Поэтому, с его помощью, мне удалось значительно ускорить игру.

Использовать его довольно просто:
1. Создаем пустой объект и назначаем ему скрипт SpriteManager или LinkedSpriteManager (если объекты постоянно движутся). Заполняем параметр AllockBlockSize - примерное количество объектов данного вида (т.е. создается статический массив заданной длины) и задаем материал.
2. Затем создаем объект (например, Plane), отключаем Renderer. Навешиваем на него скрипт, который содержит ссылку на объект со  SpriteManager из пункта 1.
3. Вызываем соответствующие процедуры инициализации. Я использовал функцию AddSprite.

Всем кто занимается 2D анимацией очень рекомендую использовать данный класс. Экономит много времени и ускоряет вашу игру.

9 февр. 2011 г.

2D анимация

Про то как сделать 2D анимацию в Unity есть полезная статья.
Подход заключается в том чтобы нарисовать спрайт с различными положениями объекта.
Натянуть его на плейн и использовать скрипт, который будет пробегать по кадрам и соответствующим образом менять текстуру.
Скрипт дан в статье.

8 февр. 2011 г.

Лучи света


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

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

Оптимизация игр на Unity для iPhone


Некоторый список рекомендаций по оптимизации игр на Unity, на которые приходилось обращать внимание в процессе разработки:

  • объединяйте мэши и текстуры;
  • используйте как можно меньше различных материалов;
  • используйте как можно меньше источников света;
  • максимальное количество draw calls для iPhone составляет около 25-30 (посмотреть их количество можно во вкладке Game, нажав кнопку Stats);
  • на каждый элемент GUI уходит draw call;
  • прозрачные материалы нагружают процессор, рекомендуется их использовать как можно реже;
  • отключайте поведение и отображение объектов, находящихся за пределами камеры;
  • старайтесь сжимать текстуры в PVRTC - это ускоряет рендеринг на iPhone;
  • желательно чтобы все аудио треки были моно;

  • если вы пишите на JavaScript используйте директиву #pragma strict;
  • используйте больше статических полей;
  • при элементов GUI, вместо создания объекта Rect для их позиционирования в функции OnGUI, лучше данный объект сделать свойством класса и проинициализировать его в функции Awake, иначе он будет создаваться при каждом вызове OnGUI;
  • избегайте постоянного вызова в функции Update, FixedUpdate или OnGUI таких функций как GetComponent, либо transform, желательно такие объекты делать свойствами класса, инициализировать их в Awake и затем использовать.

7 февр. 2011 г.

iPhoneKeyboard


Почему-то на форумах, когда речь заходит о iPhoneKeyboard ответ получить довольно сложно. Либо я не умею их задавать, либо мало кто понимает как она работает.

В игре нужно было сделать запись в таблицу рекордов. При завершении игры, если пользователь попал в 10-ку лучших по количеству очков, ему отображается таблица рекордов и предлагается вписать свое имя. Для удобства я хотел автоматически поместить поле для ввода имени в фокус и открыть клавиатуру iPhone.

Почитав, что GUI.TextField рассчитано на работу с iPhone я, конечно же, первым делом написал скрипт с его использованием. На PC всё было здорово, но при загрузке на iPhone поле не становилось в фокусе и чтобы ввести имя нужно было сначала на него нажать и затем появлялась клавиатура. Такая перспектива совсем не радовала.

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


private iPhoneKeyboard keyboard;
private string userName = "";
void  Start ()
{
    keyboard = iPhoneKeyboard.Open(userName);
}
void  OnGUI ()
{
    userName = keyboard.text;
    GUI.Label(userNameTextRect, userName);
}
Т.е. клавиатура в нужный момент автоматически открывается, а набранный пользователем текст отображается в GUI.Label. Если нужна возможность последующего редактирования информации, то можно таким же образом использовать GUI.TextField.