Создание новой сущности

Материал из CryWiki Russia

(Различия между версиями)
Перейти к: навигация, поиск
(Новая страница: «<!-- Please enter the information about your article for each section after the equal sign. The information will be translated into a formatted page upon b...»)
(Создание новой entity (сущности))
 
(4 промежуточные версии не показаны)
Строка 6: Строка 6:
{{Статья
{{Статья
|автор=ins
|автор=ins
-
|переводчик=Sodiet
+
|переводчик=Sodiet, AndreyFilantrop(текст статьи)
|сложность=Средняя
|сложность=Средняя
|совместимости=All
|совместимости=All
Строка 16: Строка 16:
<!-- The article's topic (Basic Level Design, Terrain...)-->
<!-- The article's topic (Basic Level Design, Terrain...)-->
-
}}
 
-
= Creating a new entity =
 
-
In this document we will go through creating a new entity (in Lua), with support for flowgraphs.
 
-
I’ll be using MyMod and MyEntity to identify our mod and the new entity. You can of course change this to whatever you like.
 
-
== Lua compiler ==
+
= Создание новой entity (сущности) =
-
It is handy to have a lua compiler to check for syntax errors in your script files. Also, the 'Reload Script' button in the Sandbox Editor uses this.
+
В этом документе мы пойдем пройдём путь создания новой сущности entity (в Lua), с поддержкой флоуграфа. Я буду использовать MyMod и MyEntity для идентификации нашего мода и нового entity. Конечно, Вы можете изменить его на что угодно.
 +
 
 +
== Lua компилятор ==
 +
Удобно иметь компилятор Lua для проверки синтаксических ошибок в файлах скриптов. Кроме того, кнопка "Reload Script 'в Sandbox исполняет это.
 +
 
[[Image:Lua_entity_tutorial_reloadscript.jpg]]
[[Image:Lua_entity_tutorial_reloadscript.jpg]]
-
You can get the lua compiler [http://www.crymod.com/attachment.php?attachmentid=7970 here].
+
Lua компилятор можно взять тут [http://crymod.net/index.php?page=DatabaseItem&id=98 LuaCompiler].
-
Extract LuaCompiler.exe to <crysis folder>/bin32/ or <crysis folder>/bin64/
+
Скачайте файл и следуйте инструкции по установке.
-
 
+
== Настройка entity ==
-
== Setting up an entity ==
+
Теперь, давайте начнем. Прежде всего создадим папку модов. Перейдите к папке Crysis и создайте папку Mods. В этой папке создать MyMod папку. Далее, давайте создадим ярлык в этой папке, так что мы можем запустить редактор загрузки нашего мода. Мы должны добавить -MOD MyMod (где MyMod это пример имени нашего мода везде дальше по тексту) в ярлык поэтому чтобы редактор знал, какой мод надо запустить. Это может быть что-то вроде:
-
Now, let's get started. First of all we’re going to create a mod folder. Browse to your Crysis folder and create a Mods folder. In that folder create a MyMod folder.
+
-
Next, let’s create a shortcut in that folder so we can launch the editor with our mod loaded. We have to add –MOD MyMod to the shortcut so the editor knows what mod to load. It could be something like this:
+
{{SimpleBox|"C:\Program Files\Electronic Arts\Crytek\Crysis\Bin32\Editor.exe" -MOD MyMod}}
{{SimpleBox|"C:\Program Files\Electronic Arts\Crytek\Crysis\Bin32\Editor.exe" -MOD MyMod}}
-
After that, we need to let the engine know we have a new entity which needs to be loaded. We will need to create a new folder in our mod-directory: Game, and in there another new dir: entities. In that folder create a new file called MyEntity.ent.
+
После этого, мы должны сообщить движку, что у нас новая entity, которая должна быть загружена. Нам нужно создать новую папку в нашей мод-директории: Game и внутри другая новая директория: entities. В этой папке создаем новый файл и называем, например, MyEntity.ent. (где MyEntity это имя нового entity).
-
 
+
Теперь давайте отредактируем MyEntity.ent в любом текстовом редакторе на выбор. Вот что должно прежде всего быть написано в файле:
-
Now let’s edit our created MyEntity.ent in a text-editor of your choice. This is the content that needs to be in the file:
+
{{SimpleBox| <nowiki><Entity Name="MyEntity" Script="Scripts/Entities/MyMod/MyEntity.lua" /></nowiki>}}
{{SimpleBox| <nowiki><Entity Name="MyEntity" Script="Scripts/Entities/MyMod/MyEntity.lua" /></nowiki>}}
-
Let’s look at that a bit closer. It’s just a simple xml file with the name in it, and the location to a .lua file. We will create that scriptfile in the next chapter. Let’s get to the scripting part.
+
Рассмотрим подробнее. Это простой xml файл с именем внутри и локализацией пути к .lua файлу. Мы создадим этот скрипт-файл в следующей главе. А теперь давайте обратимся к написанию скриптовой части.
-
== The entity script (basics) ==
+
== Скрипты entity (основы) ==
-
Now that we have the entity setup, we need to create the lua file for it. The lua file will contain the code and the properties of our entity. If you look at our MyEntity.ent file you can see the path Scripts/Entities/MyMod/MyEntity.lua. We need to create this file, as it doesn’t exist yet.
+
Теперь, когда у нас есть установочная часть для entity, нам необходимо создать lua файл для неё. Lua файл будет содержать код и свойства нашей entity. Если вы посмотрите в
-
 
+
MyEntity.ent файл, вы увидете путь Scripts/Entities/MyMod/MyEntity.lua. Нам нужно создать этот файл, который сейчас не существует.  
{{Warning
{{Warning
-
|Because Sandbox doesn’t like editing and reloading entities from our mod-folder, we will develop our entity inside the default Crysis/Game/ folder. Once our entity is ready, we can move it to our Mod folder.
+
|Из-за того, что Sandbox не любит редактирование и перезагрузку entities из нашей папки с модом, мы создадим нашу entity непосредственно внутри корневой Crysis/Game/ папки. А когда наша entity готова, мы перенесём её в папку мода.  
}}
}}
-
Let’s create a new file in Crysis/Game/Scripts/Entities/MyMod/ (create directories if needed). The file name should be MyEntity.lua, which is specified in our MyEntity.ent file. Now that we have our new file, open it in a text editor. I will now go step by step and analyze the code we have to type. If you want, you can copy and paste the whole file at the end of this tutorial.
+
Создадим новый файл в Crysis/Game/Scripts/Entities/MyMod/
 +
(создайте директории если необходимо).  
 +
Имя файла должно быть MyEntity.lua, что определено в нашем файле MyEntity.ent. Теперь у нас есть новый файл, откроем его текстовым редактором. Я теперь пойду шаг за шагом и буду анализировать код который мы должны напечатать. Если хотите, можете скопировать и вставить целый файл в конце данного руководства.
 +
 
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 75: Строка 75:
}}
}}
-
Let’s analyze that code a bit. First we define our entity with
+
Давайте слегка изучим этот код. Для начала мы определяем нашего entity при помощи
{{SimpleBox|<nowiki>MyEntity = { … }</nowiki> }}
{{SimpleBox|<nowiki>MyEntity = { … }</nowiki> }}
-
Next we set up our Properties. Everything in here will be properties you can adjust in the Sandbox editor, like in the picture on the right, which are the properties of the Tornado entity.
+
Следующим шагом мы настраиваем его Свойства. Всё что внутри будет свойствами, которые можно настроить в редакторе Sandbox, как на картинке справа, которые являются свойствами Торнадо entity. Эти свойства:
-
Our properties are:
+
{| style="border: 1px solid black; background-color: #3F3F3F"
{| style="border: 1px solid black; background-color: #3F3F3F"
|-
|-
| fMessageDuration
| fMessageDuration
-
| The time a message will be shown when we use our entity.
+
| Это время в течение которого сообщение будет показываться при использовании нашего entity.
|-
|-
| sMessage
| sMessage
-
| The actual message to show.
+
| Само показываемое сообщение.  
|-
|-
| bDoesNothing
| bDoesNothing
-
| This actually does nothing
+
| Это реально ничего не делает does nothing  
|-
|-
| object_MyModel
| object_MyModel
-
| The model that our entity has
+
| Модель которую имеет наша entity  
|-
|-
| clrColor
| clrColor
-
| The color of our message
+
| Цвет сообщения
|}
|}
-
A few things to note: our variables have prefixes like f,s,b,clr,object_ . They are there for a reason. It lets Sandbox know what kind of variable it is. That way we can’t put in text in our MessageDuration, we get a Open file dialog for our models, etc… . Here’s a small list with the most common prefixes:
+
Несколько вещей на заметку: наши переменные имеют префиксы типа f,s,b,clr,object_ . На то есть причина. Это позволяет сандбоксу знать какого рода это переменная. Таким образом мы не можем передать словами в нашей последовательности, мы получаем открытый диалог для наших моделей и т.д… Здесь небольшой список наиболее часто встречающихся префиксов:  
{| style="border: 1px solid black; background-color: #3F3F3F"
{| style="border: 1px solid black; background-color: #3F3F3F"
|-
|-
Строка 122: Строка 121:
-
Also note that our clrColor is in another table in the Properties table. This way we will have a subcategory in Sandbox. After our Properties come the Editor properties. Here we set the Icon which sandbox will use.
+
Также отметим, что наш  clrColor находится в другой таблице Свойств. Таким путем у нас будет субкатегория в Sandbox. После наших Свойств идут Свойства в Редакторе. Здесь мы размещаем иконку, которую Sandbox будет использовать.  
{{SimpleBox|<nowiki> Editor = { Icon= "Target.bmp", }, </nowiki>}}
{{SimpleBox|<nowiki> Editor = { Icon= "Target.bmp", }, </nowiki>}}
-
After that you can also set up some private variables which you can use in the scripts. But for this tutorial we won’t need those.
+
После этого мы можем также определить некоторые собственные переменные которые вы можете использовать в скриптах. Но в этом руководстве таковых мы не используем.
-
We can already take a peek in the editor, and I suggest you do so. That way we can check if our files are in the right place, and if the editor loads our file.
+
Мы уже можем заглянуть в редактор, и я предлагаю вам сделать это. Таким образом, мы можем проверить, есть ли наши файлы в нужном месте, и что редактор загружает наш файл.  
-
So browse to our mod folder we created and launch the editor via the shortcut to sandbox.
+
Так что зайдите в папку мода которую мы создали и запустите редактор через созданный ярлык для сандбокса. Нет необходимости в загрузке карты, в роллапбаре (панель справа) выберите  Entity и там в списке должна быть наша entity обнаруживаемая в карте под названием MyMod.
-
No need to load a map, in the rollup bar select Entity and there we should find our entity listed, nicely found in a map called MyMod.
+
Если нету, что-то не правильно. Проверьте что вы всё сделали правильно, загрузили редактор с помощью ярлыка, сделали .ent файл, сделали .lua.  
-
 
+
Если щелкнуть 2 раза по нашей entity, вы должны увидеть наши Свойства, которые мы определили в  lua файле:  
-
If that isn’t the case, something is wrong. Make sure you did everything right, launched the editor with our shortcut, made the .ent file, made the .lua file.
+
-
 
+
-
If you double click our entity you should see our properties we defined in the lua file:
+
[[Image:Lua_entity_tutorial_properties.jpg]]
[[Image:Lua_entity_tutorial_properties.jpg]]
-
Here you can also see what the prefixes have done. Also note that everything is sorted alphabetically, without prefixes.
+
Здесь мы также видим, что сделали префиксы. Также обратите внимание, что всё отсортировано в алфавитном порядке без префиксов.  
-
Now, our entity has some properties, but it doesn’t do anything. You can even try to set a model, it won’t show up. So let’s code that in first. (No need to close the Editor now, we can keep it open for quick debugging) Open the MyEntity.lua script again and add
+
Теперь наша Entity имеет некоторые свойства, но ничего не делает. Вы даже можете попытаться добавить модель, которую она не показывала. Давайте сначала закодируем её. (нет необходимости закрывать редактор сейчас, мы можем оставить его открытым для быстрого дебага). Откроем снова MyEntity.lua скрипт и добавим:
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 153: Строка 149:
}}
}}
-
The OnInit function gets called when our entity gets initialized, typically when loading the map. We call a function called OnReset(), which we will now make.
+
Функция OnInit вызывается когда наша entity инициализируется, типично при загрузке карты. Мы вызываем функцию называемую OnReset(), которую мы сейчас сделаем.
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 165: Строка 161:
}}
}}
-
There’s a bit more to explain now. The function gets called on its own when we jump into the editor. (We also call it from OnInit here, which is pretty common)
+
Необходимо ещё кое-что пояснить. Функция вызывается сама по себе, когда мы заходим в редактор. (Мы также вызываем её из OnInit здесь, что вполне обычно)  
-
This first checks if the model is not an empty string. After that it loads the model. Save your file now.
+
Это первое проверяет, не является ли модель пустым string. После этого она загружает модель. Теперь сохраните свой файл. Вернемся в редактор. Откроем карту, если вы ещё не открыли. Поместим MyEntity entity на ней. Вы должны увидеть модель Если нет – перезагрузите скрипт entity нажав кнопку Reload Script.
-
Let’s get back to the editor. Open a map if you didn’t do so yet. Place the MyEntity entity on it. You should see a model now. If not, reload the entity script via the Reload Script button.
+
Теперь постарайтесь изменить модель снова. Похоже, что не работает. Мы должны добавить ещё немного кода для этого.
-
Now try changing the model again. It doesn’t seem to work. We need to add some more code for that.
 
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 180: Строка 175:
}}
}}
-
OnPropertyChange() gets called whenever we change a property in the editor. Because of that, we need to reload the model. So we call OnReset again which will load the new model.  
+
OnPropertyChange() вызывается всякий раз, когда мы меняем Свойства в редакторе. Из-за этого мы должны перезагрузить модель. Таким образом, вызываем OnReset снова, что загрузит новую модель.  
-
 
+
Посмотрим на то, что мы сейчас имеем. Entity, которая имеет модель, мы можем менять эту модель но на этом – всё. Она ничего не делает. Сделаем так, чтобы мы могли использовать нашу entity.  
-
Let’s take a look at what we have by now. An entity which has a model, we can change that model, but that’s about it. It doesn’t do anything. Let’s make it so we can use our entity.
+
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 196: Строка 190:
}}
}}
-
The first function IsUsable() returns 2. This makes it so that we can use our entity. The second function defines what message we will get when we want to use the entity. We return the message we set in our properties. Now our entity will be useable, but it still won’t do anything. For that, we need, you guessed it, more code.
+
Первая функция IsUsable() возвращает 2. Это позволяет использовать нашу entity. Вторая функция определяет, какое сообщение мы получим, когда захотим использовать entity. Мы возвращаем сообщение, которое мы установили в наши Свойства. Теперь наша entity может быть использована, но всё ещё не будет ничего делать. Для этого нам нужно, как вы догадались, кодировать дальше.  
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 212: Строка 206:
}}
}}
-
What this does is print a message to our screen. The message is “Used: OurMessage”, OurMessage gets replaced with the message specified in the properties.  
+
Это будет появление сообщения на нашем экране. Сообщение будет “Used: OurMessage”, OurMessage заменяется на сообщение указанное в Свойствах.
 +
Следующий аргумент – это размер сообщения, текущий размер равен 2.Следующий аргумент это цвет, мы также получаем его из свойств.
 +
4-й аргумент это имя сообщения, 5-й и последний аргумент – это длительность нашего сообщения в секундах.  
-
Second argument is the size of our message, currently set to 2.  
+
Можем протестировать теперь, вернемся в редактор, нажмем перезагрузку скрипта и прыгнем в игру. Подойдем к нашей entity и нажмем  ‘f’. Мы должны увидеть сообщение, определенное в её свойствах. Постарайтесь изменить некоторые из переменных в свойствах на панели и прыгните в игру, чтобы посмотреть результаты.  
-
Next argument is the color, we also get it from the properties.
+
Вот что у вас теперь должно быть:
-
4th argument is the name of the message 5th and last argument is the duration of our message, in seconds.
 
-
 
-
We can try that out now, jump back to the editor, click the reload script button and jump ingame. Run up to our entity and press ‘f’. You should see the message specified in the properties. Try changing some of the values in the properties panel and jump ingame to see the results.
 
-
 
-
 
-
This is what you should have by now:
 
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
<source lang="lua">
<source lang="lua">
Строка 274: Строка 264:
-
== Extending our entity ==
+
== Расширение нашей entity ==
-
We have a basic entity now, let’s add some more interesting/advanced stuff. We will base this on the entity we just made. First, let’s make our model physicalized. We will make a new function for this called PhysicalizeThis, and call it in the OnReset function.
+
Теперь у нас есть базовая entity, давайте добавим побольше интересного/продвинутого барахла. Будем базироваться на той entity, которую мы сейчас сделали. Сперва давайте сделаем нашу модель физической. Мы создадим новую функцию для этого PhysicalizeThis, и вызовем её в OnReset функции.
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 283: Строка 273:
self:LoadObject(0, self.Properties.object_MyModel);
self:LoadObject(0, self.Properties.object_MyModel);
end
end
-
self:PhysicalizeThis(); -- This is the new line
+
self:PhysicalizeThis(); -- Это новая строчка
end
end
Строка 300: Строка 290:
}}
}}
-
In the PhysicalizeThis function we define Physics which contains some vars you should recognize from the editor. Then we pass them along EntityCommon.PhysicalizeRigid(). And now our model is physicalized, it’s that simple.  
+
В PhysicalizeThis функции мы определяем физику, которая содержит некоторые переменные, которые вы должны увидеть из редактора. Затем мы пропускаем их с EntityCommon.PhysicalizeRigid(). И теперь наша модель имеет физику. Всё просто. Можем войти в редактор и опрокинуть нашу entity теперь. Одна из последних вещей, которые мы сделаем теперь, это клонирование нашей entity когда мы нажимаем на неё. Закодируем это. Нам нужно добавить код когда мы используем нашу entity, так что сделаем это и вызовем новую функцию.  
-
We can jump in the editor and knock over our entity now. One of the last things we will do now is clone our entity when we press it. Lets’ get coding. We need to add code when we use our entity, so let’ go there and call a new function.
 
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 330: Строка 319:
}}
}}
 +
Это клонирует нашу entity. Сначала мы устанавливаем класс для MyEntity, который будет спавнить нашу entity с дефолтными параметрами. Т.к. нам нужны параметры установки нашей главной entity (main entity), то мы копируем наши собственные свойства (self). Когда мы спавним entity, берем позицию нашей главной entity (main entity) и увеличиваем значение x на 1. Это реально позволит нам увидеть, клонировалась она или нет. После этого мы устанавливаем позицию снова на нашу новую позицию. И закончив мы получили нашу клонирующую функцию.
-
This clones our entity. First we set the class to MyEntity, which will spawn our entity with the default values. We want the settings of our main entity though, so we copy the properties of our self. Then we spawn the entity, get the position of our main entity and increase the x value by 1. This will make it so we can actually see if it’s cloned or not. After that, we set the position again to our new position.  
+
Можем протестировать это в редакторе.
-
And done, we got our cloning function. You can test it out in the editor.
+
== Добавление поддержки флоуграфа. ==
-
 
+
Для этой конкретной entity это немного глупо, но главное, это принцип. Вся информация по флоуграфу поступает в FlowEvents. Мы должны определить это, так что давайте сделаем таким образом.
-
 
+
-
== Adding flowgraph support ==
+
-
For this particular entity it’s a bit stupid, but it’s the idea that counts. All the flowgraph info goes into FlowEvents. We have to define that, so let’s do that now.
+
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 351: Строка 338:
}}
}}
-
When we look at it for a second, it doesn’t seem that hard. We have the inputs and the outputs part. In the Inputs part we got a Clone and a Message. In the output we have a Used which will get called when we used our entity.  
+
Если посмотрим на это на секунду, окажется что ничего тяжелого. У нас есть части по входящим значениям инпутам (inputs) и выходящим значениям аутпутам (outputs). В части инпутов у нас есть Clone (клонирование) и Message (сообщение). В аутпутах у нас есть Used (использована) которая вызывается, когда мы использовали нашу entity. Но что вещи идут после Clone = и Message = ? MyEntity.Event_Clone и MyEntity.Event_Message, откуда они взялись? Вы правы, они взялись из ниоткуда, так что мы должны объявить некоторые функции.
-
 
+
-
But what’s the stuff after Clone = and Message = ? MyEntity.Event_Clone and MyEntity.Event_Message, where does that come from? You’re right, it comes out of nowhere, so we need to declare some functions.
+
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 367: Строка 352:
}}
}}
-
Event_Clone just calls our Clone function we made earlier. With Event_Message we can change our property sMessage from the flowgraph. That covers our Inputs, but how are the outputs handled? We need to add some code that triggers that event, and it’s actually quite simple:
+
Event_Clone просто вызывает нашу Clone функцию, которую мы сделали ранее. При помощи Event_Message мы можем изменить наше свойство sMessage из флоуграфа. Это покрывает инпуты, но как обрабатываются аутпуты? Нам надо добавить немного кода который вызывает это событие, и это довольно просто:
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|
Строка 380: Строка 365:
);
);
self:Clone();  
self:Clone();  
-
self:ActivateOutput( "Used" ,true ); -- This is the new line
+
self:ActivateOutput( "Used" ,true ); -- Это новая строчка
end
end
</source>
</source>
}}
}}
-
We just set that Used value we defined earlier in the output Flowevents and set it to true.  
+
Мы просто устанавливаем это Used значение, которое мы определили ранее в аутпутовских событиях флоуграфа и устанавливаем это на true (правда).  
-
 
+
Таким образом наш флоуграф должен работать теперь. Давайте немного протестируем его. Войдём в редактор и перезагрузим нашу entity, потом кликнем  Create button под  Flowgraph. Зададим ему какое-нибудь имя и потом перейдем к полю флоуграфа. Теперь правой кнопкой мыши нажмем в поле и выберем ‘Add Graph Default Entity’. У нас есть entity в нашем флоуграфе теперь.  
-
That was it, our flowgraph should work now. Let’s give it a little test. Go to the editor and reload your entity, then click on the Create button under Flowgraph. Give it some name and then we got a blank flowgraph. Now rightclick and select ‘Add Graph Default Entity’. We have the entity on our flowgraph now.  
+
-
Let’s give it a little test:
+
Давайте протестируем:
[[Image:Lua_entity_tutorial_flowgraph_sample.jpg]]
[[Image:Lua_entity_tutorial_flowgraph_sample.jpg]]
-
And now once we use our entity, we will see a “Flowgraph is here” message. Note that it this will only show on the original entity. So that sums it up, we have a custom entity which doesn’t do anything spectacular, with flowgraph support.  
+
И теперь однажды использовав нашу entity мы увидим сообщение “Flowgraph is here”. Обратите внимание, что это будет показываться только для оригинальной entity. Таким образом суммируя вышесказанное, у нас есть новая entity которая не делает ничего выдающегося, но с поддержкой флоуграфа.  
-
== Full code ==
+
== Полный код ==
{{Lua_Code|notable=1|
{{Lua_Code|notable=1|

Текущая версия на 18:07, 18 января 2012

О статье
Авторins
ПереводчикSodiet, AndreyFilantrop(текст статьи)
СложностьСредняя
ТребованияТекстовый редактор
Дата добавления03/08/08
Последнее изменение16/06/11



Содержание

Создание новой entity (сущности)

В этом документе мы пойдем пройдём путь создания новой сущности entity (в Lua), с поддержкой флоуграфа. Я буду использовать MyMod и MyEntity для идентификации нашего мода и нового entity. Конечно, Вы можете изменить его на что угодно.

Lua компилятор

Удобно иметь компилятор Lua для проверки синтаксических ошибок в файлах скриптов. Кроме того, кнопка "Reload Script 'в Sandbox исполняет это.

Lua entity tutorial reloadscript.jpg

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 файле:

Lua entity tutorial properties.jpg

Здесь мы также видим, что сделали префиксы. Также обратите внимание, что всё отсортировано в алфавитном порядке без префиксов.

Теперь наша 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 в нашем флоуграфе теперь.

Давайте протестируем:

Lua entity tutorial flowgraph sample.jpg

И теперь однажды использовав нашу 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", },
}