Difference mouse-collision to gameobject when camera moved

Hey there.

I am not sure if I AM CONFUSED or there is a bug with defold.

Background:
I’ve generated a random map using tilemap.
I’m spawning some gameobjects
I got a script for a crosshair which checks collisions.
worked so far.
Now I’ve added a camera and a moving script. - works also.

but now, following is happening:
IF i dont move the camera, clicking at the gameobject works (collision with crosshair and any gameobject).
BUT if i move the camera, there is no collision detected, so no gameobject is clickable. If I move the camera back to the normal initiated pos it works again. ALSO works if I click the position of the gameobject - moved-camera.

hm… any ideas?

Here are some code-snippets…
CROSSHAIR:

function on_message(self, message_id, message, sender)
	-- collision-handling
	if message_id == COLLISION_RESPONSE and not self.collision_id then		
		if not collision_id then
			self.collision_group = message.group	
			self.collision_id = message.other_id
		end
	end		
end

function on_input(self, action_id, action)
	-- if no action_id, set position of crosshair to mouse-position
	if not action_id then
		go.set_position(vmath.vector3(action.x, action.y, 0))
	end
	
	-- mouseclicks handling
	if action.pressed and action_id == LEFTCLICKED then		
		-- crosshair collisions 
		if self.collision_id then
			if self.collision_group == hash("unit") then
				if self.collision_id ~= self.activeUnit then
					--print("CROSSHAIR: collision-click @ " .. self.collision_id)
					msg.post(self.collision_id, "activated")
					msg.post(self.activeUnit, "deactivated")
					self.activeUnit = self.collision_id					
				else
					--print("CROSSHAIR: DEACTIVATE collision-click @ " .. self.collision_id)
					msg.post(self.activeUnit, "deactivated")
					self.activeUnit = nil										
				end				
			end				
		else
			if self.activeUnit then		
				print("CROSSHAIR: sending unit targetpos " .. go.get_position())
				msg.post(self.activeUnit, "moveto", {targetpos = go.get_position()})
			end		
		end
	end	
end

UNIT (the clickable GO):

function update(self, dt)
	
	self.pos = go.get_position()
	
	-- DEBUG: transparent if NOT activated		
	local isActive
	if self.active == true then
		isActive = "ACTIVE"		
		go.set("#sprite", "tint.w", 1.0)
	else
		isActive = "INACTIVE"
		go.set("#sprite", "tint.w", 0.5)
	end
	--msg.post("@render:", "draw_text", {text = isActive .. " " .. self.unit.energy, position = self.pos + vmath.vector3(self.spriteD.x, 0, 0)})
	-- DEBUG END
	
	
	if self.ismoving == true then
		--self.active = false
		--ACTIVEOBJECT = nil		
		local from = vmath.vector3(self.pos.x, self.pos.y, 0)
		local angle = -math.atan2(self.targetpos.x - from.x, self.targetpos.y - from.y)
		local rotation = vmath.quat_rotation_z(angle)
		go.set_rotation(rotation)
		
		local distance = self.unit.moveSpeed * dt
		local direction = vmath.rotate(rotation, vmath.vector3(0, distance, 0))
		go.set_position(go.get_position() + direction)			

		local distance_traveled = math.abs(vmath.length(self.targetpos - self.pos))				
		if distance_traveled <= 1 or self.pos == self.targetpos then
			go.set_position(self.targetpos)
			self.ismoving = false
		end
		
		updateUnitinfo(self)
		
	elseif self.unit.energy < self.unit.energyMax then
		self.unit.energy = self.unit.energy + self.unit.energyReload
	end	
	
end

function on_message(self, message_id, message, sender)
	if message_id == hash("activated") then
		self.active = true
		self.targetpos = go.get_position()
		self.ismoving = false
		ACTIVEOBJECT = go.get_id()	
		updateUnitinfo(self)
		msg.post("main:/ingamegui#gui", "unitmenu", {position =  go.get_position() + vmath.vector3(self.spriteD.x,0,0)})		
	end
	
	if message_id == hash("deactivated") then
		self.active = false
		msg.post("ingamegui", "disable")
	end	
	
	if message_id == hash("moveto") then
		local toX = message.targetpos.x
		local toY = message.targetpos.y
		
		self.targetpos = vmath.vector3(math.floor(toX / TILESIZE) * TILESIZE, math.floor(toY / TILESIZE) * TILESIZE, 0)
		local distance_traveled = math.abs(vmath.length(self.targetpos - self.pos))
		if distance_traveled <= self.unit.energy then
			self.unit.energy = self.unit.energy - distance_traveled
			self.ismoving = true
			msg.post("ingamegui", "disable")
		else
			msg.post("main:/ingamegui#gui", "warning", {text = "NOT ENOUGH ENERGY! \nNeed " .. distance_traveled - self.unit.energy})
		end
	end
end

and CAMERA:

function on_input(self, action_id, action)
	-- Add input-handling code here
	-- Remove this function if not needed	
--	if action.pressed then
		if action_id == KEY_LEFT then
			print("LEFT")
			self.PosX = self.PosX - camSpeed
			go.set_position(vmath.vector3(self.PosX, self.PosY, 0))
			label.set_text("#caminfo", go.get_position().x .. " x " .. go.get_position().y)
		elseif action_id == KEY_RIGHT then
			self.PosX = self.PosX + camSpeed
			go.set_position(vmath.vector3(self.PosX, self.PosY, 0))
			label.set_text("#caminfo", go.get_position().x .. " x " .. go.get_position().y)
		elseif action_id == KEY_UP then
			self.PosY = self.PosY - camSpeed
			go.set_position(vmath.vector3(self.PosX, self.PosY, 0))
			label.set_text("#caminfo", go.get_position().x .. " x " .. go.get_position().y)
		elseif action_id == KEY_DOWN then
			self.PosY = self.PosY + camSpeed
			go.set_position(vmath.vector3(self.PosX, self.PosY, 0))
			label.set_text("#caminfo", go.get_position().x .. " x " .. go.get_position().y)
		end
--	end
end

Have you tried enabling the physics debug setting in game.project? I’m guessing that you’re not taking into account the offset of the camera when you are moving the crosshair. It’s probably positioned at 0,0 + mouse offset instead of 0,0 + camera offset + mouse offset

thanks @britzl.

Will check that.
I’ve found something that sounds similar and is equal to my thinkings: correcting the coordinates by subtracting the cam-position. Hope to check that tomorrow :slight_smile:

oh… debug activated.
now I can see if i move the camera the crosshair (which is just a collider without sprite) is moving with the camera (away from mouse) o.O

why the hell do i get the gamecam-pos the same as the crosshair position?

CROSSHAIR.script is like this.

	
	local camPos = go.get_position("#gamecam")
	
	label.set_text("#crosshair", "POS: " .. go.get_position().x .."x"..go.get_position().y .. " CAMpos: " .. camPos.x .."x" .. camPos.y .." TILE: " .. tilemap.get_tile("main:/map#level", "base", go.get_position().x / TILESIZE, go.get_position().y / TILESIZE))	
	

oh by the way: I added a collider (debug enabled) to the camera-GO. its always at 0:0. doesnt matter what coordinates I try to give the GO. hm…

The # sign in that URL indicates that the camera is a component of the gameobject that the script is attached to. Is that really correct?

Yes. There is a gameobject called “gamecam”. attached the script “gamecam.script” and the camera of cause. testwise the defold-image als sprite to see the position - which is always down-left-corner.

Is there another / better way to handle the cam?

Ok, so if you want the position of the gamecam gameobject from the crosshair.script (which I assume is attached to a crosshair gameobject) then it’s likely that you want to write:

go.get_position("gamecam")

And not:

go.get_position("#gamecam")

The # sign indicates that you want the position of a component attached to the same gameobject that the script is attached to. Also note that it’s not possible to get the position of a component so I’m guessing that the call to go.get_position("#gamecam") either generates an error in the console or returns the position of the game object the script is attached to.

Please read more about message passing and URLs here in the manual. Consider this example to understand the very basics:

The format of a URL is socket:/path#component which in the case above translates to:

mycollection:/mygo#mysprite

So, if I from the crosshair.script need the position of the gamecam the absolute URL would be:

go.get_position("mycollection:/gamecam") -- component can be omitted in this case

Now, the socket is not needed since both game objects exist in the same collection:

go.get_position("/gamecam")

It gets a bit more complex if I add a collection from file and need to reference a game object inside that collection.

2 Likes

I’ve read the manual to this. I quess I understood the main thing (its not SOOO complicated ;))

I’ve made the change you sugguest to me (removing #). Now the coords of the gamecam are different, thanks.
But, that makes me wonder… shouldn’t be the coords of all components the same as the parent (GO)? or min relative to the GO??

Most of the visual components such as sprites, particle effects and so on can be offset from the game object. And if you have a game object hierarchy the positions will obviously be aggregated.

1 Like

ah ok. thanks

1 Like