#блог

об играх, разработке и личном опыте

Ctrl + ↑ Позднее

Запуск билда Unity в симуляторе iOS

Если у вас возникли проблемы с запуском билда в симуляторе iOS, в то время как на устройстве и редакторе все работает — следует проверить пару моментов:

  • Если у вас есть нативные плагины, которые используют сервисы недоступные в симуляторе (in-app, push, keychain, etc) — их нужно отключить/закомментировать.
  • Возможно, вы забыли поменять Target SDK при компиляции на Simulator SDK.
  • А еще, Unity мог неправильно выставить Build Settings в xCode проекте и их нужно поправить вручную, например так:

После этого, все должно заработать ;)

Публикация тормозит на «Authenticating with the iTunes store»

Эта довольно распространенная «проблема» известная уже несколько лет! На stackoverflow предложено куча вариантов: от просто подождать (что кстати иногда работает), до смены WiFi сети, запуска одновременно нескольких Application Loader’ов и другого шаманства.

Столкнулся с этим делом дважды. Первый раз как-то само разрешилось — подождал около 5 минут, второй раз ничего не помогало. Гугл подсказал, что наиболее часто работающий метод — это удалить и заново загрузить iTunes Store’s Transporter.

Для этого в терминале выполняем следующие команды:

cd ~
mv .itmstransporter/ .old_itmstransporter/ // сохраняем предыдущую версию, на всякий случай
rm -rf ~/.itmstransporter/ // или удаляем если не нужен 
"/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms/bin/iTMSTransporter"

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

Unity, iOS и IPv6

С 1 июня 2016 года, все отсылаемые приложения в AppStore должны уметь работать по IPv6.

Unity вроде как решили все эти вопросы еще в прошлом году. Но если погуглить, то оказывается, что некоторые получают отказы до сих пор, по тем или иным причинам связанным с IPv6. Чтобы проверить работает ли ваше приложение в сетях IPv6, Apple написали специальную статью с мануалом. Я ей воспользовался и обнаружил, что приложение не коннектится к серверу :(

Для соединения используются сокеты, поэтому код был очень простой:

...
private Socket _socket;
 
public static void Connect () {
    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    _socket.BeginConnect("134.253.17.11", 10001, new AsyncCallback(OnEndConnect), null);
}
 
void OnEndConnect (IAsyncResult iar) {
    Debug.Log ("connected");
}
...

Собственно, сразу стало понятно в чем проблема — AddressFamily должен быть InterNetworkV6 если работаем по IPv6 или InterNetwork для IPv4.

Если подключаться к серверу по домену, то можно воспользоваться таким решением — передаем хост, указываем тип, в ответ получает IPv6 или «обычный» IP адрес.

Если же подключение осуществляется по IP адресу, то преобразование с помощью различных конвертеров в IPv6 (раз, два), не дало работающего результата — сокет просто не подключался.

Ответ был найден в том самом мануале от Apple (смотрим на подраздел Use System APIs to Synthesize IPv6 Addresses) и на одном китайском сайте :) Если все это объединить, то получится более-менее универсальное решение которое будет работать и по IPv6, и по IPv4, в iOS и Android.

Исходник на Github

2017   git   ios   plugin   unity   разработка

Кликабельные ссылки в TextMeshPro

Как сделать чтобы ссылки в тексте, стали «ссылками» и при клике на них открывалась страница? Просто! Достаточно открыть примеры из TextMeshPro (TMP) и добавить немного кода.

Пускай у нас есть компонент ТМР с текстом, в котором встречаются ссылки на страницы в сети, например: http://mopsicus.ru, www.unity3d.com, и другие. И нужно чтобы это выглядело примерно так, и было кликабельно:

Для этого, находим ссылки в тексте с помощью регулярного выражения, сокращаем их (по желанию) и приводим к формату для обработки ТМР.

// Check links in text
void CheckLinks () {
	Regex regx = new Regex ("((http://|https://|www\\.)([A-Z0-9.-:]{1,})\\.[0-9A-Z?;~&#=\\-_\\./]{2,})" , RegexOptions.IgnoreCase | RegexOptions.Singleline); 
	MatchCollection matches = regx.Matches (textMessage.text); 
	foreach (Match match in matches) 
		textMessage.text = textMessage.text.Replace (match.Value, ShortLink(match.Value));     	
}

// Cut long url
string ShortLink (string link) {
	string text = link;
	int left = 9; 		
	int right = 16; 		
	string cut = "..."; 	
	if (link.Length > (left + right + cut.Length)) 
		text = string.Format ("{0}{1}{2}", link.Substring (0, left), cut, link.Substring (link.Length - right, right));
	return string.Format("<#7f7fe5><u><link=\"{0}\">{1}</link></u></color>", link, text);
}

Как установить подчеркивание, цвет текста и другое смотрите в документации ТМР. Осталось повесить обработчик нажатия и определить на какую ссылку кликнули:

// Get link and open page
public void OnPointerClick (PointerEventData eventData) {
	int linkIndex = TMP_TextUtilities.FindIntersectingLink (textMessage, eventData.position, eventData.pressEventCamera);
	if (linkIndex == -1) 
		return;
	TMP_LinkInfo linkInfo = textMessage.textInfo.linkInfo[linkIndex];
	string selectedLink = linkInfo.GetLinkID();
	if (selectedLink != "") {
		Debug.LogFormat ("Open link {0}", selectedLink);
		Application.OpenURL (selectedLink);        
	}
}

Исходник на Github

Баг в userInfo NotificationItem [iOS]

Если вы работаете с пуш уведомлениями в iOS и делаете это стандартными средствами Unity, то при обработке уведомления у вас могут возникнуть сложности с цифровыми значениями. Видимо Unity сам преобразует их в Int64. В тоже время, с текстовыми полями все в порядке.
Чтобы получить «нормальное» цифровое значение из пуша и преобразовать в Int, можно воспользоваться таким способом:

...
int my_int_value = 0;
object data = push.userInfo["my_int_value"];
if (data is Int64)
	my_int_value = ConvertInt64ToInt32((Int64)data);
...
// Convert function
int ConvertInt64ToInt32 (Int64 val) {
	return (int)(val & 0xFFFFFFFF);
}

Но как показывает практика, лучше использовать нативный плагин :)

2017   ios   unity   с#

О Texture2D и памяти

Если погуглить на тему Unity Texture2D, memory leak, www.texture — то можно обнаружить кучу постов с вопросами о том, почему не освобождается память. И это на на самом деле так, если ничего не предпринимать.

Намучившись со всем этим, составил небольшой список мыслей/советов:

  • Создавайте, как можно меньше Texture2D, в идеале использовать пул. И обязательно делать Destroy, когда объект уже не будет использоваться, иначе память не освободится.
  • При использовании класса WWW, также нужно удалять www.texture и делать www.Dispose.
  • Сжатие «на лету» не работает, т. е. если вы например загружаете изображение из интеренетов и потом вставляете в Image, способом ниже, то на мобильном устройстве, картинка полностью развернется в память, без сжатия. И это печально.
// data is downloaded byte[]
...
Texture2D texture = null;
#if UNITY_ANDROID
	texture = new Texture2D(2, 2, TextureFormat.ETC2_RGBA8, false);
#elif UNITY_IOS
	texture = new Texture2D(2, 2, TextureFormat.PVRTC_RGBA4, false);
#endif
texture.LoadImage(data); 
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(.5f, .5f)));
MyImage.sprite = sprite;
  • Используйте сжатие предназначенное под конкретную платформу. Для iOS — это PVRTC4, для новых моделей подойдёт ASTC, начиная с iPhone 6. Для Android — ETC. Подробнее про это можно прочитать в мануале Unity.
  • Кроме того, сжатие не будет работать в некоторых случаях, если размеры спрайтов и атласов не равны степени 2. Т. е. размеры должны быть 128x128, 2048x2048 и т. д.

10+ ссылок для самостоятельного продвижения игры

ASO: как увеличить установки игры на 53% в день за счет оптимизации названия и описания в Google Play

https://blog.appfollow.ru/aso-как-увеличить-установки-игры-на-53-в-день-за-счет-оптимизации-названия-и-описания-в-google-9fc3d38e18c

Пошаговый алгоритм работы с ASO

https://habrahabr.ru/company/miip/blog/313804/

Итак, вы создали игру. Что дальше?

https://habrahabr.ru/post/324702/

Сколько заработает ваша мобильная игра?

https://habrahabr.ru/company/miip/blog/322552/

Продвижение вашей инди-игры: самые важные нюансы, о которых никто не знает

https://habrahabr.ru/post/257379/

100 и 1 инструмент для маркетинга и монетизации

http://apptractor.ru/marketing

Как бесплатно исследовать целевую аудиторию вашей новой игры

http://apptractor.ru/measure/user-analytics/kak-besplatno-issledovat-tselevuyu-auditoriyu-vashey-novoy-igryi.html

Как провести маркетинговый анализ? Руководство от Ильи Еремеева из Game Insight

http://app2top.ru/marketing/kak-provesti-marketingovy-j-analiz-rukovodstvo-ot-il-i-eremeeva-iz-game-insight-95389.html

Продвижение мобильных приложений: выученные уроки

https://habrahabr.ru/company/enterra/blog/295774/

Подкасты Галенкина

http://galyonkin.com

Подборка англоязычных ресурсов, нужных для продвижения игры

http://app2top.ru/marketing/poleznoe-podborka-ssy-lok-po-marketingu-dlya-mobil-ny-h-razrabotchikov-82746.html

SSL/TLS в Unity

А сегодня мы будем шифровать весь трафик. А зачем? А чтобы усложнить жизнь читерам.

Если у вас мультиплеер на авторитарном сервере, естественно все действия должны контролироваться на нем. Но зная, какие команды отправлять, можно легко написать бота, который автоматизирует некоторые процессы, нарушая баланс и игру «правильных» игроков. Конечно, если сильно захотеть, можно сломать все что угодно, но усложнить жизнь взломщикам и читерам тоже можно. Будем использовать SSL.

Ничего изобретать не буду, потому что «все уже придумано до нас» :)
Для теста серверной части (на node.js) и генерации ключей используем эти скрипты. Единственное, чего там нет — это как из сертификата и ключа сделать PFX файл:

openssl pkcs12 -export -in client.crt -inkey client.key -out mycert.pfx

Этот файл понадобится для клиента. Для проверки SSL соединения берем пример с сокетами с MSDN и немного переделываем его. Получаем поток и прокидываем его через SSL.

IEnumerator UseSSL () {
	NetworkStream stream = new NetworkStream (socket);
	SslStream sslStream = new SslStream (stream, false, new RemoteCertificateValidationCallback (CertificateValidationCallback), new LocalCertificateSelectionCallback (CertificateSelectionCallback));
	bool authenticationPassed = true;		
	#if UNITY_EDITOR
		X509Certificate2 cert = new X509Certificate2(certPath, certPassword);
	#elif UNITY_ANDROID || UNITY_IOS
		WWW reader = new WWW (certPath);
		while (!reader.isDone) 
			yield return null;
		X509Certificate2 cert = new X509Certificate2 (reader.bytes, certPassword);
	#endif
	X509Certificate2Collection certs = new X509Certificate2Collection();
	certs.Add (cert);
	sslStream.AuthenticateAsClient (server, certs, SslProtocols.Tls, true);
	authenticationPassed = sslStream.IsAuthenticated;
	if (authenticationPassed) {
              ///
	}
	yield break;
}

Вот и весь квест. Теперь трафик между игровым сервером и клиентом зашифрован.

Ccылка на Github

2017   git   unity   разработка   с#

Система плагинов для iOS и Android

Простая система плагинов для мобилок. Контроллер инициализирует все плагины и обрабатывает приходящие сообщения. Обмен данными в формате JSON.

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

Ссылка на Github

Ctrl + ↓ Ранее