How do I make my player consistently move with keys? (WINDOWS EXCLUSIVE)

Hey guys! I started with Solar2D 4 weeks ago and it’s been going pretty well. Now, I want to make games for windows only (no android settings, etc)- and I wrote a player movement script. It moves, except that I’d have to press the key repeatably, rather than holding it down to move.

local function move(event) -- Uses keys to move. Event is just the class that we access to use values if event.keyName == "a" then --print(event.keyName.." was pressed on "..event.phase) player.x = player.x - 5 end if event.keyName == "d" then player.x = player.x + 5 end end

Cheers.

You can take a look at my Knight sample project from the playground:

I would split this into two functions: a key press checker which records whether a key is being held, and a frame listener which updates the player every frame based on which keys are recorded as being pressed:

local pressedKeys = {}

local function onKeyEvent(event)
    if event.phase == "down" then
    	pressedKeys[event.keyName] = true
   	else
   		pressedKeys[event.keyName] = false
   	end
end


local function onEnterFrame(event)
	if pressedKeys["a"] then
		player.x = player.x - 5
	end
	if pressedKeys["d"] then
		player.x = player.x + 5
	end
end


Runtime:addEventListener( "key", onKeyEvent )
Runtime:addEventListener( "enterFrame", onEnterFrame )

Thank you so much for this, cheers!!! Quick question: What does pressedKeys[event.keyName] = true mean? Why not check for the keys? What does true mean in this context?

Edit: Nevermind, I checked this out

To clarify:
True/false in this context simply means “is held down” or “is not held down”. Checking the key presses themselves is not sufficient, as pressing a key only triggers a single key event (regardless of whether it is tapped or held down). You need to keep a record of it being pressed in your code and then clear that record when the key is released - which is what the pressedKeys table is doing.

In my example, when the “a” key is pressed on the keyboard the onKeyEvent function will be triggered with event.keyName being “a” and event.phase being “down”. So my code says: populate the pressedKeys table, using the event.keyName as the key, and true as the value.
The result would be the same as manually writing out:
pressedKeys["a"] = true
Of course writing it out manually like this means it wouldn’t handle other keys, whereas using event.keyName allows it to keep track of all keys being held.

When the key is released the same function will be called, this time with phase == “up”. This in turn will set the pressedKeys value for that particular keyName to false (similar to manually coding it as pressedKeys["a"] = false)

The second part of this is the enterFrame function. This function will run every single frame, and check the current state of the key presses (as recorded in the pressedKeys table). If the key is being held during a frame, it will adjust the x position accordingly. If it’s still being held in the next frame it will adjust it again, and so on. Once the value for that key is set to false (or nil) it will stop updating the player in that direction.

1 Like

Thank you.

I just reached home and tested it, but it seems like its returning me an error.

local function onKeyDown(event) local keyN = event.keyName if event.phase == "down" then keys[event.keyN] = true else keys[event.keyN] = false end end

Table index is ‘nil’. And whenever I remove it, the keys won’t respond. Now, I have thought of a solution, but I forgot.

Edit: I fixed it, Turns out I mixed up the Runtime event listeners!

It’s broken because you are trying to index event.keyN instead of either event.keyName or your local variable keyN

1 Like