Избранное Все заметки GitHub icon Мой Github Обо мне
42 заметки с тегом

разработка

Позднее Ctrl + ↑

Unity EventManager 2.0

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

using UnityEngine;
using UnityEngine.Events;
using System.Collections.Generic;
using System;

public class EventManager : MonoBehaviour {

    [Serializable]
    public class GameEvent : UnityEvent<object[]> { };

    private static EventManager _instance;
    private Dictionary<string, GameEvent> _eventDictionary;

    void Awake () {
        if (_instance != null)
            return;
        _instance = GetComponent<EventManager> ();
        if (_eventDictionary == null)
            _eventDictionary = new Dictionary<string, GameEvent> ();
    }

    /// <summary>Добавляем "слушателя" для события</summary>
    /// <param name="eventName">Название события</param>
    /// <param name="listener">Метод-обработчик события</param>
    public static void Subscribe (string eventName, UnityAction<object[]> listener) {
        GameEvent thisEvent;
        if (_instance._eventDictionary.TryGetValue (eventName, out thisEvent))
            thisEvent.AddListener (listener);
        else {
            thisEvent = new GameEvent ();
            thisEvent.AddListener (listener);
            _instance._eventDictionary.Add (eventName, thisEvent);
        }
    }

    /// <summary>Удаляем "слушателя" из списка</summary>
    /// <param name="eventName">Название события</param>
    /// <param name="listener">Метод-обработчик события</param>
    public static void Unsubscribe (string eventName, UnityAction<object[]> listener) {
        if (_instance == null)
            return;
        GameEvent thisEvent;
        if (_instance._eventDictionary.TryGetValue (eventName, out thisEvent))
            thisEvent.RemoveListener (listener);
    }

    /// <summary>Отправить событие</summary>
    /// <param name="eventName">Название события</param>
    /// <param name="parameters">Параметр массив</param>
    public static void SendEvent (string eventName, params object[] parameters) {
        GameEvent thisEvent;
        if (_instance._eventDictionary.TryGetValue (eventName, out thisEvent)) {
            thisEvent.Invoke (parameters);
        }
    }
}

Теперь количество параметров динамическое и любого типа. Для простого взаимодействия, вполне работоспособно. Пример использования:

void OnEnable () {
	EventManager.Subscribe ("event_name", MyFunction);
}

void OnDisable () {
	EventManager.Unsubscribe ("event_name", MyFunction);
}

void MyFunction (object[] parameters) {
	Debug.Log (parameters.Length); // количество параметров -> 3 в примере
	Debug.Log (parameters[1]);        // выведет -> 1 
}

...

EventManager.SendEvent ("event_name", "param_string", 1, 2); // вызов события
2017   unity   разработка   с#

iPhone X & Edge Protection

С выходом iPhone X и отказом от физической кнопки Home, Apple доставила некоторые неудобства разработчикам. И хотя для нативных приложений всё прошло более-менее гладко (неадаптированные приложения просто получили черные рамки), то для других — пришлось делать оптимизацию.

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

Но почему-то в тестах на iPhone 7 с установленной iOS 11.1.1, приложение стало вести себя как-будто это iPhone X — на нижних и верхних гранях экрана перестал работать тач, точнее, он срабатывал, но некорректно. Видимо это баг iOS или Unity, пока не разобрался, но исправить надо было.


Оказывается, можно скрыть Home Indicator и включить т. н. Edge Protection. Это когда первый свайп показывает Home Indicator, а второй скрывает приложение. Пока из коробки Unity не умеет так делать, пишут что в одном из следующих обновлений добавят. Кто на старых версиях 5.5+ (как я), нужно патчить XCode проект. Как это сделать, я уже писал. Раз, два.

Чтобы включить Edge Protection нужно добавить пару строчек кода в два файла:

// UnityViewControllerBaseiOS.h
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures; 

// UnityViewControllerBaseiOS.mm
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
    return UIRectEdgeAll;
}

Ветка на форуме Unity
Статья на Medium

2017   ios   iphone   разработка

Участь игр с «честным» рандомом

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

Это относится к карточным играм, где рандомно карты выдаются, игры с кубиками, игры где случайно выпадают предметы, сундуки и т. п. Игроки всегда будут недовольны настоящим рандомом, будут говорить и писать, что нечестно и подстроено, хотя на самом деле, всё наоборот.

И варианта тут два:

  1. Оставить всё как есть — ведь это честно! и правильно, со стороны разработчика
  2. Сделать «нечестный» рандом и настроить баланс

Хотя нет, один вариант — №2. Потому что в итоге, главная цель любой игры — дать удовольствие от игры играющему; выигрывает он, проигрывает — неважно.

Почитать на эту тему: https://gdcuffs.com/post/unfr-rndm/

2017   игры   мысли   разработка   ссылки

Визуальное программирование в Unity

Для Unity уже давно существует ассет Playmaker, который позволяет создавать сценарии игры без написания кода. У него есть свои пользователи и их достаточно много. Я никогда не пользовался такими инструментами и думаю, что какой-либо более-менее серьезный проект невозможно сделать без написания кода.

Однако, для каких-то отдельных элементов и частей игры, такой подход вполне может сократить время разработки. Так недавно появился ещё один инструмент для визуального программирования, похожий на Blueprints из движка Unreal — Bolt.

Выглядит красиво, требует одну из последних версий Unity 2017.1.0 и говорят, работает быстро. Плагин функциональный и может:

  • два типа графов: как в Unreal Blueprints и конечные автоматы как в Playmaker
  • группировка, слои и зум
  • события, макросы, плагины
  • live-редактирование
  • поддержка всех типов
  • встроенная документация

Кроме того, судя по плану разработки — у этого инструмента будет много полезных и удобных функций. Ещё есть сравнительная таблица с другими визуальными редакторами.


А вот что касается использования визуальных средств для создания сложных шейдеров, то тут я «за» :) Таких инструментов много, цены на них приемлемые и результат достойный.

  1. Amplify Shader Editor
  2. Shader Forge
  3. Shader Weaver

Если хочется начать с чего-нибудь попроще и получить красивый результат, есть ассет Minimalist. Привет, Monument Valley!

Можно применять разные цвета на разные стороны объекта с одним материалом, использовать градиенты, есть встроенный редактор материалов, стоит недорого и есть версия Free.

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

2017   unity   ассеты   инструменты   разработка   расширение

Автоподстановка полей в UI

Нашёл интересное решение, которое сохранит дорогое время разработки, взяв на себя рутинные операции по присвоению объектов со сцены полям класса. Как-то так.

Например: вы сделали новый объект интерфейса, создали для него класс, добавили соответствующие поля и потом ручками в инспекторе Unity присвоили текстовое поле к Text и кнопку к Button.

А если таких полей 10-15? И окошек столько же... Я думаю мысль понятна.

Вот как раз для таких дел этот скрипт и есть. Только делает он всё сам. Работает это так:

using UnityEngine;
using UnityEngine.UI;

public class DialogWindow : AutoReferencer<DialogWindow> {
   public Text DialogLabel;
   public Button ConfirmButton;
}
Главное, чтобы названия полей и имена объектов совпадали. И типы соответственно.

Ну и сам скрипт. Конечно, вряд ли есть возможность использовать его везде — всё-таки архитектура приложения у всех отличается, однако, полезность какая-то в нём есть.

using System.Linq;
using UnityEngine;

public class AutoReferencer<T> : MonoBehaviour where T : AutoReferencer<T> {

   #if UNITY_EDITOR
   // Этот метод вызывается один раз, когда мы добавляем компонент на объект
   protected new virtual void Reset()
   {
       // Магия рефлексии
       // Для каждого поля в классе/компоненте, мы ищем только пустые или null
       foreach (var field in typeof(T).GetFields().Where(field => field.GetValue(this) == null))
       {
           // Теперь ищем объект с таким же именем
           Transform obj;
           if (transform.name == field.Name)
           {
               obj = transform;
           }
           else
           {
               obj = transform.Find(field.Name); // Или нужно сделать рекурсию, чтобы пойти глубже по иерархии
           }

           // Если находим объект с таким же именем как и поле - пытаемся присвоить его к этому полю
           if (obj!=null)
           {
               field.SetValue(this, obj.GetComponent(field.FieldType));
           }
       }
   }
   #endif
}

Подглядел на The Knights of Unity ;)

2017   unity   интерфейс   разработка   с#

SublimeText vs VSCode for Unity

Судя по статистике, ко мне часто заходят по запросам связанным с настройкой SublimeText для Unity. Хочется вам сказать:

— Друзья! Переходите на VSCode — он удобнее. Для него также есть куча плагинов и расширений, подсветка, форматирование, автодополнение, дебаг... Всё работает очень быстро и ничего настраивать не надо. И он бесплатный.

https://code.visualstudio.com

2017   инструменты   разработка

Machine Learning теперь и в Unity

На волне популярности дополненной реальности, машинного обучения и нейронных сетей — Unity выпустила в открытый бета-тест свой SDK для машинного обучения.

На Github есть вики с описанием, как начать работать с SDK.
А вот так выглядит демо обучения агента:

Это круто!

2017   unity   разработка

Группы по Unity и GameDev

Небольшой список групп и пабликов, где можно пообщаться, спросить совета, узнать что-то новое по Unity и разработке игр. На русском и парочка на английском:

Unity

GameDev

2017   игры   разработка   ссылки

Unit тесты в Unity

Что такое юнит-тестирование, зачем оно нужно, стоит ли покрывать весь код тестами — можно узнать из этой хорошей статьи. Я лучше сразу скажу, как создать тест в Unity. Открываем пункт меню Window → Editor Tests Runner. Если у вас ещё нет тестов, то увидите окно, как на скриншоте, если нет этого пункта меню — значит у вас старая версия Unity :)

При нажатии на кнопку — создастся пример теста. Все!
На самом деле — нет.

using UnityEngine;
using UnityEditor;
using NUnit.Framework;

public class NewEditorTest {

	[Test]
	public void EditorTest() {
		//Arrange
		var gameObject = new GameObject();

		//Act
		//Try to rename the GameObject
		var newGameObjectName = "My game object";
		gameObject.name = newGameObjectName;

		//Assert
		//The object has a new name
		Assert.AreEqual(newGameObjectName, gameObject.name);
	}
}

Как видно, у метода есть атрибут [Test], который и указывает, что это будет тестом. Если создать несколько тестов и запустить их через тот же Editor Tests Runner, можно увидеть какие тесты прошли, а какие нет:

В Unity для тестирования используется опенсорсная библиотека NUnit, которая предназначена для работы с .Net языками, в том числе и с C#. На Github есть обширная документация, где расписаны все атрибуты которые можно использовать.

Кроме того, есть специальные Unity-атрибуты, с помощью которых можно тестировать корутины, запускать тесты в режимах редактирования или игры, тестировать на определенных платформах. Доки и примеры есть на сайте Unity.

Также, у Unity есть ещё специальный ассет для тестирования — Unity Test Tools, но как я понял они его перестали поддерживать.

2017   unity   ассеты   инструменты   разработка   с#

Работа в фоне в iOS и Unity

Маленький плагин который позволяет поработать приложению в свернутом виде на iOS, некоторое время. Зачем это нужно? Например, чтобы дождаться команды с сервера и показать пользователю уведомление, что пришло время его хода.
Весь плагин состоит из двух функций, которые запускают и останавливают задачу при потере фокуса.

-(void) startTask {
    [self endTask];
    if (bgTask == UIBackgroundTaskInvalid) {
        bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [[UIApplication sharedApplication] endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];
    }
}

- (void) endTask {
    if (bgTask != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
    [UIApplication sharedApplication].idleTimerDisabled = NO;
}

А в Unity это вызывается на OnApplicationFocus:

void OnApplicationFocus (bool focusStatus) {								
    if (focusStatus) 
        Background.StopTask();
    else 
        Background.StartTask();
}

Ссылка на Github

2017   git   ios   plugin   unity   разработка
Ранее Ctrl + ↓