Iterating through a table of keyboard keys

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
bbashar
Prole
Posts: 2
Joined: Wed May 26, 2021 1:35 pm

Iterating through a table of keyboard keys

Post by bbashar »

When I started with LÖVE, I used to have an ugly bunch of keyboard callback checks, like these in the code below:

Code: Select all

function love.keypressed(key)
	if key == 'd' then
		player.right = true
	end
	if key == 'a' then
		player.left = true
	end
end
function love.keyreleased(key)
	if key == 'd' then
		player.right = false
	end
	if key == 'a' then
		player.left = false
	end
end
Later, I got rid of them by creating a table with keyboard keys for keys and state variables for values. Iterating through such a table and checking the direction variables looked nice and took less space.

Code: Select all

keys = {
	'a': 'left',
	'd': 'right'
}
--...
function love.keypressed(key)
	for k, d in pairs(keys) do
		if key == k then
			player[d] = true
		end
	end
end
--the same with keyreleased
Is it a good practice to handle callbacks like this? I thought that the table could take some extra memory, especially when you have to check plenty of keys.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Iterating through a table of keyboard keys

Post by grump »

You shouldn't care about using a few bytes more or less of memory. It doesn't matter in the slightest.

What you should care about though is using the correct type of input. If your game uses W/A/S/D for movement and your code responds only to the literal keycode instead of the more appropriate positional scancode, you will make a bunch of French (and some other) people angry.
bbashar wrote: Wed May 26, 2021 1:57 pm

Code: Select all

function love.keypressed(key)
	for k, d in pairs(keys) do
		if key == k then
			player[d] = true
		end
	end
end

Code: Select all

if keys[scancode] then
    player[keys[scancode]] = true
end
User avatar
pgimeno
Party member
Posts: 3672
Joined: Sun Oct 18, 2015 2:58 pm

Re: Iterating through a table of keyboard keys

Post by pgimeno »

grump wrote: Wed May 26, 2021 3:30 pm You shouldn't care about using a few bytes more or less of memory. It doesn't matter in the slightest.

What you should care about though is using the correct type of input. If your game uses W/A/S/D for movement and your code responds only to the literal keycode instead of the more appropriate positional scancode, you will make a bunch of French (and some other) people angry.
bbashar wrote: Wed May 26, 2021 1:57 pm

Code: Select all

function love.keypressed(key)
	for k, d in pairs(keys) do
		if key == k then
			player[d] = true
		end
	end
end

Code: Select all

if keys[scancode] then
    player[keys[scancode]] = true
end
Yes but with the parameter added :)

Code: Select all

function love.keypressed(key, scancode)
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Iterating through a table of keyboard keys

Post by grump »

pgimeno wrote: Wed May 26, 2021 4:03 pm Yes but with the parameter added :)
You gotta leave some of these things as an exercise to the reader ;)

Keycodes being the first argument in keyboard events comes right after love.load on the list of things that should be burned at the stake.
User avatar
tomxp411
Prole
Posts: 29
Joined: Thu Apr 08, 2021 5:41 pm

Re: Iterating through a table of keyboard keys

Post by tomxp411 »

what I did is create a table with each keyboard command, then call it from my love.keypressed function:

My Input.lua file looks like this:

Code: Select all


Input = {
    ["up"] = function(v)
        Player:setSpeed(Player.ctlFwdSpeed * v)
    end,

    ["down"] = function(v)
        Player:setSpeed(Player.ctlBackSpeed * v)
    end,

    ["left"] = function(v)
        Player:setturnSpeed(-Player.ctlTurnSpeed * v)
    end,

    ["right"] = function(v)
        Player:setturnSpeed(Player.ctlTurnSpeed * v)
    end,
}

and in love.keypressed, something like

Code: Select all

function love.keypressed( key, scancode, isrepeat )
	if Input[key] then
		Input[key](1)
	end

	LastKey=key
end

function love.keyreleased(key)
	if Input[key] then
		Input[key](0)
	end

	LastKey = ""
end
So the idea is that a key down event calls the relevant function in Input, with a 1 in the parameter. This turns the movement or rotation on.

Then when the user releases the key, this calls the same function, but with 0 as the parameter. This turns off the movement or rotation.

And, as has been suggested above, it might be wise to use scancodes to actually accomplish this. What I plan to do in the long run is allow the player to map keys, and I'll do some quick function assignments to map the actions to keypresses, kind of like this:

Input[UpKey] = Input["up"]

I have to test whether this actually works, but I think it will do what I'm hoping. If that doesn't work, I can use loadstring to accomplish the same thing, by building a function at runtime that basically just calls the relevant action.

Also, as this is a prototype, I'll probably better encapsulate the functions, so instead of the Input file above, my functions would look like:

Code: Select all

 ["up"] = function(v)
        Player:foward(v)
    end,
 
Then the "forward" action can change dynamically, if the Player object changes. (this actually will change in this game, as the player will switch between different vehicles and on foot requiring different driving and movement controls.)
bbashar
Prole
Posts: 2
Joined: Wed May 26, 2021 1:35 pm

Re: Iterating through a table of keyboard keys

Post by bbashar »

grump wrote: Wed May 26, 2021 3:30 pm You shouldn't care about using a few bytes more or less of memory. It doesn't matter in the slightest.

What you should care about though is using the correct type of input. If your game uses W/A/S/D for movement and your code responds only to the literal keycode instead of the more appropriate positional scancode, you will make a bunch of French (and some other) people angry.
bbashar wrote: Wed May 26, 2021 1:57 pm

Code: Select all

function love.keypressed(key)
	for k, d in pairs(keys) do
		if key == k then
			player[d] = true
		end
	end
end

Code: Select all

if keys[scancode] then
    player[keys[scancode]] = true
end
Thank you!
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 8 guests