Unity3D + C#, или как переводить скрипты

    image

    На Unity3D я натолкнулся сравнительно недавно, до этого работал со своими самописными движками для мобильных телефонов на Java2ME, в остальное время я — дотнетчик.

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

    Про Unity в целом тут уже писали, так что повторяться не буду, отмечу главное — разрабатываемую игру можно (а на мой взгляд — и нужно) скриптовать на C# (спасибо Mono). Единственное ограничение — следует писать в пределах .NET Framework 1.1 — только он поддерживается на iPhone. [upd: пока я писал этот пост, вышла новая версия Unity3D для iPhone, поддерживающий .NET 2.1]

    Итак, ключевые плюсы для меня от использования Unity вообще и C# в частности:
    • Использование .NET Framework и C# (лично для меня это очень удобно)
    • Возможность сделать сборку сразу на iPhone и для веб-плеера (standalone сборки меня не прельщают по ряду причин, выходящих за рамки поста)
    • Уже готовые сценарии поведения на C# можно будет повторно использовать, например, при создании порта игры на XBox при помощи XNA (с изменениями, но все же)
    • Удобный интерфейс и не слишком прожорливые редакторы
    • Приемлимая цена

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

    Для скриптования используется прикрученный редактор UniSciTE на базе Scintilla, что лично мне пришлось не по душе, а потому я сразу захотел воспользоваться старой доброй Visual Studio. Вот о том, как скриптовать на C# будет речь ниже:

    [upd: перенесено в Game Development]



    Текущая версия Unity — 2.6.1, и в ней с интеграцией с Visual Studio проблем никаких нет — достаточно в окне обозревателя проекта сделать правый клик и выбрать соответствующий пункт меню. После этого Unity создаст солюшн, а если он уже создан — обновит. В проекте уже будут указаны ссылки на используемые библиотеки UnityEditor и UnityEngine, а все файлы со скриптами (независимо от языка) — добавлены в проект.
    VisualStudio

    Что надо иметь ввиду:

    • Каждый отдельный скрипт — это класс, описывающий поведение игровой сущности. Например, то что сущность «мокрая» при касании повышает уровень влажности на 3. Потом в игровом редакторе мы прикручиваем эту сущность к конкретной луже — и при попадании в нее уровень влажности будет повышаться. Каждый такой класс должен быть отнаследован от класса UnityEngine.MonoBehaviour, и если в скриптах на js это подразумевается, то в C# надо указывать явно.
    • Unity не переваривает namespace'ы. В будущем обещают исправить, но пока так.
    • Имя класса и имя файла скрипта должны совпадать. Если вы создадите класс через Visual Studio, то не забудтье брать namespace И отнаследовать класс от MonoBehaviour (using тоже не забудьте). Если вы создадите класс через Unity, то по умолчанию он будет называться NewBehaviourScript, не забудьте переименовать как файл скрипта, так и имя класса.

    Для описания других тонкостей приеду пример простого скрипта, который идет в комплекте с движком и позволяет перемещаться как в FPS, то есть wasd + пробел для прыжка + мышь. Чтобы игровой аватар пользователя не провалился ниже пола, его надо обернуть в простой коллайдер — CharacterController, каковой должен налепиться на игровой объект автоматически при применении к нему сущности FPSWalker.

    //параметры нашего хождения<br/>
    var speed = 6.0;<br/>
    var jumpSpeed = 8.0;<br/>
    var gravity = 20.0;<br/>
     <br/>
    //внутренние переменные<br/>
    private var moveDirection = Vector3.zero;<br/>
    private var grounded : boolean = false;<br/>
     <br/>
    //обновление по таймеру<br/>
    function FixedUpdate() {<br/>
       //мы на земле<br/>
       if (grounded) {<br/>
          //строим вертор перемещения<br/>
          moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));<br/>
          //переносим в глобальные координаты<br/>
          moveDirection = transform.TransformDirection(moveDirection);<br/>
          //увеличиваем пропорционально скорости<br/>
          moveDirection *= speed; <br/>
     <br/>
          //если велено прыгать - прыгаем<br/>
          if (Input.GetButton ("Jump")) {<br/>
             moveDirection.y = jumpSpeed;<br/>
          }<br/>
       }<br/>
     <br/>
       //вычитаем падение<br/>
       moveDirection.y -= gravity * Time.deltaTime;<br/>
     <br/>
       //берем товарища<br/>
       var controller : CharacterController = GetComponent(CharacterController);<br/>
       //перемещаем<br/>
       var flags = controller.Move(moveDirection * Time.deltaTime);<br/>
       //и проверям, на земле ли он<br/>
       grounded = (flags & CollisionFlags.CollidedBelow) != 0;<br/>
    }<br/>
    //ах да, если этот скрипт применят к игровому объекту, надо затребовать от объекта наличие компоненты CharacterController<br/>
    @script RequireComponent(CharacterController)


    Итак, при переводе этого скрипта на C# помимо вышесказанного следует учесть:
    • вы хотите, чтобы значения параметров можно было менять в игровом редакторе? Тогда делайте их public'ами.
      editor
    • Не путайте класс CharacterController и его тип typeof(CharacterController)
    • инструкции типа "@script RequireComponent(CharacterController)" превращаются в аттрибуты класса — [RequireComponent(typeof(CharacterController))]
    • Плавающая запятая предсавлена float'ом, на double даже вектор не помножить =)
    • В js не надо было явно приводить типы. C# — не такой!
    • И если вам нужно что-то сложное инициализировать, воспользуйтесь готовыми функциями Awake() и Start(), перегружать конструктор MonoBehaviour не рекомендуется

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

    using UnityEngine;<br/>
     <br/>
    //тот самый аттрибут класса<br/>
    [RequireComponent(typeof(CharacterController))]<br/>
    //не забыли переименовать класс и файл и указать наследование<br/>
    public class FPSWalkerInCS : MonoBehaviour {<br/>
       //это надо показать в редакторе, обращаем внимание на float <br/>
       public float speed = 6.0f;<br/>
       public float jumpSpeed = 8.0f;<br/>
       public float gravity = 20.0f;<br/>
       //а это - не надо<br/>
       private Vector3 moveDirection = Vector3.zero;<br/>
       private bool grounded = false;<br/>
     <br/>
       //сюда класть инициализцию<br/>
       void Start () {<br/>
     <br/>
       }<br/>
     <br/>
       void FixedUpdate() {<br/>
          if (grounded) {<br/>
             moveDirection = new Vector3(Input.GetAxis("Horizontal")0, Input.GetAxis("Vertical"));<br/>
             moveDirection = transform.TransformDirection(moveDirection);<br/>
             moveDirection *= speed;<br/>
     <br/>
             if (Input.GetButton ("Jump")) {<br/>
                moveDirection.y = jumpSpeed;<br/>
             }<br/>
          }<br/>
     <br/>
          moveDirection.y -= gravity * Time.deltaTime;<br/>
          //не забываем приведение типов<br/>
          CharacterController controller = (CharacterController)GetComponent(typeof(CharacterController));<br/>
          CollisionFlags flags = controller.Move(moveDirection * Time.deltaTime);<br/>
          grounded = (flags & CollisionFlags.CollidedBelow) != 0;<br/>
       }<br/>
    }


    Все, класс готов.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 15

      +3
      Единственное ограничение — следует писать в пределах .NET Framework 1.1 — только он поддерживается на iPhone.


      На странице Unity прочитал следующее:

      Added .NET 2.1 support via the Mono 2.6 runtime.
        +1
        упс, я не прав, сам все еще пользуюсь версией 1.5.1.

        Пойду-ка обновлюсь
          +7
          ха, да этот патч вышел седня ночью =)

          * ушел ковыряться в новой версии
            +1
            А что такое .NET 2.1 — это 2.0 + SP1?
            +2
            Когда начал читать подумал, что это об Unity DI контейнере от MS. Где встречал комментарий на хабре уже по поводу этих имен. :(
              +1
              Переименуйте, пожалуйста, в Unity3d в тексте, а то народ путает с DI-контейнером.

              А по теме — скриптовать в Unity еще очень удобно на Boo (Бу) — там практически питоновский синтаксис и есть метаплюшки, здорово уменьшаюшие объем тупого кодирования.
                +1
                есть.

                Бу — не владею, но ежели похож на Луа — должно быть добро
                  +4
                  Грубо говоря, бу это симпатишный C#. Или C# с питоноподобным синтаксисом. Разница с питоном в том, что есть метаплюшки, как назвал их комментатор выше :), и duck typing это отдельный тип (причём нежелательный по словам автора), а так это язык со статической типизацией.

                  myvar as duck;
                  myvar = 2;
                  myvar = 'hello';

                  myvar = 2; // myvar число
                  myvar = 'hello'; # кирдык

                  В тонкостях могу ошибаться, давно его ковырял.
                    +1
                    а по скорости он ближе к чему?)
                      +1
                      Должен быть максимально близко к C#, т.к. Boo перегоняется сначала в C#, а потом компилируется стандартными средствами. Получается скорость сродни C# минус скорость на обработку особенных конструкций языка.

                      Как-то так. :)
                +2
                В профильный блог перенесите какой-нить)
                  +2
                  Перенес в Game Development.
                  +1
                  пару вопросиков о Unity:
                  насколько сложно игру написанную на Unity для PC или веб-плейера портировать на айфон?
                  возможно писать только код и не совсем использовать визуальный редактор?
                    +2
                    Ну если вкратце, то при портировании все равно придется думать за дополнительную оптимизацию, заменять модели на более простые, убирать высокополигональные элементы сцены (тот же Terrain), делать просчет Occlusion Culling'а для всяких многостеночных сцен (инструментарий имеется), для тех же скриптов придется переписывать конроллеры ввода, потому как на iPhone в любом случае ввод будет не такой, как на PC/Web. Подробнее — опишу отдельным постом [не забыть бы].

                    Использовать редактор по минимуму — это значит создать проект, импортировать в него контент (включая скрипты), создать иерархию сцен, в каждую сцену закинуть соответствующие игровые сущности (по минимуму — по одной игровой сущности «сцена_такая_то», в которой все прописано уже), после чего редактор использовать только для билда. В данном случае unity сравним с Adobe Flash: можно активно пользовать редактор, а можно все вынести в скрипты, а в редакторе просто поместить экземпляр класса «сцена».

                    Даже не уверен, зачем это может понадобиться. Редактор вполне удобен, хотя конечно, бывают и лучше.
                      +1
                      С нетерпением ожидаю поста.)

                  Only users with full accounts can post comments. Log in, please.