Если вам надоело писать код, чтобы построить уровень для мини-игры, то вам захочется сделать себе визуальную среду, перетаскивать объекты по экрану и сохранять результаты в файл. Здесь вы увидите пример и сможете на его основе создать собственные редакторы уровней, персонажей, чего угодно. Чтобы не заморачиваться с форматами для сохранения данных, я создал модуль, который записывает любые классы, их списки, словари или просто переменные в виде кода на питоне в файл с расширением RPY. Нужно указать имя файла (можно без расширения), имя функции, которая будет отвечать за "загрузку", ее "уровень" (порядок выполнения блока init) и через запятую имена всех переменных, списков и т.д., которые нужно сохранить, то есть превратить в ренпаевский код.
# в папку game проекта нужно закинуть файл rpy_save.rpy # он отвечает за сохранения любых данных (в виде кода на питоне) # уровень этого блока должен быть ниже уровня сохраняемого init python: # создадим для примера какой-нибудь класс для объектов на экране # у него может быть любая структура, параметры, функции # классов может быть несколько class TUnit: # имена параметров на входе должны совпадать с именами параметров класса! def __init__(self, id, sprite=None, x=0, y=0, flip=False): # уникальный идентификатор объекта self.id = id # его изображение (объекты могут выглядеть одинаково) if not sprite: sprite = id self.sprite = sprite # координаты объекта self.x = x self.y = y # отзеркаливание self.flip = flip # функция возвращает зум объекта по горизонтали def xzoom(self): if self.flip: return -1.0 return 1.0 # перечень всех объектов на экране units = [] # если флаг установлен, то режим редактора, а не игры edit_mode = False # выбранный юнит current_unit = None # список доступных спрайтов sprites_list = ["guy", "kolonna", "lenin", "bg"] # последний выбранный спрайт last_sprite = sprites_list[0] # функция возвращает объект с нужным id def get_unit(id): # перебираем все юниты в поисках нужного for i in units: if i.id == id: return i return None # функция для перетаскивания объекта мышкой def draggetxy(drags, drop): global units, current_unit # сбрасываем старые координаты объекта drags[0].oldposition = None # получаем доступ к нужному i = get_unit(drags[0].drag_name) # если он существует, то if i: # меняем координаты объекта на текущие i.x, i.y = drags[0].x, drags[0].y # выбираем текущий объект current_unit = i # перерисовываем экран renpy.restart_interaction() # сохраняем уровень и закрываем программу, # чтобы при следующем запуске ренпай скомпилировал # сохраненный код на питоне в файл типа *.rpyc def save_quit(): # сохраняем в файл TEST_DATA_SAVE.rpy # сгенерированный блок test_data_init # с уровнем 1 (init 1 python:) # через запятую указать имена всех переменных, # объектов, списков, кортежей и т.д., # текущее состояние которых нужно запомнить # в данном случае только список объектов на экране # и список доступных спрайтов rpy_save("TEST_DATA_SAVE", "test_data_init", 1, "units", "sprites_list") # закрываем программу Quit(confirm=False)() # создаем action для кнопки редактора SaveQuit = renpy.curry(save_quit) # создать новый уникальный id def new_id(): i = 0 name = None # перебираем номера id, пока не попадется еще несуществующий while not name: if get_unit("id" + str(i)): i += 1 else: name = "id" + str(i) return name # добавление нового объекта на экран def add_unit(): global units, current_unit current_unit = TUnit("id", last_sprite) current_unit.id = new_id() # добавляем созданный объект в список units.append(current_unit) renpy.restart_interaction() AddUnit = renpy.curry(add_unit) # удаление объекта с экрана def del_unit(): global units, current_unit if current_unit: units.remove(current_unit) current_unit = None renpy.restart_interaction() DelUnit = renpy.curry(del_unit) # смена слоя объекта def up_unit(): global units, current_unit if current_unit: oldindex = units.index(current_unit) newindex = oldindex + 1 if newindex >= len(units): newindex = 0 units.insert(newindex, units.pop(oldindex)) renpy.restart_interaction() UpUnit = renpy.curry(up_unit) # отзеркаливание объекта def flip_unit(): global units, current_unit if current_unit: current_unit.flip = not current_unit.flip renpy.restart_interaction() FlipUnit = renpy.curry(flip_unit) # смена изображения объекта def spr_unit(): global units, current_unit, last_sprite if current_unit: index = sprites_list.index(current_unit.sprite) + 1 if index >= len(sprites_list): index = 0 current_unit.sprite = sprites_list[index] last_sprite = sprites_list[index] renpy.restart_interaction() SprUnit = renpy.curry(spr_unit) # экран редактора (он же экран игры) screen game: modal edit_mode # в режиме игры просто выводим объекты на экран if not edit_mode: for i in units: add i.sprite pos (i.x, i.y) # в режиме редактора позволяем перемещать и менять объект else: for i in units: drag: # имя объекта для функции смены координат drag_name i.id # координаты объекта pos (int(i.x), int(i.y)) # сам объект button: # кнопка без фона и отступов background None xpadding 0 ypadding 0 xmargin 0 ymargin 0 # изображение объекта add i.sprite xzoom i.xzoom() # чтобы можно было перетаскивать, отключаем действия action [] # чтобы перетаскивать только за рисунок focus_mask True # что делать при перетаскивании (функция выше) dragged draggetxy # выбор предмета кликом, а не перетаскиванием clicked SetVariable("current_unit", i) if edit_mode: # меню редактора frame: background "#0128" align (1.0, 1.0) vbox: textbutton _("Добавить объект") action AddUnit() textbutton _("Сменить спрайт") action [SensitiveIf(current_unit), SprUnit()] textbutton _("Поменять слой") action [SensitiveIf(current_unit), UpUnit()] textbutton _("Отзеркалить объект") action [SensitiveIf(current_unit), FlipUnit()] textbutton _("Удалить объект") action [SensitiveIf(current_unit), DelUnit()] textbutton _("Выйти") action Return() textbutton _("Сохранить и выйти") action SaveQuit() # параметры спрайта if current_unit: frame: background "#0128" align (0.0, 1.0) vbox: text "id: " + str(current_unit.id) text "sprite: " + str(current_unit.sprite) text "x, y: " + str(current_unit.x) + ", " + str(current_unit.y) text "flip: " + str(current_unit.flip) text "order: " + str(units.index(current_unit)) # выбираем режим label start: $ quick_menu = False menu: "Режим редактора": call edit_mode "Режим игры": call game_mode $ quick_menu = True return # показываем экран в игровом режиме label game_mode: # если сохранения есть, то запускаем загрузку из них if "test_data_init" in globals().keys(): $ test_data_init() $ edit_mode = False show screen game "Показываем результат..." return # показываем экран в режиме редактора label edit_mode: # если сохранения есть, то запускаем загрузку из них if "test_data_init" in globals().keys(): $ test_data_init() $ edit_mode = True $ current_unit = None $ last_sprite = sprites_list[0] call screen game return
Комментарии
Отправить комментарий