Новые возможности C# 8

Прошло примерно пол года с момента выхода C# 8, думаем самое время кратко рассмотреть основные нововведения. И начнем мы, пожалуй, по идее, с самого значимого из них, а именно с Nullable reference types.

Nullable reference types

Если бы Microsoft и компания писали бы сочинение по русскому языку в 5-ом классе, то обязательно бы получили минус полбалла за тавтологию, причем  заслуженно. Дело в том, что reference types (ссылочные типы) по определению nullable, т.е. зануляемые, таким образом получается масло масляное. Кроме того, название этого функционала пересекается с уже имеющимся функционалом, а именно с Nullable value types. А так как эти возможности имеют мало общего , это приводит к небольшой неразберихе. И даже больше, не только названия пересекаются, но и синтаксис полностью идентичен, что с одной стороны, конечно, хорошо, но вот с другой… Основная цель этого нововведения — решить (а по факту получается «решить») крайне неприятную и старую, как мир, проблему The Billion Dollar Mistake, т.е. всем известную проблему с Null Pointer Exception. В современных и мейнстрим языках, на наш взгляд, подобной проблемы существовать не должно вовсе, но, по тем или иным причинам, большиство популярных языков программирования продолжают гордо нести дух старой школы, а вместе с тем и весь тот груз, с которым каждому разработчику приходится бороться ежедневно, как будто бы других проблем у разработчиков больше нет. Ошибки дизайнеров, допущенные при укладке фундамента в самом начале, и необходимость в обратной совместимости теперь и не дают шанса на исправление подобных ошибок на корню. Из-за чего мы и получаем то, что имеем, как бы грустно это ни было. Напомним, что первая версия C# вышла в далеком 2002 году. С учетом того, что текущая версия вышла в прошлом году, не трудно подсчитать, что на то, чтобы начать (подчеркнем, не побороть, а именно начать) бороться с проблемой, которой быть в принципе не должно, потребовалось невообразимых 17 лет.

Чтобы начать пользоваться Nullable Reference Types, необходимо одним из возможных способов включить эту функцию вручную. И если для старых проектов это оправдано, то почему не включить эту функцию для новых проектов? Остается только гадать. Активировать эту возможность можно как для проекта целиком, в свойствах проекта, так и для отдельно взятых файлов с помощью директивы  #nullable enable . Давайте рассмотрим несколько примеров.
Читать →

Пользовательский интерфейс в Unity #2 — RectTransform


Небольшое видео с объяснением компонента трансформации пользовательского интерфейса.

Unity 2019.3

На днях стала доступна новая версия Unity2019.3. Это последняя запланированная версия с индексом 3. В этом году будет выпущено только две версии: 2020.1 и 2020.2 соответственно. В эту версию вошло приличное количество новых возможностей, как для художников и дизайнеров, так и для разработчиков. Самые значимые изменения, на наш взгляд, это:

  • сериализация с поддержкой полиморфизма и честный  null ;
  • ускоренный переход в Play Mode;
  • улучшения профайлера;
  • Addressable Asset System;
  • UIElements и UI Builder (превью);
  • обновление пакетного менеджера;
  • новая версия Asset Import Pipeline;
  • Accelerator service.

Более подробно с этими и остальными (а их гораздо больше) изменениями можно ознакомиться здесь.

Unity DOTS

DOTS

Unity уже довольно давно представили миру свой новый дата-ориентированный технлогический стек (Data-Oriented Technology Stack или сокращенно DOTS). Возможно, вы уже что-то слышали о нем. Именно о DOTS сегодня и пойдет речь. Мы рассмотрим, что же это такое, с чем его едят и попробуем написать простое приложение с его помощью.

Думаю, ни для кого не секрет, что с производительностью в Unity дела обстоят далеко не самым лучшим образом. Да и производительности как таковой никогда не бывает много. В Unity, естесственно, знают, как обстоят дела с производительностью в их собственном движке; и именно поэтому и был представлен DOTSDOTS позволяет использовать всю мощь современных мультиядерных процессоров для получения высокопроизводительного кода относительно просто и безопасно. По заявлению разработчика, благодаря использованию DOTS вы не только получаете максимально доступную (на данный момент) в Unity производительность. Одновременно с этим упрощается разработка кода, последующие его чтения и даже переиспользование кода в других проектах. На самом деле, конечно же, не все так просто; и это не какая-то серебряная пуля, и все (как и обычно) зависит целиком и полностью от разработчика: как напишет так и будет).

Так что же из себя представляет DOTS?

DOTS включает в себя три основных компонента:

  • Job System;
  • Burst Compiler;
  • Entity Component System.

Читать →

Советы по оптимизации Unity проекта

Рано или поздно практически любой разработчик на Unity сталкивается с проблемами производительности в своем проекте. И не важно, что это за проект: очередной AAA проект от известной студии, или Match 3 в новом сеттинге от новичков в игровой индустрии. Оптимизировать проект придется так или иначе. Также не важно, под какую платформу (платформы) написан проект: PC, консоль или мобильный. Кажется, что уж в 2019 году-то с гигагерцами не только на компьютерах, но и на телефонах, необходимость в оптимизации для не AAA проектов должна была отпасть. Но нет, приходится экономить спички практически как на заре игростроения. Непонятно, почему так происходит; возможно, это плата за скорость разработки в Unity? Гоу в комментарии, обсудим.

 

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

Искусство оптимизации состоит в том, чтобы за наименьшее количество потраченных сил получить максимальный прирост производительности. Другими словами, не нужно гнаться за оптимизацией каждой функции или алгоритма. Отсюда и первый совет.

Читать →

Как наладить дружеские отношения между Unity и F#?

F# — это функциональный язык программирования (но, если точнее, на самом деле, это — мультипарадигмальный язык, т.к., кроме функционального программирования, он поддерживает как императивное программирование, так и объектно-ориентированное программирование) под платформу .NET Framework. Своего рода Scala в мире JVM, только для CLRF# предоставляет много интересных возможностей, и во многих сценариях он на две головы выше своего брата C#. Пожалуй, чтобы описать все преимущества F# над C#, потребуется целая статья (кстати, хорошая идея для следующей статьи), поэтому давайте не будем останавливаться на этом вопросе сейчас. Тем более, никто не обязывает нас писать проект полностью на F#. Если в каких-то местах есть необходимость (или более выгодно) писать на C#, нам никто не запретит это сделать. Таким образом, можно использовать сильные стороны обоих языков программирования!

 

Основным языком программирования в движке Unity, как, думаю, многим должно быть известно, является C#. И, несмотря на то, что F# движком Unity официально не поддерживается, нам попадалась информация от одного из сотрудников Unity в твиттере о том, что у них есть тесты некоторой кодовой базы на F#.

Другими словами, не стоит бояться писать на F# под Unity, только из-за того, что что-то может не заработать или не скомпилиться, т.к. F# официально не поддерживается. Все-таки, и C# и F# работают поверх CLR и компилируются в промежуточное представление (IL), которое и выполняется либо Mono, либо компилируется в нативный код посредством IL2CPP. Таким образом, для Unity, теоретически, абсолютно не важно, на каком языке вы будете писать.

Читать →

Несовершенство современного ПО на примере Unity

Разработка ПО в современном мире идет семимильными шагами. От релиза до релиза количество добавленых фич может составить несколько десятков (а порой счет идет и на сотни), а API измениться до неузнаваемости. И, вроде бы, в этом нет ничего плохо, но из-за количественных изменений довольно часто страдает качество. Баг-трекер забивается нерешенными задачами, частенько можно наблюдать регрессию по уже имеющемуся функционалу, а часть багов не правится по непонятным причинам, а порой и вовсе без таковых. Отправляемые баг-репорты отклоняются или ожидают минимального проекта для воспроизведения ошибки, а последний, зачастую, невозможно создать. А если все-таки удалось создать, то в ответ нередко получаешь отписку «У меня все работает».

И вишенка на торте — голосование за исправление багов. И если «ваша» проблема наберет большое количество лайков, то тогда, возможно, разработчики обратят внимание и поправят ошибку, хотя не факт. Бывают случаи, когда даже большое количество лайков не помогает. Увы (. И если баги (и то в основном критические, и то не всегда) худо-бедно правятся, то разного рода мелкие улучшения и полезности, которые могли бы сэкономить время, остаются за бортом, что не может не печалить. Само собой, вышеперечисленное относится не ко всему ПО вообще, а, скорее, это что-то типа средней температуры по палате.

Как вы уже могли догадаться, сегодня речь пойдет о нескольких мелких проблемах в Unity, вероятность исправления/улучшения которых стремится к нулю. Перечисленные ниже проблемы — это небольшая капля из того моря проблем, с которыми приходится сталкиваться ежедневно при работе с Unity. Думаю, если вы плотно общаетесь с Unity, то вам должно быть понятно, о чем идет речь. Вообще, стабильность Unity улучшается, и сейчас хотя бы можно стало работать (иногда недолго). Раньше это был просто кромешный ад из зависаний и крешей (сейчас же можно отработать день-другой, а можно встрять всего на полдня). И если на нашем относительно маленьком проекте столько проблем, трудно представить, сколько их на крупных проектах.
Читать →

Неожиданное исключение на ровном месте

Намедни столкнулся с неожиданным (по крайней мере для меня) исключением на банальном куске кода в Unity. Если убрать все лишнее, то получится примерно вот такой скрипт:

Вышепреведенный код отрабатывал без ошибок, если на игровом объекте висел компонент CanvasGroup . А если этого компонента нет, то код генерирует исключение:

MissingComponentException: There is no ‘CanvasGroup’ attached to the «Button» game object, but a script is trying to access it.
You probably need to add a CanvasGroup to the game object «Button». Or your script needs to check if the component is attached before using it.
TestScript.Start () (at Assets/TestScript.cs:10)

По задумке, само собой, не ожидалось никакого исключения. Какое-то время потребовалось, чтобы понять, почему генерируется это исключение. Я, конечно, был в курсе, что Unity переопределяет оператор сравнения и что использовать операторы ?.  и  ??  с Unity.Object  и его наследников не следует. Но почему-то мне казалось, что переопределенный оператор на что-то влияет, только если мы имее дело с уничтоженным объектом. В моем же коде, по идее, этого не должно было быть. И потому это исключение оказалось неожиданным. Логично было бы предположить, что вместо  MissingComponentException будет генерироваться исключение  NullPointerException . Но, как вы уже поняли, этого не происходит. Согласно документации, метод  GetComponent :

Returns the component of Type type if the game object has one attached, null if it doesn’t.

Этот метод должен вернуть ссылку на компонент или  null , если компонент не найден. А далее приводится пример:

который «подтверждает» ранее описанное поведение. Но если бы это была бы правда, то мой код бы не генерировал исключение. А он генерирует. Дело в том, что метод  GetComponent возвращает ссылку на управляемый компонент, даже если компонент не найден. Иными словами, если запрашиваемый компонент не найден, то все равно возвращается ссылка на управляемый компонент, который не ссылается на настоящий C++ компонент и переопределенный оператор сравнения с  null  не срабатывает.  Создается ощущение, что вернулся  null . Это легко подтвердить, например, таким кодом:

В результате выполнения этого кода мы увидим:

UnityEngine.CanvasGroup
UnityEngine.Debug:Log(Object)
TestScript:Start() (at Assets/TestScript.cs:9)

Также стоит отметить, что, если сбилдить приложение, то тестовый код выполнится без ошибок, а ненайденный компонент будет добавлен. Происходит это потому, что в run-time  GetComponent будет возвращаться настоящий  null , и все выполнится, как и задумывалось. Т.е. подмена возвращаемого значения работает только в редакторе Unity. Само собой, не стоит использовать операторы  ?.  и  ??  с  Unity.Object  и его наследниками в реальном коде.