[SOLVED] Registering objects being clicked and dragged using Defold Input library as nil

I’m trying to make a script that uses the cursor script from the Defold Input library and using the example given in Github as a basis, however, the message.id, and message.group always comes back as nil and I don’t know why.

debug messages

collection layout

Settings for the collision object in each of the game objects I want to be clickable and draggable.


image

Code in controller.script

local cursor = require "in.cursor"

function init(self)
	if not go.get("#cursor", "acquire_input_focus") then
		self.forward_input = true
		msg.post(".", "acquire_input_focus")
	end
end

function on_input(self, action_id, action)
	if self.forward_input then
		msg.post("#cursor", "input", { action_id = action_id, action = action })
	end
end

function on_message(self, message_id, message, sender)
	if message_id == cursor.OVER then
		print("Cursor over", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.OUT then
		print("Cursor out", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.PRESSED then
		print("Pressed", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.RELEASED then
		print("Released", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.CLICKED then
		print("Clicked", message.id, message.group, message.x, message.y)
		if message.group == hash("computer") then
			msg.post("/computer#computer", "acquire_input_focus")
		end
	elseif message_id == cursor.DRAG_START then
		print("Drag started", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.DRAG_END then
		print("Drag ended", message.id, message.group, message.x, message.y)
	elseif message_id == cursor.DRAG then
		print("Drag", message.id, message.group, message.x, message.y, message.dx, message.dy)
	end
end

book.script

local cursor = require "in.cursor"

function on_message(self, message_id, message, sender)
	if message_id == cursor.OVER then
		self.over_pos = go.get_position()
		go.set_position(vmath.vector3(self.over_pos.x, self.over_pos.y, 1))
		go.animate("#sprite", "tint.w", go.PLAYBACK_ONCE_FORWARD, 1.5, go.EASING_OUTQUAD, 0.1)
	elseif message_id == cursor.OUT then
		local pos = go.get_position()
		go.set_position(vmath.vector3(pos.x, pos.y, self.over_pos.z))
		go.animate("#sprite", "tint.w", go.PLAYBACK_ONCE_FORWARD, 1, go.EASING_OUTQUAD, 0.1)
	end
end

If I click on the computer, it should have the input focus, but if I click somewhere else or another object like the book, if I drag the book it should move. Only it doesn’t for some reason, I’m slightly confused by how the groups and masks on collision objects work. I’m reading Collision messages in Defold so I get where message.group is coming from, but if I just want the behavior to be specific to only a game object, how does other_id work. Like it states to get the instance’s id, but how would you do that, isn’t every different instance going to have a different id?

Thanks to anyone who answers.

Hard to say what’s wrong. The groups and masks look ok and the rest of the setup too.

I’d start by checking Physics Debug in game.project physics section and check that the collision objects are where you expect them to be. Next I’d also look at the physics debug visualization that it indicates a collision when you move the cursor above the different items.

I would also compare the working examples in Defold-Input with your own project. What are the differences? And could any of the differences be the cause of your problems?

I see, I see the issue now, the cursor’s collision is really far away compared to the actual cursor, and it’s also falling down. I think it might have to do with the type of collision the cursor is. Question is why is it so far away compared to the actual cursor. Switched to trigger, that fixes the falling, however there’s still the issue of the cursor being too far away.

To give context, for the camera I’m using rendercam and set it to be 1920 x 1080, I don’t know if that’s the issue or not.

Are you translating from screen coordinates to world coordinates using one of the functions in rendercam?

No I haven’t, that might be the issue, I have it set up in bootstrap as the default render, where exactly should I be calling the function in Rendercam, inside the script that’s a part of the game object that is the cursor? Is the function I’m supposed to call screen_to_world_2d? I’m slightly confused where I’m supposed to get the parameters from, especially delta and worldz.

Yes, I believe screen_to_world_2d() is correct. Docs here:

Thanks for the document:

rendercam.screen_to_world_2d(x, y, [delta], [worldz], [raw])

Transforms x and y from screen coordinates to world coordinates at a certain Z position—either a specified worldz or by default the current camera’s “2d World Z”. This function returns a position on a plane perpendicular to the camera angle, so it’s only accurate for 2D-oriented cameras (facing along the Z axis). It works for 2D-oriented perspective cameras, but will have some small imprecision based on the size of the view depth (farZ - nearZ). For 3D cameras, use rendercam.screen_to_world_plane or rendercam.screen_to_world_ray. Set the [raw] parameter to true to return raw x, y, and z values instead of a vector. This provides a minor performance improvement since returning a vector creates more garbage for the garbage collector.

I’m slightly confused on how to get the x and y for the screen coordinates if my cursor is in the world.

The screen coordinates is what you get in on_input(). It tells you where your cursor is on the screen (lower left being 0:0). The world coordinate is where the cursor is in the game world (ie with camera translation taken into account).

I see, so in my controller.script

function init(self)
	if not go.get("#cursor", "acquire_input_focus") then
		self.forward_input = true
		msg.post(".", "acquire_input_focus")
	end
end

function on_input(self, action_id, action)
	if self.forward_input then
		msg.post("#cursor", "input", { action_id = action_id, action = action })
	end
end

I’d pass in action.dx and action.dy right? Would I call the screen_to_world_2d() on on_input()? I’m reading API reference (go) right now. Or screen_x and screen_y.

function on_input(self, action_id, action)
	if self.forward_input then
		rendercam.screen_to_world_2d(action.screen_x,  action.screen_y, delta, worldz)
		msg.post("#cursor", "input", { action_id = action_id, action = action })
	end
end

Something like that, but passing something in for delta and worldz. Yea no, that’s not going to work, it’s because what’s placed inside of those methods aren’t going to be called.

local pos = rendercam.screen_to_world_2d(action.x,  action.y)
3 Likes

Thank you selimanac, I’m assuming then I would pass pos into something else.

Yes, that’s is the position you pass to the cursor so that it is correctly positioned in the world.

1 Like

I see, I’m curious, what function would you use to pass to the cursor though? I’m looking at cursor.script and cursor.lua and it doesn’t seem like I’m supposed to pass positions through it.

There is an example of how to use a camera and cursor at the same time in the Defold-Input project. Here (using the Orthographic camera solution, but the same thing can be done with RenderCam):

It is also mentioned in the documentation here: https://github.com/britzl/defold-input/blob/master/in/cursor.md#input-handling

I see, thank you. Sorry, it’s just difficult for me to grasp these concepts in Defold. :+1:

No problem. Some of this is specific to Defold, but the general concept of translating a mouse position on the screen to a position in the game world is something you will find in most game engines.

2 Likes