On-screen: implement joystick plus a split screen for mobile (solved)

I am stuck with a tiny problem and need your help, please:
My app is going to be html, so I need to cater for possible mobile input, too.
I would like the mobile user to have a choice:
move when touching the left side of the screen, rotate when touching the right side.
Those who would like to have visual cues can switch on a virtual joystick.
To implement this, I have added two large nodes to the gui (they will be invisible in the game) one covering the right side, one the left side of the screen. I also added nodes for the joystick:

image832

I would like to use @britzl’s onscreen.lua for this. Movement does work quite well, but the joystick buttons do not move, either one or both of them. I then moved the large nodes out of the way when the joystick is switched on, still the joystick buttons are stuck.
This is my code:

game.script init:

msg.post(/controls#controls, register)
-- register the joystick
msg.post(/controls#controls, register_analog, { id = move, radius = 52 })
msg.post(/controls#controls, register_analog, { id = rotate, radius = 52 })

game.script on_message:

	if message_id == ONSCREEN_ANALOG and message.id == MOVING or message.id == MOVING_LARGE then
		self.action_dx = 0
		self.action_dy = 0
		if message.released then
			self.move.x = 0
			self.move.y = 0
			self.move.z = 0
			self.speed = 0	
		else
			self.move.x = message.x
			self.move.z = -message.y
			self.speed = speed_keys
		end
	elseif message_id == ONSCREEN_ANALOG and message.id == ROTATING or message.id == ROTATING_LARGE then
		if message.released then
			rotation_speed = 0.2
			self.action_dx = 0
			self.action_dy = 0
		else
			rotation_speed = 1
			self.action_dx = message.x
			self.action_dy = message.y
		end
	end

game.script on_input:

	if action_id == MULTITOUCH then 
		-- register the invisible controls
		-- radius set to 1, because these controls don't need to move like a joystick button
		msg.post("/controls#controls", "register_analog", { id = "move_large", radius = 1 })
		msg.post("/controls#controls", "register_analog", { id = "rotate_large", radius = 1 })
	end

controls.gui_script on top:

local function on_analog(action_id, node, action)
	post_to_listener(action_id, action)
end

controls.gui_script init:

    self.analog = {}
	post_to_listener = function(message_id, message)
		if self.listener then
			msg.post(self.listener, message_id, message or {})
		end
	end

controls.gui_script on_message:

	if message_id == REGISTER then
		self.listener = sender
	elseif message_id == UNREGISTER then
		self.listener = nil
	elseif message_id == REGISTER_ANALOG then
		onscreen.register_analog(gui.get_node(message.id), { radius = message.radius }, on_analog)
	end

controls.gui_script on_input:

onscreen.on_input(action_id, action)

Sorry for the long post :flushed: I did try lot’s of things, including my own script for screen splitting or using a separate on-screen script for the invisible nodes, I fiddled with the radii, too.

That’s odd. I don’t see an obvious problem with your setup. I think I need to play around with it myself. Perhaps you can share something with me?

1 Like

@britzl: Björn, thank you very much!
If you like, I can share the link to the whole project with you, would that be ok?
P.S sent you a link via pm

@britzl - just solved the problem. :partying_face:
I just had an inkling that the wrong node would be picked when the button is stuck.
So I added a print statement to your handle_analog(control, node) function to check: print(control.id)
Turns out that most of the times the large box would be picked, so of course the button wouldn’t move. So I just set the z-position of the joystick buttons’ parent nodes to 1, et voilà, it works now :partying_face:
Just tried on my tablet, all good so far, so this issue should be solved now. Thank you for having offered to help me out!

EDIT: didn’t last, wrong nodes picked again. What is weird, sometimes it works, next build it doesn’t. Need to look for another solution :thinking: :face_with_monocle:

Good to hear that you have an idea what is wrong at least! It seems like there is a need to give priority to the joystick and always check that before the big node.

1 Like

Thank you! I am just about to get this working, it will be done - well, hopefully :grinning_face_with_smiling_eyes:

2 Likes

I have meanwhile found an astonishingly simple solution that might be of interest for other people, too:

I added a check to see if a node is enabled to this function in onscreen.lua:

	local function find_control_for_xy(x, y)
		for node,control in pairs(controls) do
			--if gui.pick_node(node, x, y) then
			if gui.pick_node(node, x, y) and gui.is_enabled(node) then
				return control, node
			end
		end
	end

If my joystick is switched on, I disable the large nodes and vice versa.

This way, I also solved this issue:
I didn’t want the large nodes to take over when the joystick is on if the user touches anywhere outside the joystick buttons.
And this too:
When the user moves or rotates using the large nodes and happens to touch the hidden joystick buttons, the button’s animations would still run since they still received input. If the user switched the joystick on in such a case, the buttons would jump back to their initial position - which would look odd.

So, at least for my purposes, this problem is solved. :partying_face:

2 Likes