ruggaraxe ruggaraxe

Jusper, Спасибо! По железу средней требовательности. Достаточно Intel Core i5 и 16 Гб ОЗУ и карту типа Geforce 1050. Это так, навскидку. Детально пока не замеряли.

Jusper Jusper

Девблог интересный. Статичный скриншоты очень доставляют.
Сильно игрушка сейчас требовательна к железу?

alexprey alexprey

Скриншоты великолепны!)

yo_serjio yo_serjio

alexprey, редактор зданий да) с возможностью шейрить прессеты другим людям)
На данном этапе можно только пристрои делать, поддержка полной смены архитектуры в будущем планируется)

Mariya Mariya

Всем привет!
Новый ролик на движке. Сегодня мы покажем Вам бытовые сцены из жизни Сырны, и то как мы расставили мебель в ее домике.

RedHelium RedHelium

Работаю над освещением и над игровым контроллером, скоро приступлю к разработке прототипа города. Пока некоторые наброски..

alexprey alexprey

О это что то вроде редактора зданий? Можно самостоятельно новые дома собирать?

yo_serjio yo_serjio

Jusper, yo_serjio, через воркшоп будет потом работать?
Пока что, работает перебросом текстового файла с городом, в теории должно и сообщением передаваться.

Jusper Jusper

yo_serjio, через воркшоп будет потом работать?
Пока что, работает перебросом текстового файла с городом, в теории должно и сообщением передаваться.

yo_serjio yo_serjio

Jusper, подстроить дизайн домов под себя, если не нравится стандартный) можно же будет летать в чужие города, персонализайия в этом плане сыграет только на руку)

Jusper Jusper

Вернул тебе ссылку на ич, невалидная была.
Выглядит оч круто. Надо пощупать. А в чем смысл такого редактора в игре? Что можно будет делать?

Tartal Tartal

Попробовал воплотить злодея-пришельца (раса до сих пор без названия) для Exterminator'а в 3D, скетч которого я недавно показывал здесь:

EfReeZe EfReeZe

SINILIAN, привет, мультфильм "Планета сокровищ". Рекомендую :)

Mariya Mariya

Всем привет!
Сегодня хочу показать Вам полный комплект мебели для домика Сырны.

Wings' might Wings' might

Всем привет друзья, на этой неделе я добавил отображение урона, критические удары; обновил интерфейс магазина и изменил меню способностей

Следить за ежедневными изменениями: https://vk.com/wingsmight

Razz Razz

Сбегаем от контролёра
https://vk.com/iron_meat_game

SINILIAN SINILIAN

С приветом)) Что за мульт или фильмец?
(последний трек если что)

Mariya Mariya

Всем привет!
В мире Сырны появилось второе живое существо - лягушка!

Wings' might Wings' might

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

Логотип проекта Unreal Engine

Акторы как переменные

Наконец-то удалось победить лень и допилить данную подстатью

В одной из предыдущих частей статьи, когда я рассказывал о типах переменных, я не упомянул тип, который используется в UnrealScript едва ли не чаще всех остальных. В этой подстатье я наверстаю утраченное, тем более, что с этой темой мы уже немного соприкасались в предыдущей подстатье, когда делали видимым Павна, и убирали гигантскую пушку. Речь пойдет об использовании в качестве переменных Акторов.

Прошу подметить, что эта статья является исключительно экспериментальной, и никаких изменений в игру не принесет, но требуется для нормального понимания некоторых аспектов US.


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

class TestActor extends Actor;

defaultproperties
{
     Begin Object Class=SpriteComponent Name=Sprite
     Sprite=Texture2D'EditorResources.S_NavP'
     End Object
     Components.Add(Sprite)
}

Поскольку спавнить его мы будем непосредственно во время игры, мы больше не нуждаемся в ключе placeable. PostBeginPlay тоже можно убрать, так как с самым актором мы ничего не собираемся делать.

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

exec function StartFire( optional byte FireModeNum )
{
     super.StartFire(FireModeNum);
}

FireModeNum в этой функции отвечает за соответственный режим стрельбы, например, плазменные сгустки или плазменный луч в нашем стартовом оружии. Но для нас это не важно, важно только, чтобы вызывалась "супер"-версия функции.

Теперь объявим новую переменную в нашем TestPlayerController, а типом укажем TestActor

var TestActor MyTestActor

Если у вас возникнет вопрос, какое же значение принимают акторы по умолчанию, то это легко проверить, дополнив функцию PostBeginPlay нашего TestPlayerController соответственной строчкой вывода.

simulated function PostBeginPlay()
{
     super.PostBeginPlay();
     bNoCrosshair = true;
     `log(MyTestActor @ "<-- Default for MyTestActor");
}
class TestPlayerController extends UTPlayerController;

var TestActor MyTestActor;
var vector PlayerViewOffset;

simulated function PostBeginPlay()
{
     super.PostBeginPlay();
     bNoCrosshair = true;
     `log(MyTestActor @ "<-- Default for MyTestActor");
}

exec function StartFire( optional byte FireModeNum )
{
     super.StartFire(FireModeNum);
}

simulated event GetPlayerViewPoint(out vector out_Location, out Rotator out_Rotation)
{
     super.GetPlayerViewPoint(out_Location, out_Rotation);
     if(Pawn != none)
     {
          Pawn.Mesh.SetOwnerNoSee(false);
          if(Pawn.Weapon != none)
          Pawn.Weapon.SetHidden(true);
          out_Location = Pawn.Location + PlayerViewOffset;
          out_Rotation = rotator(Pawn.Location - out_Location);
     }
}

function Rotator GetAdjustedAimFor( Weapon W, vector StartFireLoc)
{
     return Pawn.Rotation;
}

defaultproperties
{
     PlayerViewOffset=(X=-64,Y=0,Z=1024)
}

Немало уже набралось, не правда ли? Вот именно по этому, переменным стоит давать четкие ясные имена, дабы не путаться.

Скомпилируйте код и проверьте наш лог. Найдете там следующее:

[0008.17] ScriptLog: None <-- Default for MyTestActor

Как видим, для акторов значение по умолчанию - None. Где-то мы уже это видели. Мы использовали это слово в нашем "контроле потока", чтобы спрятать оружие павна:

if(Pawn.Weapon != none)
     Pawn.Weapon.SetHidden(true);

В конкретном случае, у павна есть актор-переменная, под именем Weapon. Можно найти ее в коде класса Pawn

/** Weapon currently held by Pawn */
var Weapon Weapon;

Как видите, переменной можно спокойно давать имя, сходное с классом, но тогда весьма легко запутаться. Именно поэтому я назвал нашу переменную MyTestActor - легко понять, что это переменная, при этом сразу же определив ее класс.

Мы проверили, является ли переменная Weapon каким-либо актором. Если да, то условие исполняется, и ход программы идет дальше.

Стоит подметить, что, с одной стороны, далеко не все акторы являются переменными в каком-то классе, а с другой - объявление новой переменной-актора в классе не создает этот самый актор. Переменные-акторы являются лишь методом привязать существующие акторы к какому-либо классу. К примеру, в предыдущых подстатьях мы размещали наш TestActor на уровне просто в редакторе, и не было никаких переменных, связанных с ним.

Так как же присваивать переменной значение в виде актора? Тут есть несколько способов. Первый - приравнять переменную определенного класса к другой переменной этого же класса. Например, создадим переменную типа Weapon в нашем TestPlayerController.

var Weapon AnotherWeaponVariable;

PostBeginPlay в нашем случае срабатывает слишком рано, следовательно, не советую им пользоваться. А вот StartFire на подходит по всем параметрам - можно выводить значение переменной каждый раз, когда мы стреляем. Измените эту функцию следующим образом:

exec function StartFire( optional byte FireModeNum )
{
     super.StartFire(FireModeNum);
     AnotherWeaponVariable = Pawn.Weapon;
     `log(AnotherWeaponVariable);
}

Скомпилируйте, запустите игру, выстрелите (неважно сколько раз), и проверьте лог.

[0005.79] ScriptLog: UTWeap_LinkGun_0

С этой строчки можно сделать два вывода. Первый - синтаксис названий нам уже встречался, когда мы ставили два TestActor на уровне: прочерк и порядковый номер. Второй - несмотря на то, что переменная типа Weapon, нам выдало именно UTWeap_LinkGun_0, с чего можно сделать итог, что переменной определенного класса можно также присваивать его подклассы, что весьма упрощает создание игры (вместо создания переменной под каждый тип оружия, мы обходимся одной переменной "материнского" класса).

Теперь, когда AnotherWeaponVariable является равной переменной Pawn.Weapon, мы можем оперировать ею точно так же, как и Pawn.Weapon. Например, следующий код:

if(Pawn.Weapon != none)
     Pawn.Weapon.SetHidden(true);

можно спокойно заменить на

if(AnotherWeaponVariable != none)
     AnotherWeaponVariable.SetHidden(true);

Но мы этого делать не будем (а зачем?).

Важно помнить, что даже если мы присвоили AnotherWeaponVariable значение Pawn.Weapon, мы сделали это только один раз. Если Pawn.Weapon изменится, это не значит, что изменится AnotherWeaponVariable. Чтобы было яснее, гламурный пример о цвете: припустим, тваш любимый цвет пурпурный. Далее, я говорю, что мой любимый цвет такой же, как и ваш, то есть, пурпурный. Но потом вы поменяли свой любимый цвет на синий. Но это же не значит, что мой любимый цвет тоже поменялся на синий, до тех пор, пока я снова не скажу, что мой любимый цвет такой же, как и ваш. //Знаю, что пример несколько бредовый, но так было в оригинале.


Второй метод присвоить переменной актор - создать актор самому. Поменяем нашу функцию StartFire следующим образом:

exec function StartFire( optional byte FireModeNum )
{
     super.StartFire(FireModeNum);
     MyTestActor = spawn(class'TestActor',,, Pawn.Location);
     `log(MyTestActor @ "<-- MyTestActor");
}

Мы использовали функцию spawn, давайте же посмотрим, как она работает:

native noexport final function coerce actor Spawn
(
     class<actor> SpawnClass,
     optional actor SpawnOwner,
     optional name SpawnTag,
     optional vector SpawnLocation,
     optional rotator SpawnRotation,
     optional Actor ActorTemplate,
     optional bool bNoCollisionFail
);

Как видим, единственным обязательным параметром является только первый - класс актора, который мы спавним. Остальные являются необязательными. Но нам же нужно указать, где будет спавниться этот актор, а это четвертый параметр, SpawnLocation, в качестве которого мы указываем Pawn.Location - расположение самого павна. Вот тут важно запомнить, что, даже если мы можем пропускать необязательные параметры, если нам нужен, к примеру, только четвертый необязательный параметр, то мы должны указать, что это именно четвертый параметр, именно поэтому после первого параметра стоят три запятые. Следующие же переменные можно пропустить. Помимо прочего, мы можем сразу же присвоить свежеспеченный актор как значение соответственной переменной, что мы и сделали.

Скомпилируйте, запустите игру, постреляйте несколько раз, и посмотрите что будет.

Акторы как переменные — Unreal Engine — DevTribe: Разработка игр

Как видим, все исправно спавнится. Теперь заглянем в лог:

[0007.76] ScriptLog: TestActor_0 <-- MyTestActor
[0008.11] ScriptLog: TestActor_1 <-- MyTestActor
[0008.52] ScriptLog: TestActor_2 <-- MyTestActor
[0008.81] ScriptLog: TestActor_3 <-- MyTestActor
[0021.36] ScriptLog: TestActor_4 <-- MyTestActor

Ка видим, каждый раз когда мы спавним новый актор, он присваивается нашей переменной, заменяя старое значение, и при этом старые акторы не исчезают.


Еще один способ присвоить значение переменной-актору - итераторы. Итератор - функция, схожая с циклом, вот только вместо условия, она выполняет свои действия по разу на каждый экземпляр определенного класса. То есть, необходимо, чтобы акторы этого класса уже существовали в игре. Давайте разместим один TestActor на уровне. Не забудьте вернуть placeable в первую строчку, чтобы сделать размещение возможным.

Для того, чтобы итератор нашел наш актер, можно воспользоваться PostBeginPlay в контроллере:

simulated function PostBeginPlay()
{
     super.PostBeginPlay();
     bNoCrosshair = true;

     foreach DynamicActors(class'TestActor', MyTestActor)
          break;

     `log(MyTestActor @ "<-- MyTestActor");
}

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

[0004.62] ScriptLog: TestActor_0 <-- MyTestActor

Красота. Все работает как надо.


В общем, использование акторов в качестве переменных сильно упрощает создание игры, так как без него было бы очень трудно прописывать взаимодействия между игровыми элементами, весь код не выглядел бы таким цельным и т.д.. Как и в случае с обычными переменными, тут применимы операторы != и ==, а также массивы. Если актор присвоенный переменной, у программиста есть доступ ко всем его параметрам, делая возможным его изменение не только через меню свойств в редакторе, но и через код. С другой стороны, нельзя использовать их в свойствах по умолчанию, так как классы - всего лишь схемы для еще несуществующих объектов.


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



Когда вставляю AnotherWeaponVariable = Pawn.Weapon; выдает ошибку при компиляции:
C:\UDK\UDK-2012-10\Development\Src\TestGame\Classes\TestPlayerController.uc(16) : Error, 'AnotherWeaponVariable': Bad command or expression

Heroic_Pizza, без навыков дебага вы не станете нормальным программистом. Проблему легко решить, зная в чем она заключается. "Bad command or expression" - уже с перевода ясно, что компилятор просто не знает переменной "AnotherWeaponVariable", и это может значить только одно - эта переменная у вас не объявлена. Проверьте, есть ли у вас строчка

var Weapon AnotherWeaponVariable;

lentinant, так вот зачем их нужно объявлять. Теперь я чуть ближе к цели, спасибо, заработало.

Я прочитал все статьи, чем то UnrealScript схож на cJass как в Warcraft 3, хотя есть и функции, которых в нем нет :)