Need help with my cursor in my basic top down shooter

I have a crosshair game object (not a child of the player or anything) with a sprite inside it, and this script:

function init(self)
	-- make sure the script will receive user input
	msg.post(".", "acquire_input_focus")
end

function on_input(self, action_id, action)
	if not action_id then --this is the id for mouse movement
		local cursorX = action.x --sets the coordinates of the mouse input to variables
		local cursorY = action.y
		local cursorposition = vmath.vector3(cursorX, cursorY, 500) -- assigns the coordinates to a variable (500 on the z axis so it its always on top of other game objects)
		go.set_position(cursorposition)
	end
end	

Im using a camera that follows the player (2d, with the camera having orthographic projection turned on), and when i try to move my cursor around to somewhere outside the range of world coordinates (1920x1080), it stops at the max x and y or min x and y coordinates. I understand that this is because i am setting the game object to the screen coordinates of the mouse input (1920x1080 maximum), but i cant find any way to get the mouse coordinates in the world. I’d greatly appreciate some help and im very new to both lua and defold. Let me know if you need more info. ty

Incase it’s also relevant, this is the script for the player’s aiming:

function init(self)
	msg.post(".", "acquire_input_focus")--ensures the script gets input
end

local function look_at(target_position)
	local my_position = go.get_position()--gets player's own position

	local angle = math.atan2(my_position.x - target_position.x, target_position.y - my_position.y)-- calculates the angle that this object has to rotate to look at the target position

	go.set_rotation(vmath.quat_rotation_z(angle))-- sets rotation as a quaternion
end

function on_input(self, action_id, action)
	if not action_id then--id for mouse movement is "null"
		self.target_position = vmath.vector3(action.x, action.y, 0)-- sets the cursor position to be the target position
		look_at(self.target_position)-- rotate this object to look at the target position
	end	
end

function update(self, dt)
	look_at(self.target_position)-- updates rotation constantly
end

Here’s a complete example of how to convert screen to world using an orthographic camera:

2 Likes

Thanks for the assistance, but after trying this script:

local DISPLAY_WIDTH = sys.get_config_int("display.width")
local DISPLAY_HEIGHT = sys.get_config_int("display.height")

local function screen_to_world(x, y, z, camera)
	local projection = go.get(camera, "projection")
	local view = go.get(camera, "view")
	local w, h = window.get_size()
	-- The window.get_size() function will return the scaled window size taking into account display scaling
	w = w / (w / DISPLAY_WIDTH)
	h = h / (h / DISPLAY_HEIGHT)

	local inv = vmath.inv(projection * view)
	x = (2 * x / w) - 1
	y = (2 * y / h) - 1
	z = (2 * z) - 1
	local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
	local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
	local z1 = x * inv.m20 + y * inv.m21 + z * inv.m22 + inv.m23
	return x1, y1, z1
end

function init(self)
	-- make sure the script will receive user input
	msg.post(".", "acquire_input_focus")
end

function on_input(self, action_id, action)
	if not action_id then --this is the id for mouse movement
		local cursorX = action.x --sets the coordinates of the mouse input to variables
		local cursorY = action.y
		local cursorpositionscreen = vmath.vector3(cursorX, cursorY, 500) -- assigns the coordinates to a variable (500 on the z axis so it its always on top of other game objects)
		local cursorpositionworld = screen_to_world(cursorposition)
		go.set_position(cursorpositionworld)
	end
end

I get the exact same issue as i did before. Im unsure as to what i’ve done wrong as i used a new variable to double check that the screen_to_world() function is returning coordinates

(Side question, how do i put the code into its own window thing on this website?)

Hard to say why it is not working. Compare your project with the one I shared. What are the differences?

Can you share your project?

Put it in three quotes:

```
Your code here
```

1 Like

As far as i can tell, its the same function as the example you sent me. How would i go about sharing my project?

EDIT:

Actually, it appears that my old crosshair script was running despite me replacing the script path with the new one in the game object. Having run it again, i get “attempt to index local ‘target_position’ (a nil value)” in my aiming script

function init(self)
	msg.post(".", "acquire_input_focus")--ensures the script gets input
end

local function look_at(target_position)
	local my_position = go.get_position()--gets player's own position

	local angle = math.atan2(my_position.x - target_position.x, target_position.y - my_position.y)-- calculates the angle that this object has to rotate to look at the target position

	go.set_rotation(vmath.quat_rotation_z(angle))-- sets rotation as a quaternion
end

function on_input(self, action_id, action)
	if not action_id then--id for mouse movement is "null"
		self.target_position = vmath.vector3(action.x, action.y, 0)-- sets the cursor position to be the target position
		look_at(self.target_position)-- rotate this object to look at the target position
	end	
end

function update(self, dt)
	look_at(self.target_position)-- updates rotation constantly
end

but this only happens with the new crosshair script, not my old crosshair script. As far as i can tell, neither should have an impact on the aiming script as i dont think they’re interacting, but im guessing i must be wrong

You are not initialising self.target_position in init() which means that the value is nil until you receive some input.

function init(self)
	msg.post(".", "acquire_input_focus")--ensures the script gets input
	self.target_position = vmath.vector3()
end
1 Like

ty, does this: “/crosshair#CrosshairV2’ does not have any property called ‘projection’” mean that i need to change the go.get(camera, “projection”) and view lines to the url of the camera or something? Im unsure. Sorry to be a pain

Correct, you need to make sure the URL is that of the camera so that it is possible to read the camera projection etc

1 Like

Thank you!

Been really annoying trying to figure this out, thank you for all your help. In case anyone wants to do the same thing, this is what i ended up with.

cursor script:

local DISPLAY_WIDTH = sys.get_config_int("display.width")
local DISPLAY_HEIGHT = sys.get_config_int("display.height")

local function screen_to_world(x, y, z, camera)--function that converts screen coordinates into world coordinates
	local projection = go.get("/camera#camera", "projection")
	local view = go.get("/camera#camera", "view")
	local w, h = window.get_size()
	-- The window.get_size() function will return the scaled window size taking into account display scaling
	w = w / (w / DISPLAY_WIDTH)
	h = h / (h / DISPLAY_HEIGHT)

	local inv = vmath.inv(projection * view)
	x = (2 * x / w) - 1
	y = (2 * y / h) - 1
	z = (2 * z) - 1
	local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
	local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
	local z1 = x * inv.m20 + y * inv.m21 + z * inv.m22 + inv.m23
	return x1, y1, z1
end

function init(self)
	msg.post(".", "acquire_input_focus")-- makes sure the script will receive user input
	self.vel = vmath.vector3()
	sys.set_update_frequency(60)--fps cap
end

function on_input(self, action_id, action)
	if not action_id or action_id == hash("touch") then
		local worldx, worldy = screen_to_world(action.x, action.y, 0, "/camera#camera")-- converts mouse/touch screen position to world position
		local world = vmath.vector3(worldx, worldy, 500)-- updates cursor position to the world position of mouse/touch position
		go.set_position(world)		
	end
	
	if action_id == hash("up") then--these just ensure the cursor moves when the player moves
		self.vel.y = 150
	elseif action_id == hash("down") then
		self.vel.y = -150
	elseif action_id == hash("left") then
		self.vel.x = -150
	elseif action_id == hash("right") then
		self.vel.x = 150
	end
end

function update(self, dt)
	local pos = go.get_position()
	pos = pos + self.vel * dt
	go.set_position(pos)
	self.vel.x = 0
	self.vel.y = 0
end

Aiming script:

function init(self)
	msg.post(".", "acquire_input_focus")--ensures the script gets input
	self.target_position = vmath.vector3()
end

local DISPLAY_WIDTH = sys.get_config_int("display.width")
local DISPLAY_HEIGHT = sys.get_config_int("display.height")

local function screen_to_world(x, y, z, camera)--function that converts screen coordinates into world coordinates
	local projection = go.get("/camera#camera", "projection")
	local view = go.get("/camera#camera", "view")
	local w, h = window.get_size()
	-- The window.get_size() function will return the scaled window size taking into account display scaling
	w = w / (w / DISPLAY_WIDTH)
	h = h / (h / DISPLAY_HEIGHT)

	local inv = vmath.inv(projection * view)
	x = (2 * x / w) - 1
	y = (2 * y / h) - 1
	z = (2 * z) - 1
	local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
	local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
	local z1 = x * inv.m20 + y * inv.m21 + z * inv.m22 + inv.m23
	return x1, y1, z1
end

local function look_at(target_position)
	local my_position = go.get_position()--gets player's own position
	local angle = math.atan2(my_position.x - target_position.x, target_position.y - my_position.y)-- calculates the angle that this object has to rotate to look at the target position
	go.set_rotation(vmath.quat_rotation_z(angle))-- sets rotation as a quaternion
end

function update(self, dt)
	local cursorpos = go.get_position("crosshair")
	look_at(cursorpos)
end

Thank you britzl!

1 Like