Simple WASD movement (SOLVED)

Is there a way to get movement controls with wasd that is simple and fast. I read through the input stuff in the manual and that gives me one jump from a to b per button press. does on_input not loop? is there a way to just do this in update were we can just do a if(buttonpressed == d){ player.x += speed * deltatime} or do we really have to use the physics stuff to move something? It just seems like a bunch of extra work to get simple movement working.

The on_input function will be called every frame if a button is pressed, so do something like:

  1. Map the buttons in game.input_binding so you have “w” mapped to a key trigger with input “up” for instance
  2. In on_input:
self.speed=vmath.vector3()
if action_id==hash("up") then
  self.speed.y=1
end
if action_id==hash("right") then
  self.speed.x=1
end
etc...

And in update:

function update(self, dt)
   player.speed=self.speed*dt
   ....
end
2 Likes

Johan,

Thanks for the reply however for some reason I cant get this to work and now i feel like an idiot. Defold works so different from anything I am used to. It doesn’t help that all the editor does id give me a red x and nothing else which makes it hard to figure out what is going on

OK I think I got it first problem I was having was I was still adding action.pressed which turns out was half of my problem the rest of what I ended up with and I am just guessing here but its what I got when it stopped saying things like attempt to perform arithmatic on a nil value or = expected near speed and other various things . Its no longer complaining. Any way this is what I got if you or someone else wouldnt mind looking it over to make sure that i got this down. It is moving in eight directions finally but I want to make sure that I am doing the multiplication by delta time right so that we are getting those benifits. Thanks in advance.

local speed = 5

function init(self)
– Add initialization code here
– Remove this function if not needed
msg.post(".", “acquire_input_focus”)

end

function final(self)
– Add finalization code here
– Remove this function if not needed
end

function update(self, dt)
– Add update code here
– Remove this function if not needed
self.speed = speed * dt
end

function on_message(self, message_id, message, sender)
– Add message-handling code here
– Remove this function if not needed
end

function on_input(self, action_id, action)
– Add input-handling code here
– Remove this function if not needed
local pos = go.get_position()
if action_id == hash(“move_up”)then
pos.y = pos.y + speed
end
if action_id == hash(“move_down”)then
pos.y = pos.y - speed
end
if action_id == hash(“move_left”)then
pos.x = pos.x - speed
end
if action_id == hash(“move_right”)then
pos.x = pos.x + speed
end
go.set_position(pos)
end

function on_reload(self)
– Add reload-handling code here
– Remove this function if not needed
end

@Travis_Mix It looks ok, but I have some comments:

Local vs self vs global
You should read up on and understand Lua scopes. The local speed = 5 at the top will be shared by all instances of game objects with this script attached. Maybe you intend this, maybe you don’t. If you only have one instance of this script then it’s ok, and you probably only have one player controlled game objects, but still it’s worth mentioning. I’ve tried to explain the scopes in Defold in this post.

Set speed in on_input() and move in update()
I would recommend that you set the speed of your game object when you detect input and then apply dt and move the game object in update(). Maybe something like this:

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

function update(self, dt)
	local pos = go.get_position()
	pos = pos + (self.speed * dt)
	go.set_position(pos)
end

function on_input(self, action_id, action)
	if action_id == hash("move_up") then
		-- this might look strange but it's a compact form of if-elseif-else
		-- if action.pressed is true self.speed.y will be set to 1
		-- if action.pressed is false self.speed.y will be set to 0
		-- if neither is true (eg action.repeated) then self.speed.y will remain as it is
		self.speed.y = (action.pressed and 1) or (action.released and 0) or self.speed.y
	elseif action_id == hash("move_down") then
		self.speed.y = (action.pressed and -1) or (action.released and 0) or self.speed.y
	elseif action_id == hash("move_left") then
		self.speed.x = (action.pressed and -1) or (action.released and 0) or self.speed.x
	elseif action_id == hash("move_right") then
		self.speed.x = (action.pressed and 1) or (action.released and 0) or self.speed.x
	end
end
1 Like

Britzl,

well it sorta works but mine worked better though I ended up making a small tweak after my post. The problem with your code here is that it at random stops movement in certain directions which is weird. It however was nice to see a different form of if the way you did it. Also the reason for the local that I had was without it the script wasnt working. It is still really weird for me to have my movement code seperated over multiple functions and doesnt make any sense at all.

@britzl I’m really having trouble getting anything to move on screen. I’ve used your exact script and I can see the position being updated on the game object after go.set_position is run and I’m holding down a direction key. However, nothing moves on screen and the new position value is constant in every frame. Then when I release the key, it returns to the original position value! My game object just contains a sprite, a collision object and the script.

Ok, after writing that I realised I should probably try removing the collision object and that fixed it. I guess the default friction/mass values were preventing the object from moving at all.

If you have a dynamic collision object you cannot move the game object - the physics engine does all movement. A kinematic object can be moved though.

See http://www.defold.com/manuals/physics/#_collision_objects

4 Likes

Of course, I should have known that from my brief experience with Unity. Thanks.

4 Likes

@blues_driven I am having a similar issue as well. Would you mind giving some additional info on how you were able to resolve you issue? I attempted digging through Defold trying to find any form of collision settings and I’m having issues locating any. Thanks!

@tmscaf Could you please explain the setup you have and what you are trying to do? Do you have a game object with a collision component? If so, is that collision component of type Dynamic or Kinematic? If it is Dynamic then the only way to move it is through apply_force messages. If it is Kinematic then you can move it by directly manipulating its position using go.set_position()

@britzl - At the moment, I don’t believe that my game object/sprite has any collision component as I personally didn’t add one. And secondly I didn’t see anything while looking.

What I’ve created is very basic at the moment as I was testing the waters with Defold. I recently heard about it at the GDC. I have a simple sprite that responds with walking animations when W,A,S,D is used. I have a character script, a main collection, an atlas for my sprite, and the inputs defined in game.input_binding. I was working from the tutorial Gamesfromscratch - Sprites and animations.

So I can say that I have very little done at this point.

Yay! Maybe we met at the Defold booth?

Ok, cool, so you’ve just got started! But what was the issue that you were having then? From your latest post it sounds as if stuff is working.

The animations are working correctly and responding to the key inputs, however what I’m trying to get working is the actual physical x,y movement of the Sprite with the animations. Currently the Sprite is walking in place and not traveling anywhere in the x,y plane in relation to the directional key being pressed.

Can you share the script here?

Below is a copy of my character script. I removed the animation portion of the “toggle_right” in attempts to see if I could simply get it to move across the screen on the x axis, but no luck.

--local currentAnimation = 0

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


function update(self, dt)
	local pos = go.get_position()
	pos = pos + (self.speed * dt)
	go.set_position(pos)

end

function on_message(self, message_id, message, sender)
	-- Add message-handling code here
	-- Remove this function if not needed
end

function on_input(self, action_id, action)
	
-- Input Right	
	if action_id == hash("toggle_right")then
			--msg.post("#sprite", "play_animation", { id = hash("malewalkRight") })
			--self.currentAnimation = 0 
			self.speed.x = (action.pressed and 1) or (action.released and 0) or self.speed.x
--Input Left	
	else if action_id == hash("toggle_left") and action.pressed == true then
		if self.currentAnimation == 1 then
			msg.post("#sprite", "play_animation", { id = hash("malewalkLeft") })
			self.currentAnimation = 0
		else
			msg.post("#sprite", "play_animation", { id = hash("maleidleLeft") })
			self.currentAnimation = 1
		end	
--Input Up
	else if action_id == hash("toggle_up") and action.pressed == true then
		if self.currentAnimation == 1 then
			msg.post("#sprite", "play_animation", { id = hash("malewalkUp") })
			self.currentAnimation = 0
		else
			msg.post("#sprite", "play_animation", { id = hash("maleidleUp") })
			self.currentAnimation = 1
		end	
--Input Down
	else if action_id == hash("toggle_down") and action.pressed == true then
		if self.currentAnimation == 1 then
			msg.post("#sprite", "play_animation", { id = hash("malewalkDown") })
			self.currentAnimation = 0
		else
			msg.post("#sprite", "play_animation", { id = hash("maleidleDown") })
			self.currentAnimation = 1
		end	
	
	end
	end
	end	
	end
end

Ok, I see two problems:

  1. It’s elseif not else if You shouldn’t have all those end statements at the end of the on_input function. What you’ve done is to create some weird nested if-else conditionals.
  2. If you print self.speed in update() you’ll notice that the speed is 1, which means 1 pixel per second (ie very slow). You need to multiply the speed vector with the pixels per second as well as with dt. pos = pos + self.speed * 100 * dt to move 100 pixels per second in whatever direction it is moving.

@britzl - You’re right! It is moving…VERY SLOWLY. As soon as you pointed that out, I went back and looked at it, and it’s moving. Just very slowly! Thank you so much. Greatly appreciated.

2 Likes