Force sprite to follow mouse/touch (SOLVED)

Hello everyone,

I am all new to defold and would need some help.
I am working on an top shooter and wants my ship to follow my mouse/touch but it don’t works as i want. I was trying to cap the movement so it wouldn’t go outside the screen but my if wont work. And my other problem is that if i touch somewhere on the screen the ship jumps to that position i want it to move from where it is. Hope you understand=)

function init(self)
	msg.post(".", "acquire_input_focus")
	self.pos = go.get_position()
end


function update(self, dt)
	

end

function on_input(self, action_id, action)
	if action_id == hash("touch") and action.dx then
		local pos
		if action.dx > 0 or action.dx < 640 then
			pos = vmath.vector3(action.x, 150, 0)
		end
		if pos ~= nil then
			go.set_position(pos)
		end
	end
	
end

Thanks

/Isak

There’s some confusion in your script between the self.pos you set in init() and the local pos you modify in on_input(). I would suggest that you keep track of a direction of movement in a script variable, update it in on_input() based on user input and then move and clamp position in update(). Like this (untested):

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

    -- speed in pixels/second
    self.speed = 200
    
	-- direction of movement
	self.direction = vmath.vector3()
end


function update(self, dt)
	-- get current position
	local pos = go.get_position()

	-- move
	pos = pos + self.direction * self.speed * dt

	-- clamp to between 0 and 640
	if pos.x < 0 then pos.x = 0 end
	if pos.x > 640 then pos.x = 640 end

	-- update position
	go.set_position(pos)
end

function on_input(self, action_id, action)
	if action_id == hash("touch") then
	    if action.released then
	        self.direction.x = 0
        else
		    self.direction.x = action.dx
	    end
	end
end
1 Like

Hello @britzl,

Thanks for help, now i have a working control for my spaceship=) Just had to change the speed to 50 instead.

2 Likes

Hi @britzl,

I am not sure if its okey to reply on an solved question but i faced some problems. In the emulator everything worked good with controlling the ship but when i tried to run it on my Oneplus one 3T it don’t behave as i want. If i press in the middle the ship jumps to the right, is this because i have numbers in the script? Should i use % or something like that? In my game.project i have the resolution of 640 x 1136 and my phone has the dimensions 1080 x 1920.

/Isak

Hi!

Have you made any changes, or created your own, render script?

I took a quick look at the code Björn posted above and it looks like it should behave like you initially expected… It will position the ship/gameobject using the relative movement of the touch/mouse. You should also be able to debug it on your computer by just resizing the window to “simulate” a different resolution.

Could you share the part of your script that controls the ship movement? :slight_smile:

1 Like

Hi @sven,

I have changed to fixed_fit_projection i dont really know which projection that works best for mobile games but i felt that one made more sence.

Here is the code that controls the ship:

function init(self)
	msg.post(".", "acquire_input_focus")
	self.speed = 50
	self.direction = vmath.vector3()

end

function update(self, dt)
	local pos = go.get_position()

	pos = pos + self.direction * self.speed * dt

	if pos.x < 0 then pos.x = 0 end
	if pos.x > 640 then pos.x = 640 end

	go.set_position(pos)
	

end

function on_input(self, action_id, action)
	if action_id == hash("touch") then
		if action.released then
			self.direction.x = 0
	
	else
		self.direction.x = action.dx
	end
	end
	
end

I am also wondering how i gets the width of the ship so i can get the ship to stop at the edge of the ship sprite, now it ends in the middle of the ships sprite.

The sprite component has a size property that you can read:

Thanks @britzl,

I dont know if my problem is a bug but if i test my game on the emulator everything works goods, but when i try it on my device several strange things happen, first i get this error:

ERROR:SCRIPT: /main/main.script:5: attempt to index global 'delay' (a nil value)
stack traceback:
	/main/main.script:5: in function </main/main.script:1>

The code it’s pointing to is:

function init(self)
	msg.post(".", "acquire_input_focus")
	self.spawnSpeed = 10

	local id = delay.repeating(1.5, function(self, id)
		local enemyId = math.random(1, 3)
		local enemyType = "enemies#asteroidfactory"

		if enemyId == 1 then
			enemyType = "enemies#asteroidfactory"
		elseif enemyId == 2 then
			enemyType = "enemies#bombfactory"
		elseif enemyId == 3 then
			enemyType = "enemies#ufofactory"
		end
		print(enemyType)
		pos = vmath.vector3()
		pos.x = math.random(160, 480)
		pos.y = 1300
		factory.create(enemyType, pos)
	end)

end

I have the url to the timer set in my game.project.
And the next strange thing that happens is that the ship wont follow my touch, if i touch in the middle the ship jumps to the right and if i touch different places in the x-axis the ship start to jump to different places however not to the position i have touched. It always is on the + side of my touch.

What’s the exact URL you are using? Perhaps you are using an old version of my timer extension, back when it was still called timer.

You could try and replace it with the native timer. Replace:

delay.repeating(1.5, function...)

with

timer.delay(1.5, true, function...)

Thanks @britzl,

That solved that error, in my game.project i had:

https://github.com/britzl/defold-timer/archive/master.zip

it have worked earlier but suddenly it started to give me that error.

However the touch functionality still misbehaves. If i press one place on the x.axis the ship jumps to another place in the x.axis. If i run it in the emulator in only moves when i am dragging it don’t jumps if just touch.

I think you might get a weird dx on the frame where you first touch the screen. Ignore the touch when you get action.pressed == true

Hello @britzl,

I don’t follow know, where am i using action.pressed?

You’re not, but you should. Like this:

function on_input(self, action_id, action)
	if action_id == hash("touch") then
	    if action.released then
	        self.direction.x = 0
        -- ignore first touch since dx&dy will be huge
        elseif not action.pressed then
		    self.direction.x = action.dx
	    end
	end
end
2 Likes

Thanks!

Now it works correct=)

2 Likes