Название: Time Management
Автор: caveman
Версия: 1.0
Тип: работа с переменными и свитчами
Описание:
Написал небольшой, но, потенциально полезный скриптик для управления временем.
Он умеет считывать с одного или нескольких файлов формата csv (строки из слов, разделенных точкой с запятой - трансформируется из Excel через Save as csv; а эксель, или calc - просто для удобства редактирования) набор данных по управлению переменными, свитчами и селфсвитчами в реальном времени (точность до секунды) и сходу применять их в игре, в том же реальном времени от начала игры/запуска файла.
Кроме этого, он поддерживает циклический запуск этого набора в заданном в нем же промежутке времени.
Вроде пока всё. Если ничего непонятно, поясню словами и демкой:
* Я хочу сделать демку, которая изображает два дня в лесу.
* Я хочу удобно управлять временами дня (хотя бы через screen color tone), погодой и событиями в течении этого времени.
* Я хочу думать в реальном времени, а не в фреймах, например, пусть мои сутки длятся 2 минуты.
- Я составляю 2 файлика (в экселе, так мне удобно) - тут приведу отконверченный в csv вариант обработки переменных, свитчей и селфсвитчей, предварительно настроенных в проекте для времен дня и погоды.
Файлик для огорода в демке.
ЗЫ: если видите пусто между двумя ";", то там ячейка попросту пуста
- Я добавляю скрипт, что внизу под спойлером, чуть выше Main.
- Я добавляю в авторане первой (и единственной) карты вызов
$time_owner.add_manager(1)
$time_owner.add_manager(2)
$time_owner.reload(1, "test") - тут файл погоды и времени дня
$time_owner.reload(2, "farm") - тут обработка роста овощей
$time_owner.start_all - для простоты - запускаю всё, можно запускать и по отдельности, командой $time_owner.start(1)
- Я запускаю демо и радуюсь
Теперь разберем файлик, вот он:
Name;forest;;;;;;
Cycling;yes;;;;;;
Time;0:00:00;0:04:00;;;;;
Commands;;;;;;;
Время;Тип;Id;Значение;Map_id;Event _id;Letter;Comment
0:00:00;Variable;1;1;;;;morning
0:00:30;Variable;1;2;;;;day
0:01:00;Variable;1;3;;;;evening
0:01:30;Variable;1;4;;;;night
0:02:00;Variable;1;1;;;;morning
0:02:30;Variable;1;2;;;;day
0:03:00;Variable;1;3;;;;evening
0:03:30;Variable;1;4;;;;night
0:00:02;variable;2;1;;;;music day
0:01:10;variable;2;2;;;;music night
0:02:02;variable;2;1;;;;music day
0:03:10;variable;2;2;;;;music night
0:02:40;Variable;3;1;;;;rain
0:03:25;Variable;3;2;;;;no rain
0:01:00;Variable;4;1;;;;fog
0:01:35;Variable;4;2;;;;no fog
0:02:10;Variable;4;1;;;;fog
0:03:20;Variable;4;2;;;;no fog
0:01:40;Switch;1;True;;;;crow
0:02:10;Switch;1;FALSE;;;;no crow
0:00:05;SelfSwitch;;True;1;3;A;squirrel
0:01:10;SelfSwitch;;FALSE;1;3;A;squirrel
0:03:35;SelfSwitch;;True;1;3;A;squirrel
0:03:58;SelfSwitch;;FALSE;1;3;A;squirrel
Первая строка в нем - заголовок. Он ни к чему не обязывает, и просто служит мне для удобства.
Вторая строка показывает, запускаю ли я обработку файла циклически (yes/no).
Третья строка задает время начала запуска и окончания запуска (очень полезно для циклических запусков).
Четвертая и пятая - просто для удобства в экселе.
А далее начинаются команды (значения нечувствительны к регистру)
Время; - время срабатывания в формате hh:mm:ss
Тип; - тип (Variable, Switch, SelfSwitch)
Id; - номер переменной или свитча, для SelfSwitch бесполезно
Значение; - значение переменной/свитча. Для variable это - число; для остальных вариантов - True или False
Map_id; - номер карты, актуален для селфсвитча
Event_id; - номер события, актуален для селфсвитча
Letter; - буква-селфсвитч (A,B,C,D), актуален для селфсвитча
Comment - комментарий (для удобства)
Скрипт пока не поддерживает русские подписи, борюсь...
Вот он сам:
class Time_Command
attr_accessor :affect_type # 0 - variable, 1 - switch, 2 - self switch
# для selfswitch
attr_accessor :map_id
attr_accessor :event_id
attr_accessor :letter
attr_accessor :ss_value
# для switch
attr_accessor :switch_id
attr_accessor :s_value
# для variable
attr_accessor :var_id
attr_accessor :v_value
attr_accessor :need_refresh # true (пока)
attr_accessor :time # в секундах
attr_accessor :is_used # уже пройдено
def initialize
self.need_refresh = true
end
end
class Time_Manager
attr_accessor :id # id
attr_accessor :start_time # в секундах
attr_accessor :end_time # в секундах
attr_accessor :cur_time # в секундах
attr_accessor :real_start_time # в секундах
attr_accessor :need_cycle # запускать циклически
attr_accessor :commands # список команд
attr_accessor :is_started
def initialize(id)
self.id = id
self.commands =[]
@regexp = /\A(.*?);(.*?);(.*?);(.*?);(.*?);(.*?);(.*?);(.*?)\Z/
end
#==========================================================#
#========== Загрузка из файла =============================#
#==========================================================#
def reload(filename)
if FileTest.exist?(sprintf("%s.csv",filename))
self.commands = []
file=File.open(sprintf("%s.csv",filename),"r")
load_timing(file)
file.close
# p self.commands
end
end
def load_timing(file)
@lines = file.readlines
@line = 0
@line += 1 # название
# цикличность
@lines[@line].gsub(@regexp) do
self.need_cycle = $2.to_s.upcase == "YES"
end
@line += 1
# время начала и конца
@lines[@line].gsub(@regexp) do
self.start_time = extract_time($2.to_s)
self.end_time = extract_time($3.to_s)
end
@line += 3 # пропуск строк "команды" и "заголовки"
while @line < @lines.length
@lines[@line].gsub(@regexp) do
command = Time_Command.new
command.time = extract_time($1.to_s)
case $2.to_s.upcase
when "VARIABLE"
command.affect_type = 0
command.var_id = $3.to_i
command.v_value = $4.to_i
when "SWITCH"
command.affect_type = 1
command.switch_id = $3.to_i
command.s_value = $4.to_s.upcase == "TRUE"
when "SELFSWITCH"
command.affect_type = 2
command.ss_value = $4.to_s.upcase == "TRUE"
command.map_id = $5.to_i
command.event_id = $6.to_i
command.letter = $7.to_s
else
p 'неверный тип!'
end
self.commands.push(command)
end
@line += 1
end
end
def extract_time(str)
# выцепим время из строки вида hh:mm:ss
str.gsub(/\A(.+?)\:(.+?)\:(.+?)\Z/) do
hh = $1.to_i
mm = $2.to_i
ss = $3.to_i
return hh * 60 * 60 + mm * 60 + ss
end
end
#==========================================================#
#========== Управление ====================================#
#==========================================================#
def start
self.cur_time = 0
self.real_start_time = Graphics.frame_count / Graphics.frame_rate
self.is_started = true
end
def stop
self.is_started = false
end
def reset
stop
start
end
#==========================================================#
#========== Автоапдейт ====================================#
#==========================================================#
def update
if is_started
flag = false # рефрешить ли карту
@total_sec = Graphics.frame_count / Graphics.frame_rate
# время тут - сдвиг от запуска
self.cur_time = @total_sec - self.real_start_time
# для циклического запуска, проверяем конец цикла, сбрасываем всё
if self.need_cycle && self.cur_time >= self.end_time
for c in self.commands
c.is_used = false
end
self.cur_time = 0
self.real_start_time = Graphics.frame_count / Graphics.frame_rate
end
# просматриваем команды с точным временем
for c in self.commands
if !c.is_used
if c.time <= self.cur_time
call_command(c)
c.is_used = true
flag = true
end
end
end
if flag
$game_map.need_refresh = true
end
end
end
def call_command(c)
if c.affect_type == 0
$game_variables[c.var_id] = c.v_value
elsif c.affect_type == 1
$game_switches[c.switch_id] = c.s_value
elsif c.affect_type == 2
key = [c.map_id, c.event_id, c.letter]
$game_self_switches[key] = c.ss_value
end
end
end
class Time_Owner
attr_accessor :time_managers
def initialize
self.time_managers = []
end
def add_manager(id)
self.time_managers.push(Time_Manager.new(id))
end
def remove_manager(id)
for m in self.time_managers
if m.id == id
delete(m)
end
end
end
def reload(id, filename)
for m in self.time_managers
if m.id == id
m.reload(filename)
end
end
end
def start(id)
for m in self.time_managers
if m.id == id
m.start
end
end
end
def start_all
for m in self.time_managers
m.start
end
end
def stop(id)
for m in self.time_managers
if m.id == id
m.stop
end
end
end
def stop_all
for m in self.time_managers
m.stop
end
end
def reset(id)
stop(id)
start(id)
end
def reset_all
stop_all
start_all
end
def update
for m in self.time_managers
m.update
end
end
end
class Game_System
alias tm_update update
def update
tm_update
if $time_owner != nil
$time_owner.update
end
end
end
class Scene_Title
alias tm_main main
def main
$time_owner = Time_Owner.new
tm_main
end
end
Демо тут:
yadi.sk/d/wMk9CNKzDtYPZ
PS: я предполагал им настраивать день/ночь, погоду и жизненный цикл неписей, но вот, на нейтрале сразу же подумали про ферму