Как создать виртуальный джойстик с помощью Defold Input от britzl

Привет всем подвальным дефолдерам и не только :smiling_face_with_sunglasses:
В этом теме мы создадим виртуальный джойстик, перемещение игрового объекта и запуск снарядов с его помощью:

Виртуальный джойстик

Вы можете как создать новый проект, так и использовать существующий проект.
Добавьте в ваш проект в качестве зависимости Defold Input от britzl : cсылка на github с библиотекой.
Если вы не знаете как добавить библиотечную зависимость, то ознакомьтесь с этим руководством: Как добавить библиотечную зависимость в проект на Defold.

Модуль On-screen

Модуль onscreen в Defold позволяет легко реализовать виртуальные кнопки и джойстики для мобильных устройств или других сенсорных интерфейсов.

Он делится на две основные реализации:

Создание виртуального джойстика из .script, прикрепленного к GO:

Добавим изображения джойстиков и игрового персонажа в проект:





Создадим atlas с изображениями:

Создадим скрипт player.script и добавим в него код:

function init(self)
	msg.post("joystick", "register")
	msg.post("joystick", "register_analog", { id = "stick", radius = 50 })
    -- joistick — имя игрового объекта, в которой находится gui-скрипт с джойстиками
    -- можно поменять значение
	self.speed = vmath.vector3()
end

function final(self)
	msg.post("onscreen", "unregister")
end

function update(self, dt)
	go.set_position(go.get_position() + self.speed * dt)
end


function on_message(self, message_id, message, sender)
	--print("Position:", go.get_position(), "Speed:", self.speed)
	if message_id == hash("onscreen_analog") then
		if message.pressed then
			self.joystick_ready = false
		elseif message.released then
			self.speed = vmath.vector3()
		else
			if not self.joystick_ready then
				self.joystick_ready = true
				return  -- пропускаем первый кадр
			end
			self.speed.x = message.x * 200
			self.speed.y = message.y * 200
		end
	end
end

function on_input(self, action_id, action)
	-- Важно! Передаём события касаний в модуль onscreen
	msg.post("onscreen", "touch", action)
end

Создадим игровой объект персонажа player.go и добавим к нему два компонента: спрайт с изображением из атласа и созданный скрипт player.script:


Создадим gui-файл joystick_go.gui.
Добавим в качестве текстуры подготовленный ранее атлас с изображениями джойстика.
Добавим в этот файл две ноды: base и stick:

Каждой ноде выберите изображение в качестве текстуры:

Создадим коллекцию для примера, в которой создадим такую иерархию файлов:

Запустим проект (ctl + B или f5):
joystick_go

Как создать запуск снарядов?

Добавляем изображения для снаряда, кнопки геймпада в проект. Добавляем их в атлас.
Создаём в gui-файле новую ноду, назовём её: button_a.
Добавляем ей текстуру.
Создаём игровой объект снаряда. Добавляем в атлас.
Переходим в коллекцию, где находятся игровые объекты player и joystick.
Добавляем в игровой объект player фабрику, называем её как угодно, у нас будет laserfactory. В качестве прототипа будет игровой объект снаряда, созданный вами ранее.
Изменяем код player.script:

function init(self)
	msg.post("joystick", "register")
	msg.post("joystick", "register_analog", { id = "stick", radius = 50 })
	msg.post("joystick", "register_button", { id = "button_a" })
	self.speed = vmath.vector3()
end

function final(self)
	msg.post("onscreen", "unregister")
end

function update(self, dt)
	go.set_position(go.get_position() + self.speed * dt)
end


function on_message(self, message_id, message, sender)
	print("Position:", go.get_position(), "Speed:", self.speed)
	if message_id == hash("onscreen_button") and message.id == hash("button_a") and message.released then
		print("laser")
		local pos = go.get_position() + vmath.vector3(0, 50, 0)
		local id = factory.create("#laserfactory", pos)
		go.animate(id, "position.y", go.PLAYBACK_ONCE_FORWARD, pos.y + 1500, go.EASING_LINEAR, 0.8, 0, function()
			go.delete(id)
		end)
	elseif message_id == hash("onscreen_analog") then
		if message.pressed then
			self.joystick_ready = false
		elseif message.released then
			self.speed = vmath.vector3()
		else
			if not self.joystick_ready then
				self.joystick_ready = true
				return  -- пропускаем первый кадр
			end
			self.speed.x = message.x * 200
			self.speed.y = message.y * 200
		end
	end
end

function on_input(self, action_id, action)
	-- Важно! Передаём события касаний в модуль onscreen
	msg.post("onscreen", "touch", action)
end

Запуск снарядов

Создание виртуального джойстика внутри .gui_script:

Создание виртуального джойстика с использованием gui-скрипта:
Добавим изображения под джойстик, игрового персонажа в ваш проект и включим их в какой-нибудь атлас:



Для примера создадим отдельную коллекцию joystick_gui.collection.
Создадим joystick.gui_script, joystick_gui.gui, player.script.

Добавим в player.script код:

function init(self)
	self.speed = vmath.vector3()
end

function update(self, dt)
	go.set_position(go.get_position() + self.speed * dt)
end

function on_message(self, message_id, message, sender)
	if message_id == hash("move") then
		if message.released then
			self.speed.x = 0
			self.speed.y = 0
		else
			self.speed.x = message.x * 200
			self.speed.y = message.y * 200
		end
	end
end

В joystick.gui_script добавим ноды под джойстик, и в качестве текстуры атлас с изображениями джойстиков:


Нодам под джойстик добавим текстуры:

У вас должно получиться что-то подобное:

В joystick.gui_script добавим код:

local onscreen = require "in.onscreen"


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

	self.analog = gui.get_node("stick") -- нода, которая будет двигаться

	onscreen.register_analog(self.analog, { radius = 80 }, function(action, node, touch)
		msg.post("player", "move", touch) -- player — игровой объект, который будет двигаться
	end)
end

function final(self)
	onscreen.reset()
end

function on_input(self, action_id, action)
	onscreen.on_input(action_id, action)
end

Настроим иерархию в joystick_gui.collection подобным образом:


Выберем в качестве скрипта к joystick_gui.gui наш скриптовый файл joystick.gui_script:

Не забудьте изменить стартовую коллекцию в настройках game.project:

Запустите проект (ctrl + B или f5):
Виртуальный джойстик

Как создать запуск снарядов?

Добавляем новую ноду для кнопки в joystick_gui.gui и добавляем ей в качестве текстуры вашего изображение.
Добавляем изображение пули в наш проект.
Добавляем это изображение в атлас.
Создаем игровой объект для пули:


К игровому объекту персонажа добавляем фабрику в коллекции с joystick_gui.collection:

В качестве прототипа указываем игровой объект пули:

В joystick.gui_script добавляем код:

self.button_a = gui.get_node("button_a")

onscreen.register_button(self.button_a, nil, function(action, node, touch)
		msg.post("player", "laser", touch)
	end)

В player.script добавляем создание снарядов через созданную фабрику:

function on_message(self, message_id, message, sender)
	if message_id == hash("laser") then
		if message.released then
			print("laser")
			local pos = go.get_position() + vmath.vector3(0, 50, 0)
			local id = factory.create("#laserfactory", pos)
			go.animate(id, "position.y", go.PLAYBACK_ONCE_FORWARD, pos.y + 1500, go.EASING_LINEAR, 0.8, 0, function()
				go.delete(id)
			end)
		end
	elseif message_id == hash("move") then --предыдущий код
		if message.released then
			self.speed.x = 0
			self.speed.y = 0
		else
			self.speed.x = message.x * 200
			self.speed.y = message.y * 200
		end
	end
end

Запустим проект (ctrl + B или f5):
Запуск снарядов

2 лайка