Pull to refresh

Знакомство с UnrealEngine. Часть 2

Reading time 10 min
Views 24K
В прошлой части мы узнали что из себя представляет игра на UnrealEngine, научились строить геометрию, и расставлять акторов. В комплекте с играми на UnrealEngine и даже UnrealRuntime довольно много стандартных акторов, таких как декорации, всевозможные тригеры, оружие и прочие полезные вещи. При их грамотном использовании, можно делать разнообразные интересные уровни для игр, однако, полную свободу творчества это не даст. У игры будет стандартное начало, стандартные правила выигрыша и поражения, даже ввести лишнюю кнопку управления будет нельзя. Вот тут и пришла пора познакомится с UnrealScript. Сразу оговорюсь если вы гуру UnrealScript то скорей всего вам будет не интересно. Остальным добро пожаловать под кат.

Основы языка


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

Типы данных

UnrealScript содержит следующие простые типы данных:
  • bool — тип может принимать значение true или false
  • byte — без знаковое целое с диапазоном значений от 0 до 255
  • int — знаковое 32х битное целое с диапазоном значений −2 147 483 648 до 2 147 483 647
  • float — 32х битное число с плавающей точкой
  • string — строка из unciode символов
  • enum — тип перечисление, содержит набор именованных констант первая константа имеет значение 0, вторая 1 итд.
  • name — тип указывающий на имя чего либо, например имя состояния, статикмеша или класса

Так же существуют ссылочные типы данных:
  • Object — ссылка на объект, именно ссылка, то есть несколько переменных могут указывать одновременно на один объект
  • Actor — ссылка на объект класса Actor или унаследованный от него
  • Class — ссылка указывает на тип класса или унаследованный от него классов

Составные типы:
  • Struct — структура состоящая из фиксированного числа полей
  • Array — статический массив

Объявление классов, переменных и функции

Объявление классов

объявление класса выглядит так:
class classname extends parentclass [modifiers] ;

Где classname имя объявляемого класса, parentclass имя класса родителя, modifiers модификаторы.
Основные модификаторы:
  • Config(name) — имя .ini файла куда класс будет сохранят свои настройки
  • Native — класс частично выполнен в С++ коде
  • NativeReplication — репликация производится из С++ кода

остальные модификаторы можно найти сдесь http://wiki.beyondunreal.com/Class#Modifiers

Переменные(свойства)

Для объявление переменных существуют два ключевых слова var и local. Первый используется для объявления свойств класса и описывается сразу после объявления класса, вторые используются для указание локальных переменных методов.
Синтаксис использования этих ключевых слов следующий
var [modifiers] type variablename1, variablename2, ...;

local type variablename1, variablename2, ...;

Где type это тип переменной, variablename соответственно имена переменных.
modifiers модификаторы влияющие на поведение переменной.
список основных модификаторов
  • Const — переменная являться константой и не может быть изменена
  • Private — приватная переменная класса, доступна только внутри класса
  • Protected — защищённая переменная класса, доступна как в классе так и его подклассах
  • Public — публичная переменная, доступна из любого класса(по умолчанию все переменные Public)
  • Config — значение переменной может быть сохранено и получено из INI файла

Модификаторов очень много и для разных версий движка они разнятся с их списком можно ознакомится по адресу http://wiki.beyondunreal.com/Variables#Modifiers

Инициализация переменных

Для инициализации переменных существует специальная структура, которая, обычно, описывается в конце класса
defaultproperties
{
 varname=value
 arrayname(index)=value
 structname={(
  member1=value1,
  member2=value2
 )}
}

Соответственно varname, arrayname, structname это имена переменных, массивов и структур. Важно точка с запятой, в этом блоке в конце не ставится, используется перенос строки.

Функции (методы)

Функции объявляются следующим способом:
[modifiers] function [returntype] functionname ( [parameter] ) тело или точка с запятой

Где modifiers модификаторы влияющие на поведение функции, returntype возвращаемый функцией тип, functionname имя функции, parameter входящие(и при некоторых вариантах исходящие) параметры функции.
список основных модификаторов
  • Private — приватная переменная функция, доступна только внутри класса
  • Protected — защищённая функция, доступна как в классе так и его подклассах
  • Public — публичная функция, доступна из любого класса(по умолчанию все переменные Public)
  • Static — статичная функция, может вызываться без создания экземпляра класса, так как функция вызывается без создания экземпляра класса, она не имеет ссылки на свой объект self и не может быть реплицирована
  • Final — функция с этим модификатором не может быть переопределена в подклассах
  • Exec — функция может быть вызвана из консоли движка.
  • Native -функция реализована в С++ коде

Модификаторов очень много и для разных версий движка они разнятся с их списком можно ознакомится по адресу http://wiki.beyondunreal.com/Functions#Modifiers


Параметры функции описываются следующим образом:
[parameter modifiers] type parametername[arraysize]

parameter modifiers модификаторы, влияющие на поведение входящих параметров, type тип передаваемого параметра, parametername имя параметра, arraysize, если передаётся массив, то здесь указываем его размер.
Модификаторов для параметров гораздо меньше, основных всего два:
  • optional — указывает что данный параметр опционален и позволяет задать значение по умолчанию
  • out — указывает, что значение параметра может быть изменено внутри функции, это очень близко аналогу передачи значения по ссылке, но это не совсем оно.

States (состояния) и латентные функции

Если всё, что описано до этого встречается во всех ООП языках, но вот states(состояния) — это особенность UnrealScript. В игровой механике много вещей строится на состояниях. Например, ваш персонаж может находится в нескольких состояниях: стоять, сидеть, лежать. В каждом состоянии некоторые варианты действий будут отличатся, например скорость передвижения, возможность подпрыгнуть, итд. Существует несколько вариантов, чтобы это реализовать, например, при команде прыжка проверять в каком сейчас состоянии игрок и может ли он это сделать, а уже потом принимать решение о том прыгнет он, или просто встанет в полный рост. UnrealScript нам предлагает другой вариант. Мы описываем состояния, в которых может находится наш класс и в этих состояниях описываем функции, которые будут вызываться взамен обычных функций, если игрок находится в этом состоянии. Описывается состояние так:
[modifiers] state statename [extends parentstate] {
  ...
};

modifiers — модификаторы, на этот раз из всего два:
  • Auto — экземпляр класса автоматически переходит в это состоянии при создании.
  • Simulated — говорит, что состояние может быть выполнено на клиенте при репликации
statename — имя состояния
parentstate — указывает, что расширяет собой другое состояние.
Скрытый текст
class example extends actors;

function test(){
    log("No state");
}

state StateOne
{
    function test(){
        log("In state one");
    }
}

state StateTwo
{
    function test(){
        log("In state Two");
    }
}

state StateThree
{
    function test(){
        log("In state Three");
    }
}

Суть такова вызывая метод test мы получим вывод в консоль текущего состояние объекта в зависимости. Всё довольно просто. Также мы можем описать в состоянии набор команд который выполняется когда мы в него переходим
state StateOne
{
    function test(){
        log("In state one");
    }
    log("Going into StateOne");
}

В итоге когда объект перейдёт в состояние StateOne мы получим увидим в консоли строку Going into StateOne.
Состояние очень гибкая вещь но нужно аккуратно с ними работать чтобы не запутаться когда и что происходит.

Также в UnrealScript есть такое понятие — латентные функции. Латентные функции это функции, на выполнение которых уходит определённое количество игрового времени. Например функции Sleep, которая приостанавливает выполнение команд на определённое время. Вызывать латентные функции можно только внутри состояний. Пока состояния вам вряд ли пригодятся, но о них надо помнить, особенно, учитывая что они наследуются.

Работа со скриптами


Как можно было заметить, язык UnrealScript похож на другие ООП ничего сверх естественного в нём нет. Есть много нюансов но в целом ничего экстраординарного, и боятся его не стоит. Поэтому давайте теперь разберёмся как скрипты создавать и компилировать, Есть два пути один из них через UnrealEd, но по моему это не самый удобный вариант, по этому будем учится делать это при помощи ucc.

Немного о том что такое пакеты

UnrealEngine все свои ресурсы (текстуры, модели, звуки, музыка(не всегда), скрипты итд,) хранит в пакетах. Пакеты в зависимости от типа могут иметь разные расширения utx/umx/usx/u, однако, это всё одинаковые пакеты — разделение идёт для удобства. Из этого выплывает первый казус, никогда не делайте два пакета с одинаковыми имена, но отличающиеся расширением, движок будет видеть нормально только один из них. Также появляется второй момент — в пакете может хранится всё, что угодно ( то есть там могут быть звуки, текстуры и скрипты одновременно).

Создаём свой первый пакет

Итак чтобы создать свой пакет со скриптами при помощи ucc нам нужно в корне с игрой(не путать каталог System игры, корень на каталог выше) создать каталог и назвать его именем будущего пакета например TestPack. Теперь в этом каталоге нужно создать подкаталог Classe и уже там создавать наши скрипты. Одно из условий движка это то что один файл должен содержать описание одного класса, его имя должно быть как у имени описываемого класса и иметь расширение .uc
Создадим теперь файл с названием test.uc и содержимым:
class Test extends Commandlet;

event int Main( string Parms ){
 log("Hello World!");
 return 0;
}
Что такое Commandlet
Commandlet — это специальные класс, который позволяет запускать себя через оболочку ucc. Сам движок содержит в себе довольно много утилит которые выполнены в виде коммандлетов, А вышеописанным классом мы сделали свой который выводит всеми любимый Hello World в консоль.

Теперь нужно собрать наш пакет, для этого переходим в каталог System и там находим основной ini файл, он будет называтся также как .exe файл выбранной игры то есть UT2004 это UT2004.ini, а для UnrealEngine2Runtime это UE2Runtime.ini Отрываем его и ищем секцию Editor.EditorEngine в этой секции находим строки вида EditPackages=… и дописываем ещё одну строку EditPackages=TestPack, закрываем файл. Выполняем в консоли в каталоге игры команду ucc make, и, если всё сделано верно, то получим вывод наподобие такого:
ucc make
D:\Upload\UnrealEngine2Runtime\System>ucc make
--------------------Core - Release--------------------
--------------------Engine - Release--------------------
--------------------Fire - Release--------------------
--------------------Editor - Release--------------------
--------------------UnrealEd - Release--------------------
--------------------IpDrv - Release--------------------
--------------------UWeb - Release--------------------
--------------------GamePlay - Release--------------------
--------------------GUI - Release--------------------
--------------------Runtime - Release--------------------
--------------------RTInterface - Release--------------------
--------------------TestPack - Release--------------------
Analyzing...
Parsing test
Compiling test
Importing Defaults for test
Success - 0 error(s), 0 warning(s)


Теперь мы можем выполнить команду ucc TestPack.Test и увидеть работу нашего коммадлета, а именно вывод HelloWorld!.. Поздравляю первый пакет создан.

Маленькие хитрости

ucc make не будет пересобирать уже созданные пакеты, даже, если вы измените исходники, для того чтобы он пересобрал пакет, удалите уже собранный. Я для удобства пишу простые .bat которые пересобирают нужные мне пакеты.
Редактором кода может быть любой текстовый редактор, но есть и специализированные мне в этом плане очень приглянулся WOTgreal. В нем есть подсветка синтаксиса, вывод дерева исходников по пакетам и по наследуемым классам, и прочие полезности.
Также можно получить большую часть кода игровых классов, запустите UnrealEd, перейдите в ActorBrowser и выберите File->Export All Script. По окончанию процесса в корне игры увидите каталоги для пакетов, содержащие уже использующиеся игрой скрипты. Выведены будут только те пакеты, которые были загружены в редактор, если чего-нибудь нет, попробуйте загрузить нужный пакет отдельно и повторить процесс. Не стоит пытаться пересобрать игровые пакеты, большинство из них содержит ссылки на Native код, поэтому не смогут собраться.

Иерархия и часто используемые классы


Пришло время поговорить о иерархии классов в UnrealEngine. Корневым является класс Object от него уже наследуются все основные классы. Object — содержит в себе описание основных структур движка и некоторых системных методов. Не стоит пытаться пересобрать игровые пакеты, большинство из них содержит ссылки на Native код, поэтому не смогут собраться. Вторым по важности является именно класс Actor. В нём описаны базовые возможности всех объектов, которые могут быть добавлены на уровень — их свойства, перемещение, физика репликация и прочее. Все остальные объекты, которые добавляются на уровень наследуются от этого класса. Ниже я пишу назначение основных классов, с которыми вам придётся столкнутся.

Actor

Базовый класс для всех остальных игровых объектов. В нём описаны типы физики, освещения, сетевой роли и прочего, класс обязательно надо изучить хотя бы по диагонали. В нём объявлены функции PreBeginPlay и PostBeginPlay, которые в дальнейшем используются всем подклассами для инициализации.

GameInfo

GameInfo — класс отвечает за правила игры, ее начало и окончание, задаёт класс управление для игроков, а также контролирует их подключение и отключение от игры. Функции которые стоит изучить для PreLogin, Loging, PostLogin, Logout. A также переменные HUDType — устанавливает класс HUDa; PlayerControllerClassName — устанавливает класс PlayerController; bDelayedStart — сразу ли стартует игра или по после какого либо условия.

Pawn

Pawn(пешки) — класс которым описываются акторы, принимающие непостредственное участие в игре, такие как боты, npc, игроки. В классе описано много функций, правда, почти все применительны к 3D экшенам. Если вы делаете нового персонажа, то наследовать вы его будете от этого класса. Особое внимание я бы обратил на переменную bSpecialCalcView, которая указывает кто отвечает за отображение камеры класс Pawn или класс PlayerController. Если установить в true, то будет вызываться функция SpecialCalcView вашего класса где вы сможете задать положение камеры.

PlayerController

PlayerController — класс, которые отвечает за обработку управления, сюда стекаются все нажатия кнопок, движение мышки, положение джойстика итд. Особое внимание заслуживает функция PlayerTick которая вызывается каждый тик, и PlayerCalcView которая отвечает за положение камеры если за неё не отвечает Pawn. Также следует иметь ввиду, что многие события сначала приходят именно сюда, а уже потом могут быть переданы в Pawn например NotifyBump, NotifyHitWall. За управление ботами отвечает класс AIController.

HUD

HUD — отвечает за отрисовку HUDa. Наиболее интересная функция — это PostRender, которая и выводит на экран весь HUD.

Заключение


Вот мы кратко и познакомились с UnrealScript. Язык очень мощный, но при этом простой. В целом вы уже готовы к тому, чтобы создать нужные вам подклассы и начинать делать свою игру, или презентация, или совой вариант управление умным домом как это сделал stdamit в статье Unreal LED, или управление нагрузкой из Unreal Tournament. Основная задача этой статьи — показать что UnrealScrip это не страшно, и, надеюсь, я с этим справился.

Ссылки для ознакомления

http://wiki.beyondunreal.com/
UnrealScript. Справочное руководство
UnrealScript. Справочное руководство. Часть вторая

PS. В следующей части мы поговорим о репликации, о том что это такое, для чего нужна и как использовать.
Tags:
Hubs:
+6
Comments 3
Comments Comments 3

Articles