Создание новой сущности
Материал из CryWiki Russia
(→Создание новой entity (сущности)) |
|||
Строка 49: | Строка 49: | ||
{{Warning | {{Warning | ||
- | |Из-за того, что | + | |Из-за того, что Sandbox не любит редактирование и перезагрузку entities из нашей папки с модом, мы создадим нашу entity непосредственно внутри корневой Crysis/Game/ папки. А когда наша entity готова, мы перенесём её в папку мода. |
}} | }} | ||
Строка 121: | Строка 121: | ||
- | Также отметим, что наш clrColor находится в другой таблице Свойств. Таким путем у нас будет субкатегория в | + | Также отметим, что наш clrColor находится в другой таблице Свойств. Таким путем у нас будет субкатегория в Sandbox. После наших Свойств идут Свойства в Редакторе. Здесь мы размещаем иконку, которую Sandbox будет использовать. |
{{SimpleBox|<nowiki> Editor = { Icon= "Target.bmp", }, </nowiki>}} | {{SimpleBox|<nowiki> Editor = { Icon= "Target.bmp", }, </nowiki>}} |
Текущая версия на 18:07, 18 января 2012
|
Содержание |
Создание новой entity (сущности)
В этом документе мы пойдем пройдём путь создания новой сущности entity (в Lua), с поддержкой флоуграфа. Я буду использовать MyMod и MyEntity для идентификации нашего мода и нового entity. Конечно, Вы можете изменить его на что угодно.
Lua компилятор
Удобно иметь компилятор Lua для проверки синтаксических ошибок в файлах скриптов. Кроме того, кнопка "Reload Script 'в Sandbox исполняет это.
Lua компилятор можно взять тут LuaCompiler.
Скачайте файл и следуйте инструкции по установке.
Настройка entity
Теперь, давайте начнем. Прежде всего создадим папку модов. Перейдите к папке Crysis и создайте папку Mods. В этой папке создать MyMod папку. Далее, давайте создадим ярлык в этой папке, так что мы можем запустить редактор загрузки нашего мода. Мы должны добавить -MOD MyMod (где MyMod это пример имени нашего мода везде дальше по тексту) в ярлык поэтому чтобы редактор знал, какой мод надо запустить. Это может быть что-то вроде:
"C:\Program Files\Electronic Arts\Crytek\Crysis\Bin32\Editor.exe" -MOD MyMod |
После этого, мы должны сообщить движку, что у нас новая entity, которая должна быть загружена. Нам нужно создать новую папку в нашей мод-директории: Game и внутри другая новая директория: entities. В этой папке создаем новый файл и называем, например, MyEntity.ent. (где MyEntity это имя нового entity).
Теперь давайте отредактируем MyEntity.ent в любом текстовом редакторе на выбор. Вот что должно прежде всего быть написано в файле:
<Entity Name="MyEntity" Script="Scripts/Entities/MyMod/MyEntity.lua" /> |
Рассмотрим подробнее. Это простой xml файл с именем внутри и локализацией пути к .lua файлу. Мы создадим этот скрипт-файл в следующей главе. А теперь давайте обратимся к написанию скриптовой части.
Скрипты entity (основы)
Теперь, когда у нас есть установочная часть для entity, нам необходимо создать lua файл для неё. Lua файл будет содержать код и свойства нашей entity. Если вы посмотрите в MyEntity.ent файл, вы увидете путь Scripts/Entities/MyMod/MyEntity.lua. Нам нужно создать этот файл, который сейчас не существует.
Предупреждение:
Из-за того, что Sandbox не любит редактирование и перезагрузку entities из нашей папки с модом, мы создадим нашу entity непосредственно внутри корневой Crysis/Game/ папки. А когда наша entity готова, мы перенесём её в папку мода.
Создадим новый файл в Crysis/Game/Scripts/Entities/MyMod/
(создайте директории если необходимо).
Имя файла должно быть MyEntity.lua, что определено в нашем файле MyEntity.ent. Теперь у нас есть новый файл, откроем его текстовым редактором. Я теперь пойду шаг за шагом и буду анализировать код который мы должны напечатать. Если хотите, можете скопировать и вставить целый файл в конце данного руководства.
Lua
MyEntity = { Properties = { fMessageDuration = 10.0, sMessage = "Use me", bDoesNothing = 0, object_MyModel = "Editor/Objects/objective.cgf", Colors = { clrColor = {x=1, y=0, z=0 }, }, }, Editor = { Icon= "Target.bmp", }, };
Давайте слегка изучим этот код. Для начала мы определяем нашего entity при помощи
MyEntity = { … } |
Следующим шагом мы настраиваем его Свойства. Всё что внутри будет свойствами, которые можно настроить в редакторе Sandbox, как на картинке справа, которые являются свойствами Торнадо entity. Эти свойства:
fMessageDuration | Это время в течение которого сообщение будет показываться при использовании нашего entity. |
sMessage | Само показываемое сообщение. |
bDoesNothing | Это реально ничего не делает does nothing |
object_MyModel | Модель которую имеет наша entity |
clrColor | Цвет сообщения |
Несколько вещей на заметку: наши переменные имеют префиксы типа f,s,b,clr,object_ . На то есть причина. Это позволяет сандбоксу знать какого рода это переменная. Таким образом мы не можем передать словами в нашей последовательности, мы получаем открытый диалог для наших моделей и т.д… Здесь небольшой список наиболее часто встречающихся префиксов:
b | boolean |
s | string |
f | float |
object_ | model(with file open dialog) |
clr | Color (with colorpick dialog) |
Также отметим, что наш clrColor находится в другой таблице Свойств. Таким путем у нас будет субкатегория в Sandbox. После наших Свойств идут Свойства в Редакторе. Здесь мы размещаем иконку, которую Sandbox будет использовать.
Editor = { Icon= "Target.bmp", }, |
После этого мы можем также определить некоторые собственные переменные которые вы можете использовать в скриптах. Но в этом руководстве таковых мы не используем.
Мы уже можем заглянуть в редактор, и я предлагаю вам сделать это. Таким образом, мы можем проверить, есть ли наши файлы в нужном месте, и что редактор загружает наш файл.
Так что зайдите в папку мода которую мы создали и запустите редактор через созданный ярлык для сандбокса. Нет необходимости в загрузке карты, в роллапбаре (панель справа) выберите Entity и там в списке должна быть наша entity обнаруживаемая в карте под названием MyMod. Если нету, что-то не правильно. Проверьте что вы всё сделали правильно, загрузили редактор с помощью ярлыка, сделали .ent файл, сделали .lua. Если щелкнуть 2 раза по нашей entity, вы должны увидеть наши Свойства, которые мы определили в lua файле:
Здесь мы также видим, что сделали префиксы. Также обратите внимание, что всё отсортировано в алфавитном порядке без префиксов.
Теперь наша Entity имеет некоторые свойства, но ничего не делает. Вы даже можете попытаться добавить модель, которую она не показывала. Давайте сначала закодируем её. (нет необходимости закрывать редактор сейчас, мы можем оставить его открытым для быстрого дебага). Откроем снова MyEntity.lua скрипт и добавим:
Lua
function MyEntity:OnInit() self:OnReset(); end
Функция OnInit вызывается когда наша entity инициализируется, типично при загрузке карты. Мы вызываем функцию называемую OnReset(), которую мы сейчас сделаем.
Lua
function MyEntity:OnReset() if (self.Properties.object_MyModel ~= "") then self:LoadObject(0, self.Properties.object_MyModel); end end
Необходимо ещё кое-что пояснить. Функция вызывается сама по себе, когда мы заходим в редактор. (Мы также вызываем её из OnInit здесь, что вполне обычно)
Это первое проверяет, не является ли модель пустым string. После этого она загружает модель. Теперь сохраните свой файл. Вернемся в редактор. Откроем карту, если вы ещё не открыли. Поместим MyEntity entity на ней. Вы должны увидеть модель Если нет – перезагрузите скрипт entity нажав кнопку Reload Script. Теперь постарайтесь изменить модель снова. Похоже, что не работает. Мы должны добавить ещё немного кода для этого.
Lua
function MyEntity:OnPropertyChange() self:OnReset(); end
OnPropertyChange() вызывается всякий раз, когда мы меняем Свойства в редакторе. Из-за этого мы должны перезагрузить модель. Таким образом, вызываем OnReset снова, что загрузит новую модель.
Посмотрим на то, что мы сейчас имеем. Entity, которая имеет модель, мы можем менять эту модель но на этом – всё. Она ничего не делает. Сделаем так, чтобы мы могли использовать нашу entity.
Lua
function MyEntity:IsUsable(user) return 2; end function MyEntity:GetUsableMessage(idx) return self.Properties.sMessage; end
Первая функция IsUsable() возвращает 2. Это позволяет использовать нашу entity. Вторая функция определяет, какое сообщение мы получим, когда захотим использовать entity. Мы возвращаем сообщение, которое мы установили в наши Свойства. Теперь наша entity может быть использована, но всё ещё не будет ничего делать. Для этого нам нужно, как вы догадались, кодировать дальше.
Lua
function MyEntity:OnUsed(user, idx) CryAction.Persistant2DText( string.format("Used> %s", self.Properties.sMessage), 2, self.Properties.Colors.clrColor, "OnUsed", self.Properties.fMessageDuration ); end
Это будет появление сообщения на нашем экране. Сообщение будет “Used: OurMessage”, OurMessage заменяется на сообщение указанное в Свойствах.
Следующий аргумент – это размер сообщения, текущий размер равен 2.Следующий аргумент это цвет, мы также получаем его из свойств.
4-й аргумент это имя сообщения, 5-й и последний аргумент – это длительность нашего сообщения в секундах.
Можем протестировать теперь, вернемся в редактор, нажмем перезагрузку скрипта и прыгнем в игру. Подойдем к нашей entity и нажмем ‘f’. Мы должны увидеть сообщение, определенное в её свойствах. Постарайтесь изменить некоторые из переменных в свойствах на панели и прыгните в игру, чтобы посмотреть результаты.
Вот что у вас теперь должно быть:
Lua
MyEntity = { Properties = { fMessageDuration = 10.0, sMessage = “Use me”, bDoesNothing = 0, object_MyModel = "Editor/Objects/objective.cgf", Colors = { clrColor = {x=1, y=0, z=0 }, }, }, Editor = { Icon= "Target.bmp", }, }; function MyEntity:OnInit() self:OnReset(); end function MyEntity:OnReset() if (self.Properties.object_MyModel ~= "") then self:LoadObject(0, self.Properties.object_MyModel); end end function MyEntity:OnPropertyChange() self:OnReset(); end function MyEntity:IsUsable(user) return 2; end function MyEntity:GetUsableMessage(idx) return self.Properties.sMessage; end function MyEntity:OnUsed(user, idx) CryAction.Persistant2DText( string.format("Used> %s", self.Properties.sMessage), 2, self.Properties.Colors.clrColor, "OnUsed", self.Properties.fMessageDuration ); end
Расширение нашей entity
Теперь у нас есть базовая entity, давайте добавим побольше интересного/продвинутого барахла. Будем базироваться на той entity, которую мы сейчас сделали. Сперва давайте сделаем нашу модель физической. Мы создадим новую функцию для этого PhysicalizeThis, и вызовем её в OnReset функции.
Lua
function MyEntity:OnReset() if (self.Properties.object_MyModel ~= "") then self:LoadObject(0, self.Properties.object_MyModel); end self:PhysicalizeThis(); -- Это новая строчка end function MyEntity:PhysicalizeThis() local Physics = { bRigidBody=1, bRigidBodyActive = 0, bRigidBodyAfterDeath =1, bResting = 1, Density = -1, Mass = 5, }; EntityCommon.PhysicalizeRigid( self, 0, Physics, 1 ); end
В PhysicalizeThis функции мы определяем физику, которая содержит некоторые переменные, которые вы должны увидеть из редактора. Затем мы пропускаем их с EntityCommon.PhysicalizeRigid(). И теперь наша модель имеет физику. Всё просто. Можем войти в редактор и опрокинуть нашу entity теперь. Одна из последних вещей, которые мы сделаем теперь, это клонирование нашей entity когда мы нажимаем на неё. Закодируем это. Нам нужно добавить код когда мы используем нашу entity, так что сделаем это и вызовем новую функцию.
Lua
function MyEntity:OnUsed(user, idx) CryAction.Persistant2DText( string.format("Used> %s", self.Properties.sMessage), 2, self.Properties.Colors.clrColor, "OnUsed", self.Properties.fMessageDuration ); self:Clone(); -- This is the new line end function MyEntity:Clone() local clone = { class = "MyEntity", }; clone.properties = self.Properties; local ent = System.SpawnEntity(clone); local pos = self:GetPos(); pos.x = pos.x + 1; ent:SetPos(pos); end
Это клонирует нашу entity. Сначала мы устанавливаем класс для MyEntity, который будет спавнить нашу entity с дефолтными параметрами. Т.к. нам нужны параметры установки нашей главной entity (main entity), то мы копируем наши собственные свойства (self). Когда мы спавним entity, берем позицию нашей главной entity (main entity) и увеличиваем значение x на 1. Это реально позволит нам увидеть, клонировалась она или нет. После этого мы устанавливаем позицию снова на нашу новую позицию. И закончив мы получили нашу клонирующую функцию.
Можем протестировать это в редакторе.
Добавление поддержки флоуграфа.
Для этой конкретной entity это немного глупо, но главное, это принцип. Вся информация по флоуграфу поступает в FlowEvents. Мы должны определить это, так что давайте сделаем таким образом.
Lua
MyEntity.FlowEvents = { Inputs = { Clone = { MyEntity.Event_Clone, "bool" }, Message = { MyEntity.Event_Message, "string" }, }, Outputs = { Used = "bool", }, }
Если посмотрим на это на секунду, окажется что ничего тяжелого. У нас есть части по входящим значениям инпутам (inputs) и выходящим значениям аутпутам (outputs). В части инпутов у нас есть Clone (клонирование) и Message (сообщение). В аутпутах у нас есть Used (использована) которая вызывается, когда мы использовали нашу entity. Но что вещи идут после Clone = и Message = ? MyEntity.Event_Clone и MyEntity.Event_Message, откуда они взялись? Вы правы, они взялись из ниоткуда, так что мы должны объявить некоторые функции.
Lua
function MyEntity:Event_Clone(sender) self:Clone(); end function MyEntity:Event_Message(sender, msg) self.Properties.sMessage = msg; end
Event_Clone просто вызывает нашу Clone функцию, которую мы сделали ранее. При помощи Event_Message мы можем изменить наше свойство sMessage из флоуграфа. Это покрывает инпуты, но как обрабатываются аутпуты? Нам надо добавить немного кода который вызывает это событие, и это довольно просто:
Lua
function MyEntity:OnUsed(user, idx) CryAction.Persistant2DText( string.format("Used> %s", self.Properties.sMessage), 2, self.Properties.Colors.clrColor, "OnUsed", self.Properties.fMessageDuration ); self:Clone(); self:ActivateOutput( "Used" ,true ); -- Это новая строчка end
Мы просто устанавливаем это Used значение, которое мы определили ранее в аутпутовских событиях флоуграфа и устанавливаем это на true (правда).
Таким образом наш флоуграф должен работать теперь. Давайте немного протестируем его. Войдём в редактор и перезагрузим нашу entity, потом кликнем Create button под Flowgraph. Зададим ему какое-нибудь имя и потом перейдем к полю флоуграфа. Теперь правой кнопкой мыши нажмем в поле и выберем ‘Add Graph Default Entity’. У нас есть entity в нашем флоуграфе теперь.
Давайте протестируем:
И теперь однажды использовав нашу entity мы увидим сообщение “Flowgraph is here”. Обратите внимание, что это будет показываться только для оригинальной entity. Таким образом суммируя вышесказанное, у нас есть новая entity которая не делает ничего выдающегося, но с поддержкой флоуграфа.
Полный код
Lua
MyEntity = { Properties = { fMessageDuration = 10.0, sMessage = "Use me", bDoesNothing = 0, object_MyModel = "Editor/Objects/objective.cgf", Colors = { clrColor = {x=1, y=0, z=0 }, }, }, Editor = { Icon= "Target.bmp", }, }; function MyEntity:OnInit() self:OnReset(); end function MyEntity:OnReset() if (self.Properties.object_MyModel ~= "") then self:LoadObject(0, self.Properties.object_MyModel); end self:PhysicalizeThis(); end function MyEntity:OnPropertyChange() self:OnReset(); end function MyEntity:IsUsable(user) return 2; end function MyEntity:GetUsableMessage(idx) return self.Properties.sMessage; end function MyEntity:OnUsed(user, idx) CryAction.Persistant2DText( string.format("Used> %s", self.Properties.sMessage), 2, self.Properties.Colors.clrColor, "OnUsed", self.Properties.fMessageDuration ); self:Clone(); end function MyEntity:PhysicalizeThis() local Physics = { bRigidBody=1, bRigidBodyActive = 0, bRigidBodyAfterDeath =1, bResting = 1, Density = -1, Mass = 5, }; EntityCommon.PhysicalizeRigid( self, 0, Physics, 1 ); end function MyEntity:Clone() local clone = { class = "MyEntity", }; clone.properties = self.Properties; local ent = System.SpawnEntity(clone); local pos = self:GetPos(); pos.x = pos.x + 1; ent:SetPos(pos); end function MyEntity:Event_Clone(sender) self:Clone(); end function MyEntity:Event_Message(sender, msg) self.Properties.sMessage = msg; end MyEntity.FlowEvents = { Inputs = { Clone = { MyEntity.Event_Clone, "bool" }, Message = { MyEntity.Event_Message, "string" }, }, Outputs = { Used = "bool", }, }