Использовать монарх? Нет 🤡. Создаем переключатель с кнопками для переключения сцен

Материалы:

Для начала создадим и включим одну коллекцию, а так же научимся ее выключать.

Cоздаем в Aseets:

  • уже созданный main.collection
  • созадем коллекцию start.collection
  • controller.scipts
  • создаем папку assets, в ней создаем main.atlas и закидываем box.png

Outline main коллекции:

  • создаем go и называем controller
  • в этом же го подключаем controller.scipts
  • в этом же го создаем прокси коллекцию и выбираем в поле коллекции нашу start.collection и меняем id на start

Переходим в start.collection. Добавим спрайт, чтоб видеть, что коллекция загрузилась.

  • создаем go
    • в го создаем спрайт
      • в image выбираем атлас main
        • в default animation box.png

Что происходит при создании коллекции? Создаем отдельный мир, для физики тоже, между коллекциями обьекты не могут общаться, например, в физике это два разных мира, коллизии не будут видеть друг друга. Так же память выделяется, создание десятков коллекций не гуд, тут лучше использовать фабрики коллекций.

Загружаем коллекцию controller.scipts:

function init(self)
	msg.post(".", "acquire_input_focus")
	print('hi')

	-- загружаем коллекцию
	-- есть еще async_load загрузка
	-- обратно получим сообщение "proxy_loaded"
	-- обрабатываем в on_message
	msg.post("#start", "load")
end

-- self таблица скрипта
-- message_id как раз таки наша hash("proxy_loaded")
-- message таблица с данными, если есть
-- sender url отправителя
function on_message(self, message_id, message, sender)
	if message_id == hash("proxy_loaded") then
		-- если нужно сначала вызвать метод init, а только потом показать обьекты коллекции на экране
		msg.post(sender, "init")
		-- включаем видимость
		msg.post(sender, "enable")

		-- выключаем скрипты через секунду
		-- 1 - задержка в секундах
		-- false/true - повторять таймер
		-- функция
		-- -- handle индентификатор, всегда 0 возвращаем???? 
		-- -- timer.cancel(0) получилось отменить таймер
		-- time_elapsed - время, которое прошло с последнего вызова:
		-- 1.0004662275314, 1.0057771205902
		timer.delay(1, true, function(self, handle, time_elapsed)
			print("Прошла 1 секунда!")
			-- можно вызвать сразу unload
			-- но можно скрыть через disable
			msg.post(sender, "disable")
			-- запустить метод final
			msg.post(sender, "final")
			-- затем уже выгрузить все
			msg.post(sender, "unload")

			timer.cancel(0)
		end)
	end

	if message_id == hash("proxy_unloaded") then
		-- после выгрузки по таймеру:
		print('коллекция выгружена')
	end
end

Примерно такое будет в конце:

Cоздаем переключатель из двух кнопок для прыжков между коллекциями.

Подготовка:

  • удаляем весь код в контроллере
  • создаем еще одну коллекцию second, добавляем в нее go, в го спрайт, в спрайт вставляем атлас в image и выбираем в default animation box.png
  • в main.controller создаем коллекцию, называем second и выбираем в свойствах collection проекцию second
  • можем побегать по коллекциям старт/секонд и поменять расположение спрайтов, размер, чтоб коллекции друг от друга различались
    В контроллере быстро проверяем работоспособность
function init(self)
	msg.post("#start", "load")
	msg.post("#second", "load")
end
function on_message(self, message_id, message, sender)
	if message_id == hash("proxy_loaded") then
		msg.post(sender, "enable")
	end
end
  • Создаем новую папку menu
  • в ней же коллекцию menu
  • в коллекции го
  • в этой же папке создаем menu.gui и menu.gui_script
  • в menu.gui в свойствах Script выбираем наш созданыый menu.gui_script
  • в го подключаем menu.gui через add Component File
  • переходим в menu.gui, создаем два бокса в нодах, называем btn1, btn2, добавим обоим текст text1, text2
  • добавялем фон в fonts default уже есть в редакторе
  • выбираем у text1,text2 наш фон в Font
  • идем в main.collection, в controller, создаем новую прокси коллекцию, называем menu, выбираем коллекцию menu в Collectoin в свойствах
  • включим коллекцию menu на экране в controoler.script
  • изменим цвет текста в menu.gui у кнопок в свойстве Color, на белом фоне не видно и в свойстве Text поменяем текст на btn1,btn2
  • в текстуры menu.gui добавим main.atlas, перейдем к нодам btn1,btn2, выберем текстуры, включим side mode: manual для включения Slice 9, начинающий, точно не скажу, это когда можем создать маленькую текстурку и растягивать ее в разные стороны, если фон в центре одного тона, удобно для UI. На фото ниже видно как мы увеличили го без Slice 9 через scale и края поплыли в пиксели
function init(self)
	-- включим для будущего первого шага ввод от мышки
	msg.post(".", "acquire_input_focus")
	
	msg.post("#start", "load")
	msg.post("#second", "load")
	msg.post("#menu", "load")
end


function on_message(self, message_id, message, sender)
	if message_id == hash("proxy_loaded") then
		-- пока передаем всем коллекциям, потом исправим
		msg.post(sender, "acquire_input_focus")
		msg.post(sender, "enable")
	end
end

вот что получается

Придумываем как переключать коллекции.

Шаг 1. Научимся отслеживать клик по кнопкам.
Переходим в menu.gui_script:

function init(self)
	msg.post(".", "acquire_input_focus")
	-- выбираем по id в self таблицы
	self.btn1 = gui.get_node("btn1")
	self.btn2 = gui.get_node("btn2")
end

-- action_id — это идентификатор из input bindings, например, touch
-- action это таблица, например координаты x,y там есть
-- action.x, action.y показывают x,y координат GUI
-- то есть координаты которые заданы GUI в game.project как я понял
function on_input(self, action_id, action)
	-- нажали кнопку action.pressed
	if action.pressed and gui.pick_node(self.btn1, action.x, action.y) then
		print('кликнули на 1 кнопку')
	end
	if action.pressed and gui.pick_node(self.btn2, action.x, action.y) then
		print('кликнули на 2 кнопку')
	end
end

Шаг 2. Научимся отправлять сообщения в controller.script
menu.gui_script

function init(self)
	msg.post(".", "acquire_input_focus")
	self.btn1 = gui.get_node("btn1")
	self.btn2 = gui.get_node("btn2")
end

function on_input(self, action_id, action)
	if action.pressed and gui.pick_node(self.btn1, action.x, action.y) then
		-- main - коллекция main
		-- controller - гошка controller
		-- controller название скрипта
		-- switch - id сообщения на которое отсылаем в controller.script
		-- option = 1 - таблица с переменной option=1
		msg.post(msg.url("main:/controller#controller"), "switch", { option = 1 })
	end
	if action.pressed and gui.pick_node(self.btn2, action.x, action.y) then
		msg.post(msg.url("main:/controller#controller"), "switch", { option = 2 })
	end
end

в контроллере оставляем одну сцену menu с кнопками

function init(self)
	msg.post(".", "acquire_input_focus")
	msg.post("#menu", "load")
end


function on_message(self, message_id, message, sender)
	-- получаем сообщение по ключу switch
	if message_id == hash("switch") then
		print('hello from menu.gui_script')
		-- наш option=1
		pprint(message)
	end
	
	if message_id == hash("proxy_loaded") then
		msg.post(sender, "acquire_input_focus")
		msg.post(sender, "enable")
	end
end

Шаг 3. Включаем коллекции по клику.

-- табличка для прокси
local PROXIES = {
	["1"] = "#start", 
	["2"] = "#second",
}

function init(self)
	msg.post(".", "acquire_input_focus")
	msg.post("#menu", "load")
end

function on_message(self, message_id, message, sender)
	if message_id == hash("switch") then
		-- в строку потому что в proxies у нас тоже строка, данные: 1,2
		local option = tostring(message.option)
		-- ключ сцены для 1 - #start и 2 - #second, данные: #start, #second
		local keyScene = PROXIES[option]
		-- отправляем на загрузку
		msg.post(keyScene, "load")
	end
	-- тут загружаем коллекции
	if message_id == hash("proxy_loaded") then
		msg.post(sender, "acquire_input_focus")
		msg.post(sender, "enable")
	end
end

Шаг 4, нужно включать только одну коллекцию, другие выключаем.
Добавляем три функции и немного кода

local PROXIES = {
	["1"] = "#start", 
	["2"] = "#second",
}

function init(self)
	msg.post(".", "acquire_input_focus")

	-- будем хранить загружаемые сцены
	self.loaded = {}     
	-- текущая сцена
	self.current = nil
	-- загрузка на случай многократного вызова
	self.loading = {}

	msg.post("#menu", "load")
end

local function option_by_sender(sender)
	-- k ключи 1,2
	-- proxy #start, #second
	-- msg.url("#") можно вернуть текущий url скрипта
	-- msg.url(proxy) #start -> url: [main:/controller#start]
	for k, proxy in pairs(PROXIES) do
		if msg.url(proxy) == sender then
			return k
		end
	end
	return nil
end

-- убираем фокус у предыдущей сцены
-- при удалении коллекци в final движок сам это делает
-- но вроде как бест практика 
-- и чтобы просто потом не забывать, когда буду делать разные вариации
local function release_previous_focus(self)
	if self.current and PROXIES[self.current] then
		msg.post(PROXIES[self.current], "release_input_focus")
	end
end

local function enable_option(self, option)
	-- возвращаем, если равен текущему
	if option == self.current then return end

	release_previous_focus(self)
	
	msg.post(PROXIES[option], "enable")
	-- если нужен ввод
	msg.post(PROXIES[option], "acquire_input_focus")
	for k, proxy in pairs(PROXIES) do
		if k ~= option and self.loaded[k] then
			msg.post(proxy, "disable")
			-- если хотим экономить память, удаляем коллекцию
			msg.post(proxy, "unload")
			self.loaded[k] = nil
		end
	end
	self.current = option
end

function on_message(self, message_id, message, sender)
	if message_id == hash("switch") then
		-- в строку потому что в proxies у нас тоже строка, данные: 1,2
		local option = tostring(message.option)
		-- ключ сцены для 1 - #start и 2 - #second, данные: #start, #second
		local keyScene = PROXIES[option]
		if not keyScene then return end
		
		-- если сцена текущая, оставляем
		if option == self.current then
			return
		end

		-- если сцена загрузилась
		if self.loaded[option] and not self.loading[option] then
			enable_option(self, option)
		else
			self.loading[option] = true
			-- отправляем на загрузку
			msg.post(keyScene, "load")
		end
	end
	if message_id == hash("proxy_loaded") then
		-- включаем меню, sender и msg.url("#menu"): url: [main:/controller#menu]
		if sender == msg.url("#menu") then
			msg.post(sender, "enable")
			msg.post(sender, "acquire_input_focus")
		end

		-- выясним, какая опция загрузилась
		local option = option_by_sender(sender)
		if option then
			self.loading[option] = nil
			self.loaded[option] = true
			enable_option(self, option)
		end
	end
end

добавил еще одну кнопку для теста и проверил результат

3 лайка