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

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

Перейти к: навигация, поиск
О статье
Автор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", },
}