SoC. Спавн телепортов через скрипт — различия между версиями
Материал из S.T.A.L.K.E.R. Inside Wiki
(→Авторы) |
RedPython (обсуждение | вклад) м (restored) |
||
| Строка 1: | Строка 1: | ||
| − | + | ==Создаем телепорт== | |
| + | ===Теория этого дела=== | ||
| − | + | В игре существует такой объект как "zone_teleport", но если мы его создадим через create, то он будет выглядеть и переливаться как настоящий телепорт, но телепортировать нас куда-либо увы не сможет. Связано это с тем что, у аномалий ( а телепорт это такая разновидность аномалии ) параметры задаются хитромудро, через all.spawn. Вобщем штатным способом телепорты без полнофункционального редактора карт не получить (хотя возможно я не прав уже после написания этого текста появились идеи как это сделать через '''all.spawn'''). Значит на нашу долю остаються способы "не штатные" ;) Реализуем самый простой. Будем считать что у нас на карте есть квадрат с заданными координатами при попадании в который актера должно переместить в точку с другими координатами. Для этого будем периодически проверять координаты актера, и если он в квадрате - перемещяем. Вот в краце принцип действия нашего "самодельного" телепорта. | |
| + | |||
| + | ===Реализация=== | ||
| + | |||
| + | В каталоге ''gamedata\scripts\'' Создадим файл '''bind_mteleport.script''' с логикой работы нашего телепорта. | ||
| + | <pre> | ||
| + | -- ************************************************ | ||
| + | -- ** Imp ** | ||
| + | -- ** Биндер самодельных телепортов ** | ||
| + | -- ** Поддерживает работу самопальных телепортов ** | ||
| + | -- ************************************************ | ||
| + | |||
| + | local teleport_binders ={} -- Список телепортов | ||
| + | |||
| + | function abs_comp(a,b) | ||
| + | -- Служебная функция вычисления разности | ||
| + | if( a < b) then | ||
| + | return (b - a) | ||
| + | else | ||
| + | return (a - b) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function teleportate(x,y,z) | ||
| + | -- Функция телепортации | ||
| + | local a = vector() | ||
| + | -- Задаем координаты | ||
| + | a.x = x | ||
| + | a.y = y | ||
| + | a.z = z | ||
| + | |||
| + | -- Сама телепортация | ||
| + | db.actor:set_actor_position(a) | ||
| + | |||
| + | -- Звуковое сопровождение | ||
| + | local snd_obj = xr_sound.get_safe_sound_object([[affects\tinnitus3a]]) | ||
| + | snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0) | ||
| + | |||
| + | end | ||
| + | |||
| + | |||
| + | function actor_update(delta) | ||
| + | local i,v,acter_poz,s | ||
| + | |||
| + | -- Получим позицию актера (что-бы каждый раз не запрашивать) | ||
| + | acter_poz = db.actor:position() | ||
| + | |||
| + | -- Проверяем наши телепорты | ||
| + | for i, v in pairs(teleport_binders) do | ||
| + | s = v.parametrs | ||
| + | |||
| + | local obj = level.object_by_id( i ) | ||
| + | if obj ~= nil then | ||
| + | -- Наш телепорт в онлайне проверяем дальше | ||
| + | if s.teleporte ~= nil and s.teleporte ~= false then | ||
| + | -- Телепорт запущен | ||
| + | if ( time_global() <= s.time ) then | ||
| + | -- Если время отведенное на показ спецэфектов | ||
| + | -- прошло, производим телепортацию | ||
| + | teleportate(s.poz_x,s.poz_y,s.poz_z) | ||
| + | if s.rotate ~= nil then | ||
| + | db.actor:set_actor_direction(s.rotate) | ||
| + | end | ||
| + | s.teleporte = false | ||
| + | end | ||
| + | return | ||
| + | end | ||
| + | |||
| + | -- Пороверим не забрел-ли актер в наш телепорт | ||
| + | if (abs_comp(s.x, acter_poz.x)< v.parametrs.radius and | ||
| + | abs_comp(s.z, acter_poz.z)< v.parametrs.radius and | ||
| + | abs_comp(s.y, acter_poz.y)< v.parametrs.z_radius) then | ||
| + | -- Актер в зоне действия телепорта, запустим телепорт | ||
| + | s["teleporte"] = true | ||
| + | s["time"] = time_global() + 500 | ||
| + | |||
| + | -- Запускаем спецэфекты телепортации | ||
| + | level.add_pp_effector ("teleport.ppe", 2006, false) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function bind( obj ) | ||
| + | obj:bind_object( restrictor_teleport( obj ) ) | ||
| + | end | ||
| + | |||
| + | ---------------------------------------------------------------------------------------------------- | ||
| + | class "restrictor_teleport" ( object_binder ) | ||
| + | |||
| + | function restrictor_teleport:__init(obj, char_ini) super(obj) | ||
| + | end | ||
| + | |||
| + | function restrictor_teleport:net_spawn(data) | ||
| + | local char_ini = system_ini() | ||
| + | |||
| + | -- Если это телепорт то занесем его в специальный список телепортов | ||
| + | if self.teleport == true then | ||
| + | teleport_binders[self.object:id()] = self | ||
| + | |||
| + | -- Заполним таблицу параметров | ||
| + | self["parametrs"] = {} | ||
| + | if char_ini:line_exist(self.section, "radius") then | ||
| + | self.parametrs["radius"] = tonumber(char_ini:r_string(self.section, "radius")) | ||
| + | else | ||
| + | self.parametrs["radius"] = 2 -- Дефолтный радиус по xy | ||
| + | end | ||
| + | if char_ini:line_exist(self.section, "z_radius") then | ||
| + | self.parametrs["z_radius"] = tonumber(char_ini:r_string(self.section, "z_radius")) | ||
| + | else | ||
| + | self.parametrs["z_radius"] = self.parametrs["radius"] -- если радиус высоты не задан то задаем равным радиусу xy | ||
| + | end | ||
| + | |||
| + | -- Запомним позицию что-бы каждый раз не считать | ||
| + | local s_obj = alife():object(self.object:id()) | ||
| + | self.parametrs["x"] = tonumber(s_obj.position.x); | ||
| + | self.parametrs["y"] = tonumber(s_obj.position.y); | ||
| + | self.parametrs["z"] = tonumber(s_obj.position.z); | ||
| + | |||
| + | -- Запомним координаты куда телепортимся | ||
| + | self.parametrs["poz_x"] = tonumber(char_ini:r_string(self.section, "poz_x")) | ||
| + | self.parametrs["poz_y"] = tonumber(char_ini:r_string(self.section, "poz_y")) | ||
| + | self.parametrs["poz_z"] = tonumber(char_ini:r_string(self.section, "poz_z")) | ||
| + | |||
| + | if char_ini:line_exist(self.section, "rotate") then | ||
| + | self.parametrs["rotate"] = tonumber(char_ini:r_string(self.section, "rotate")) | ||
| + | end | ||
| + | end | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | function restrictor_teleport:net_destroy() | ||
| + | -- Удаляем наш телепорт | ||
| + | teleport_binders[self.object:id()] = nil | ||
| + | self.parametrs = nil | ||
| + | object_binder.net_destroy(self) | ||
| + | end | ||
| + | |||
| + | function restrictor_teleport:reload(section) | ||
| + | local char_ini = system_ini() | ||
| + | |||
| + | self.section = section | ||
| + | -- Если это телепорт то | ||
| + | if char_ini ~= nil and char_ini:line_exist(self.section, "teleport") then | ||
| + | self["teleport"] = true | ||
| + | end | ||
| + | end | ||
| + | |||
| + | </pre> | ||
| + | |||
| + | Для постоянного обновления нужно прицепить функцию actor_update() к биндеру актера, для чего в файле '''bind_stalker.script''' найдем функцию: | ||
| + | |||
| + | ''function actor_binder:update(delta)'' | ||
| + | |||
| + | В ней найдем вызов обновления рестрикторов | ||
| + | ''bind_restrictor.actor_update(delta)'' | ||
| + | под которым вставим строку с вызовом нашей функции обновления: | ||
| + | ''bind_mteleport.actor_update(delta)'' | ||
| + | |||
| + | Все с программной частью закончили, теперь задаем данные телепорта. | ||
| + | |||
| + | В каталоге ''gamedata\config\misc'' открываем файл '''zone_teleport.ltx''' и в конце файла добавляем следующие строки описывающие конкретный телепорт: | ||
| + | |||
| + | <pre>[m_teleport_1]:zone_teleport | ||
| + | teleport = standart | ||
| + | script_binding = bind_mteleport.bind | ||
| + | ;Параметры нашего телепорта | ||
| + | radius = 2 | ||
| + | ;Высота захвата телепорта | ||
| + | z_radius = 2 | ||
| + | |||
| + | ;Куда телепортируемся (телепортация всегда идет в пределах карты) | ||
| + | poz_x = 22.78 | ||
| + | poz_y = 20.35 | ||
| + | poz_z = 659.24 | ||
| + | |||
| + | ; Угол зрения при появлении. Если параметра нет то не меняется. | ||
| + | rotate = 1.5</pre> | ||
| + | |||
| + | Параметры нашего телепорта: | ||
| + | |||
| + | * radius - на самом деле не радиус, а половина длинны стороны нашего квадрата (в начале я хотел сделать его кругом, но посчитал, что лучше не тратить процессорное врямя по пусту). Центром квадрата является точка респавна телепорта. | ||
| + | |||
| + | * z_radius - высота нашего телепорта. | ||
| + | |||
| + | * poz_x, poz_y, poz_z - координаты точки телепортации. | ||
| + | |||
| + | * rotate - Угол поворота после телепортации от оси X (я не разбирался в каких единицах задается, но 1.5 примерно равно 90 градусов). Если параметр удалить то будет оставатья угол под которым актер вошел в телепорт. | ||
| + | |||
| + | === Использование === | ||
| + | Теперь с помощью create создадим наш телепорт: | ||
| + | Пример: | ||
| + | |||
| + | <pre> local obj | ||
| + | local a = vector() | ||
| + | a.x = -244.55 | ||
| + | a.y = -19.46 | ||
| + | a.z = -125.42 | ||
| + | obj = alife():create("m_teleport_1",a,12829,8,65535)</pre> | ||
| + | |||
| + | Создаст телепорт возле выхода из бункера Сидоровича. | ||
| + | Наш телепорт перебрасывает игрока на вышку блокпоста (перед выходом с уровня). | ||
| + | |||
| + | Все! Вот [http://www.imp.webhost.ru/stalker/ тут] вы можете взять готовый мод с двумя телепортами. | ||
| + | |||
| + | ==Авторы== | ||
| + | |||
| + | Статья создана: | ||
| + | |||
| + | * [[Участник:Imp|Imp]] | ||
| + | |||
| + | [[Категория:Скрипты]] | ||
Версия 14:27, 21 мая 2011
Создаем телепорт
Теория этого дела
В игре существует такой объект как "zone_teleport", но если мы его создадим через create, то он будет выглядеть и переливаться как настоящий телепорт, но телепортировать нас куда-либо увы не сможет. Связано это с тем что, у аномалий ( а телепорт это такая разновидность аномалии ) параметры задаются хитромудро, через all.spawn. Вобщем штатным способом телепорты без полнофункционального редактора карт не получить (хотя возможно я не прав уже после написания этого текста появились идеи как это сделать через all.spawn). Значит на нашу долю остаються способы "не штатные" ;) Реализуем самый простой. Будем считать что у нас на карте есть квадрат с заданными координатами при попадании в который актера должно переместить в точку с другими координатами. Для этого будем периодически проверять координаты актера, и если он в квадрате - перемещяем. Вот в краце принцип действия нашего "самодельного" телепорта.
Реализация
В каталоге gamedata\scripts\ Создадим файл bind_mteleport.script с логикой работы нашего телепорта.
-- ************************************************
-- ** Imp **
-- ** Биндер самодельных телепортов **
-- ** Поддерживает работу самопальных телепортов **
-- ************************************************
local teleport_binders ={} -- Список телепортов
function abs_comp(a,b)
-- Служебная функция вычисления разности
if( a < b) then
return (b - a)
else
return (a - b)
end
end
function teleportate(x,y,z)
-- Функция телепортации
local a = vector()
-- Задаем координаты
a.x = x
a.y = y
a.z = z
-- Сама телепортация
db.actor:set_actor_position(a)
-- Звуковое сопровождение
local snd_obj = xr_sound.get_safe_sound_object([[affects\tinnitus3a]])
snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0)
end
function actor_update(delta)
local i,v,acter_poz,s
-- Получим позицию актера (что-бы каждый раз не запрашивать)
acter_poz = db.actor:position()
-- Проверяем наши телепорты
for i, v in pairs(teleport_binders) do
s = v.parametrs
local obj = level.object_by_id( i )
if obj ~= nil then
-- Наш телепорт в онлайне проверяем дальше
if s.teleporte ~= nil and s.teleporte ~= false then
-- Телепорт запущен
if ( time_global() <= s.time ) then
-- Если время отведенное на показ спецэфектов
-- прошло, производим телепортацию
teleportate(s.poz_x,s.poz_y,s.poz_z)
if s.rotate ~= nil then
db.actor:set_actor_direction(s.rotate)
end
s.teleporte = false
end
return
end
-- Пороверим не забрел-ли актер в наш телепорт
if (abs_comp(s.x, acter_poz.x)< v.parametrs.radius and
abs_comp(s.z, acter_poz.z)< v.parametrs.radius and
abs_comp(s.y, acter_poz.y)< v.parametrs.z_radius) then
-- Актер в зоне действия телепорта, запустим телепорт
s["teleporte"] = true
s["time"] = time_global() + 500
-- Запускаем спецэфекты телепортации
level.add_pp_effector ("teleport.ppe", 2006, false)
end
end
end
end
function bind( obj )
obj:bind_object( restrictor_teleport( obj ) )
end
----------------------------------------------------------------------------------------------------
class "restrictor_teleport" ( object_binder )
function restrictor_teleport:__init(obj, char_ini) super(obj)
end
function restrictor_teleport:net_spawn(data)
local char_ini = system_ini()
-- Если это телепорт то занесем его в специальный список телепортов
if self.teleport == true then
teleport_binders[self.object:id()] = self
-- Заполним таблицу параметров
self["parametrs"] = {}
if char_ini:line_exist(self.section, "radius") then
self.parametrs["radius"] = tonumber(char_ini:r_string(self.section, "radius"))
else
self.parametrs["radius"] = 2 -- Дефолтный радиус по xy
end
if char_ini:line_exist(self.section, "z_radius") then
self.parametrs["z_radius"] = tonumber(char_ini:r_string(self.section, "z_radius"))
else
self.parametrs["z_radius"] = self.parametrs["radius"] -- если радиус высоты не задан то задаем равным радиусу xy
end
-- Запомним позицию что-бы каждый раз не считать
local s_obj = alife():object(self.object:id())
self.parametrs["x"] = tonumber(s_obj.position.x);
self.parametrs["y"] = tonumber(s_obj.position.y);
self.parametrs["z"] = tonumber(s_obj.position.z);
-- Запомним координаты куда телепортимся
self.parametrs["poz_x"] = tonumber(char_ini:r_string(self.section, "poz_x"))
self.parametrs["poz_y"] = tonumber(char_ini:r_string(self.section, "poz_y"))
self.parametrs["poz_z"] = tonumber(char_ini:r_string(self.section, "poz_z"))
if char_ini:line_exist(self.section, "rotate") then
self.parametrs["rotate"] = tonumber(char_ini:r_string(self.section, "rotate"))
end
end
return true
end
function restrictor_teleport:net_destroy()
-- Удаляем наш телепорт
teleport_binders[self.object:id()] = nil
self.parametrs = nil
object_binder.net_destroy(self)
end
function restrictor_teleport:reload(section)
local char_ini = system_ini()
self.section = section
-- Если это телепорт то
if char_ini ~= nil and char_ini:line_exist(self.section, "teleport") then
self["teleport"] = true
end
end
Для постоянного обновления нужно прицепить функцию actor_update() к биндеру актера, для чего в файле bind_stalker.script найдем функцию:
function actor_binder:update(delta)
В ней найдем вызов обновления рестрикторов bind_restrictor.actor_update(delta) под которым вставим строку с вызовом нашей функции обновления: bind_mteleport.actor_update(delta)
Все с программной частью закончили, теперь задаем данные телепорта.
В каталоге gamedata\config\misc открываем файл zone_teleport.ltx и в конце файла добавляем следующие строки описывающие конкретный телепорт:
[m_teleport_1]:zone_teleport teleport = standart script_binding = bind_mteleport.bind ;Параметры нашего телепорта radius = 2 ;Высота захвата телепорта z_radius = 2 ;Куда телепортируемся (телепортация всегда идет в пределах карты) poz_x = 22.78 poz_y = 20.35 poz_z = 659.24 ; Угол зрения при появлении. Если параметра нет то не меняется. rotate = 1.5
Параметры нашего телепорта:
- radius - на самом деле не радиус, а половина длинны стороны нашего квадрата (в начале я хотел сделать его кругом, но посчитал, что лучше не тратить процессорное врямя по пусту). Центром квадрата является точка респавна телепорта.
- z_radius - высота нашего телепорта.
- poz_x, poz_y, poz_z - координаты точки телепортации.
- rotate - Угол поворота после телепортации от оси X (я не разбирался в каких единицах задается, но 1.5 примерно равно 90 градусов). Если параметр удалить то будет оставатья угол под которым актер вошел в телепорт.
Использование
Теперь с помощью create создадим наш телепорт: Пример:
local obj
local a = vector()
a.x = -244.55
a.y = -19.46
a.z = -125.42
obj = alife():create("m_teleport_1",a,12829,8,65535)
Создаст телепорт возле выхода из бункера Сидоровича. Наш телепорт перебрасывает игрока на вышку блокпоста (перед выходом с уровня).
Все! Вот тут вы можете взять готовый мод с двумя телепортами.
Авторы
Статья создана: