-
Dmy
-
-
Вне сайта
-
Заблокирован
-
- Сообщений: 1142
- Спасибо получено: 2477
-
-
|
Я сначала опишу то, о чём просили, а потом опишу правильный способ.
Переполнение стека вызывается из-за алиасов:
alias start_window start
alias term_window terminate
alias update_window update
Нужно, чтобы первое название было разным во всех скриптах. То есть лучше заменить start_window на что-то типа start_hand_window_2 и так далее (а также в других местах).
alias создаёт новое имя для старой функции. А потом код переписывает старую функцию и обращается к ней через alias.
Для примера рассмотрим вот этот кусочек кода:
class Scene_Map < Scene_Base
alias start_window start
# часть кода пропущена...
def start
start_window
@winhand = Window_Hand.new
update
end
#часть кода пропущена
end
До работы этого кода у нас есть код для отображения экрана карты (Scene_Map), у которого есть функция start. Она вызывается, когда начинается показ экрана карты.
Наш код создаёт псевдоним для старой функции начала экрана карты (alias start_window start). Теперь к ней можно обращаться и как start, и как start_window.
Дальше наш код заменяет функцию start на свою функцию (def start ... end). Это совсем другой код, в котором вызывается исходная start и добавляется окно.
Следующий скрипт уже работает с изменённой функцией start. И alias start_window start сделает, что start_window будет вызывать изменённую функцию start. А так как изменённая функция start вызывает start_window, то получится бесконечный цикл: функция будет вызывать сама себя.
Информация про вызов функции хранится в специальной памяти, в стеке, и эта память не безгранична. Поэтому, когда функция вызывается слишком много раз, возникает ошибка про уровень стека.
Дальше. Другие вещи, которые надо поменять.
Нужно поменять название класса Window_Hand (например, на Window_Hand2).
Окно хранится в переменной @winhand. Нужно поменять её на что-то другое (например, на @winhand2), чтобы одно окно не переписывало второе.
Если второе окно должно иметь другие размеры, не совпадающие с первым окном, то тогда надо переименовать Hand_setting во что-то другое. Если оба окна должны быть одного размера, то тогда можно просто удалить module Hand_setting ... end и настройки будут браться из первого скрипта. (При этом важно, чтобы он был добавлен в списке скриптов выше, чем второй.)
Ну и, вероятно, нужно менять координаты X и Y окон, чтобы они не налезали одно на другое. Это делается в команде инициализации. Вот эту строчку:
super(Graphics.width-Win_w*4.93, Graphics.height-Win_h, Win_w, Win_h)
можно заменить на что-то другое... Если честно, эта строчка очень странная, я бы её сделал вот такой: # для первого окна (0, т.е. как можно левее)
super(0, Graphics.height-Win_h, Win_w, Win_h)
# для второго окна (Win_w, т.е. на расстоянии окна)
super(Win_w, Graphics.height-Win_h, Win_w, Win_h)
Ну и в draw_window_content нужно поменять номера переменных, из которых берётся номер предмета.
И ещё у меня возникала ошибка из-за порядка вызова update’ов, поэтому я заменил на: @winhand2.update if @winhand2
В результате код принимает такой вид:
include Hand_setting
class Window_Hand2 < Window_Base
def initialize
super(Win_w, Graphics.height-Win_h, Win_w, Win_h)
create_contents
self.visible = Win_vis
refresh
end
def refresh
self.contents.clear
contents.clear
draw_window_content
end
# Рисуем текст
def draw_window_content
### ПОМЕНЯЙТЕ ЧИСЛО В СКОБКАХ НИЖЕ НА НОМЕР ПЕРЕМЕННОЙ
var = $game_variables[1]
if var == 0
var = 20
end
if var < $data_items.length then
$game_variables[2] = $data_items[var].icon_index
@last_icon = $game_variables[2]
draw_text_ex(0, 0, 'Hand2: \I[\V[2]]')
else
draw_text_ex(0, 0, 'Hand2:')
end
end
# Обновить
def update
super
return if @last_icon != $game_variables[2]
refresh
end
end
# Scene_Map Class, For keeping it on the map
class Scene_Map < Scene_Base
alias start_second_hand start
alias term_second_hand terminate
alias update_second_hand update
def start
start_second_hand
@winhand2 = Window_Hand2.new
update
end
def terminate
@winhand2.dispose
term_second_hand
end
def update
update_second_hand
@winhand2.update if @winhand2
end
end
И это работает, всё хорошо, но проблема в том, что код класса Window_Hand2 почти полностью дублирует код класса Window_Hand. Поэтому вот...
ПРАВИЛЬНЫЙ СПОСОБ.
Правильным способом будет переделать код Window_Hand, чтобы его можно было использовать и для правой, и для левой руки. Тогда это будет не дубликат скрипта, а один скрипт для двух рук. Так делать правильно, потому что:
- Его можно будет легко адаптировать и для трёх рук, и для пяти ,
- Если нужно будет поменять механизм работы, можно поменять его сразу для обеих рук.
Для этого нужно передавать параметры в функцию initialize. Мы будем передавать те параметры, которыми руки отличаются друг от друга:
- item_var_id — номер переменной, из которой мы будем брать предмет,
- icon_var_id — номер переменной, в которую мы будем записывать индекс значка,
- x — количество пикселей от края экрана (у первой руки это 0 — ну, или Graphics.width-Win_w*4.93; у второй руки это Win_w)
- window_text — текст в окне ('Hand1:', 'Hand2:', etc.)
Параметры передаются в скобках, так что допишем после функции initialize скобки:
def initialize(x, item_var_id, icon_var_id, window_text)
# код пропущен
end
x используется прямо здесь — он передаётся в функцию initialize верхнего уровня (суперкласса) с помощью super, поэтому первая строчка примет такой вид:
super(x, Graphics.height-Win_h, Win_w, Win_h)
Другие параметры (item_var_id, icon_var_id, window_text) используются не в функции initialize, а в другой функции, draw_window_content. Чтобы они там были доступны, сохраним их как переменные объекта (перед переменными объекта пишется знак @):
@item_var_id = item_var_id
@icon_var_id = icon_var_id
@window_text = window_text
В результате функция initalize примет такой вид:
def initialize(x, item_var_id, icon_var_id, window_text)
super(x, Graphics.height-Win_h, Win_w, Win_h)
@item_var_id = item_var_id
@icon_var_id = icon_var_id
@window_text = window_text
create_contents
self.visible = Win_vis
refresh
end
Так как в функции initialize теперь есть параметры, эти параметры нужно передавать при создании Window_Hand — не
@winhand = Window_Hand.new
а@winhand = Window_Hand.new(0, 1, 2, 'Hand1:')
Это будет в функции start класса Scene_Map, внизу. Ну и, так как рук у нас теперь 2, создадим сразу два окна:
@winhand1 = Window_Hand.new(0, 1, 2, 'Hand1:')
@winhand2 = Window_Hand.new(Win_w, 1, 2, 'Hand2:')
Во второй руке нужно заменить 1 и 2 на номера других переменных, иначе оба окна будут показывать одно и то же.
В других местах @winhand.dispose и @winhand.update тоже нужно заменить на две строчки, одну с @winhand1, вторую с @winhand2.
Ну и нужно поменять саму функцию draw_window_content в классе Window_Hand, чтобы она учитывала @item_var_id, @icon_var_id, @window_text:
def draw_window_content
var = $game_variables[@item_var_id]
if var == 0
var = 20
end
if var < $data_items.length then
$game_variables[@icon_var_id] = $data_items[var].icon_index
@last_icon = $game_variables[@icon_var_id]
draw_text_ex(0, 0, @window_text + '\I[\V[' + @icon_var_id.to_s + ']]')
else
draw_text_ex(0, 0, @window_text)
end
end
Так как @icon_var_id — это число, а не строка, превратим его в строку с помощью to_s.
Результат получается таким:
module Hand_setting
Win_w = 120
Win_h = 50
Win_vis = 255
end
include Hand_setting
class Window_Hand < Window_Base
def initialize(x, item_var_id, icon_var_id, window_text)
super(x, Graphics.height-Win_h, Win_w, Win_h)
@item_var_id = item_var_id
@icon_var_id = icon_var_id
@window_text = window_text
create_contents
self.visible = Win_vis
refresh
end
def refresh
self.contents.clear
contents.clear
draw_window_content
end
# Рисуем текст
def draw_window_content
var = $game_variables[@item_var_id]
if var == 0
var = 20
end
if var < $data_items.length then
$game_variables[@icon_var_id] = $data_items[var].icon_index
@last_icon = $game_variables[@icon_var_id]
draw_text_ex(0, 0, @window_text + '\I[\V[' + @icon_var_id.to_s + ']]')
else
draw_text_ex(0, 0, @window_text)
end
end
# Обновить
def update
super
return if @last_icon != $game_variables[@icon_var_id]
refresh
end
end
# Scene_Map Class, For keeping it on the map
class Scene_Map < Scene_Base
alias start_window start
alias term_window terminate
alias update_window update
def start
start_window
#замените 1 на номер переменной, из которой будет браться предмет
#замените 2 на номер переменной, в которую запишется номер последнего значка
@winhand1 = Window_Hand.new(0, 1, 2, 'Hand1: ')
@winhand2 = Window_Hand.new(Win_w, 1, 2, 'Hand2: ')
update
end
def terminate
@winhand1.dispose
@winhand2.dispose
term_window
end
def update
update_window
@winhand1.update if @winhand1
@winhand2.update if @winhand2
end
end
Всё бы хорошо, но чтобы настроить скрипт, придётся редактировать строчки @winhand1 = Window_Hand.new(0, 1, 2, 'Hand1: ')
@winhand2 = Window_Hand.new(Win_w, 1, 2, 'Hand2: ') в середине кода. Считается дурным тоном заставлять людей редактировать строчки в середине кода. Лучше вынести их наверх — тем более, что у нас уже есть module Hand_setting ... end для хранения настроек.
В результате код получается таким:module Hand_setting
# ширина окона
Win_w = 120
# высота окон
Win_h = 50
# непрозрачность окон
Win_vis = 255
# Номер переменной, где хранится предмет правой руки
Right_hand_var_id = 1
# Номер переменной, куда запишется значок предмета из правой руки
Right_hand_icon_id = 2
# Текст перед значком предмета левой руки:
Right_hand_window_text = 'Hand1: '
# Номер переменной, где хранится предмет левой руки
Left_hand_var_id = 3
# Номер переменной, куда запишется значок предмета из левой руки
Left_hand_icon_id = 4
# Текст перед значком предмета левой руки:
Left_hand_window_text = 'Hand2: '
# Номер предмета, который будет показан, если рука пустая
Hand_empty_item_id = 20
end
include Hand_setting
class Window_Hand < Window_Base
def initialize(x, item_var_id, icon_var_id, window_text)
super(x, Graphics.height-Win_h, Win_w, Win_h)
@item_var_id = item_var_id
@icon_var_id = icon_var_id
@window_text = window_text
create_contents
self.visible = Win_vis
refresh
end
def refresh
self.contents.clear
contents.clear
draw_window_content
end
# Рисуем текст
def draw_window_content
var = $game_variables[@item_var_id]
if var == 0
var = Hand_empty_item_id
end
if var < $data_items.length then
$game_variables[@icon_var_id] = $data_items[var].icon_index
@last_icon = $game_variables[@icon_var_id]
draw_text_ex(0, 0, @window_text + '\I[\V[' + @icon_var_id.to_s + ']]')
else
draw_text_ex(0, 0, @window_text)
end
end
# Обновить
def update
super
return if @last_icon != $game_variables[@icon_var_id]
refresh
end
end
# Scene_Map Class, For keeping it on the map
class Scene_Map < Scene_Base
alias start_window start
alias term_window terminate
alias update_window update
def start
start_window
@winhand1 = Window_Hand.new(0, Right_hand_var_id, Right_hand_icon_id, Right_hand_window_text)
@winhand2 = Window_Hand.new(Win_w, Left_hand_var_id, Left_hand_icon_id, Left_hand_window_text)
update
end
def terminate
@winhand1.dispose
@winhand2.dispose
term_window
end
def update
update_window
@winhand1.update if @winhand1
@winhand2.update if @winhand2
end
end
Я проверял и у меня всё работает, но если что-то не работает — пиши, исправлю. Или если что-то непонятно. Удачи!
|