How to time keypresses

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
PunchyBreloom
Prole
Posts: 7
Joined: Thu Mar 23, 2017 1:21 am

How to time keypresses

Post by PunchyBreloom »

I am a newbie at coding in love and am trying to make a semi-basic platformer as my first project. I wanted to code the ability to use a 'short hop', pushing the jump button down for a shorter time in order to do a shorter jump. Is this possible, and if so could you explain to me how to do it? I have defined both the short and long jump's velocities already. This in an excerpt from my current main.lua file and I am using love 0.8.0 currently, though plan to upgrade if necessary.

Current code:
if love.keyboard.isDown("up") then
player:jump()
end

What I have unsuccesfully tried:
if love.keyboard.isDown("up") > love.timer.getMicroTime(0.5) then
player:jump()
end

Thank you in advance for your replies!
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: How to time keypresses

Post by zorg »

Hi and welcome to the forums!

First, love.timer.getMicroTime doesn't accept parameters, so that's wrong.

Second, it's strongly recommended to use the latest löve version, unless your computer's specs can't run it (mostly due to the gpu being old).

In any case, there are a few ways to accomplish what you want; here's how i'd do it (I tried to use functions as they worked in 0.8):

Code: Select all

-- This will hold the states for each key.
-- state can be 0,1,2,3 with meanings: depressed, pressed, held and released
-- held is the time the button was held down
local keys = {}
keys.up    = {state = 0, held = 0}
keys.down  = {state = 0, held = 0}
keys.left  = {state = 0, held = 0}
keys.right = {state = 0, held = 0}

function love.load()
	-- Turn off key repeat; in 0.8 it was Löve's own doing, but after, it delegated it to the OS;
	-- i always code my own, so i disable this anyways.
	love.keyboard.setKeyRepeat(0)
end

-- This gets called by Löve whenever a key is pressed, but only at that moment.
-- (unless key repeat is enabled, i usually disable that, see above.)
love.keypressed = function(key)
	if keys[key] then
		keys[key].state = 1 -- Pressed.
		keys[key].held  = 0 -- Clear the time it was held for previously.
	end
end

-- This gets called by Löve whenever a key is released, but only at that moment.
-- (same disclaimer as above.)
love.keyreleased = function(key)
	if keys[key] then
		keys[key].state = 3 -- Released.
	end
end

-- Do most of the stuff in love.update
function love.update(dt)

	-- Iterate over our keys table and update state.
	for key, tbl in pairs(keys) do
		if love.keyboard.isDown(key) then
			if tbl.state == 1 then
				-- It was just pressed.
				doStuffPressed() -- Whatever function you need to do.
				-- Modify state to held and update held time.
				tbl.state = 2
				tbl.held = tbl.held + dt
			elseif tbl.state == 2 then
				-- It was already held for more than one update loop.
				doStuffHeld(tbl.held) -- Do whatever you need to do, the passed parameter holds how long it was pressed down for.
				-- Update held time.
				tbl.held = tbl.held + dt
			end
		else
			-- If state is released, then set state to depressed.
			if tbl.state == 3 then
				-- Just released.
				doStuffReleased(tbl.held) -- If you want to, you can detect a release here.
				tbl.state = 0
			end
		end
	end
end
This may be overcomplicating things a bit, with all keys having 4 "virtual" states, but it does keep track of how long the keys were held down, and you can use that information for whatever you want; also, detecting release may also be important since that should be what stops the ascent of your player.

Edit: Fixed a mistake in my code...
Last edited by zorg on Thu Mar 23, 2017 2:57 pm, edited 1 time in total.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
PunchyBreloom
Prole
Posts: 7
Joined: Thu Mar 23, 2017 1:21 am

Re: How to time keypresses

Post by PunchyBreloom »

Ok, I'll try this! Thank you!
PunchyBreloom
Prole
Posts: 7
Joined: Thu Mar 23, 2017 1:21 am

Re: How to time keypresses

Post by PunchyBreloom »

I've had an issue with my code, this line returns an error- "attempt to index local 'tbl' (a number value)" I updated to the newest version of Love.
if tbl.state == 3 then


Also, did I do this right? juump is just what i called my shorter jump.


local keys = {state = 0, held = 0}
keys.up = {state = 0, held = 0}
keys.down = {state = 0, held = 0}
keys.left = {state = 0, held = 0}
keys.right = {state = 0, held = 0}

function love.load()
love.keyboard.setKeyRepeat(0)
end

love.keypressed = function(key)
if keys[key] then
keys[key].state = 1
keys[key].held = 0
end
end


love.keyreleased = function(key)
if keys[key] then
keys[key].state = 3
end
end


function love.update(dt)


for key, tbl in pairs(keys) do
if love.keyboard.isDown(key) then
if tbl.state == 1 then
player:jump()
tbl.state = 2
tbl.held = tbl.held + dt
elseif tbl.state == 2 then
doStuffHeld(tbl.held) player:juump()
tbl.held = tbl.held + dt
end
else

if tbl.state == 3 then
doStuffReleased(tbl.held)
tbl.state = 0
end
end
end
end
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: How to time keypresses

Post by zorg »

PunchyBreloom wrote: Thu Mar 23, 2017 11:23 am I've had an issue with my code, this line returns an error- "attempt to index local 'tbl' (a number value)" I updated to the newest version of Love.
You're probably getting that error because i had an error in my code; that's what i get for not testing it beforehand. :P

I went through it again, didn't see any other issues, so yes, hopefully it'll work. (Unless you'll have issues with setKeyRepeat not being happy with a 0 being passed to it; if you did update your Löve... switching out 0 for false would do, i think.)

Also, please do use [ code ] [ /code ] tags, it makes source code easier to read.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: How to time keypresses

Post by airstruck »

That seems unnecessarily... hairy.

What I've found to work pretty well is setting the y-velocity to the "max jump velocity" when the key is pressed, and then if it's released while the player is still moving upward, cut the y-velocity in half (or so).

I've attached a small demo (use WASD).
Attachments
jump.love
(731 Bytes) Downloaded 157 times
MrFariator
Party member
Posts: 512
Joined: Wed Oct 05, 2016 11:53 am

Re: How to time keypresses

Post by MrFariator »

If you want to reproduce jumping controls from something like Mega Man, you can just set the vertical speed to 0 if player releases the jump button, and gravity hasn't caught up yet (ie. vertical speed is still such that player is ascending).

For funsies, you can pull the exact movement values for Mega Man titles from here and here. Alternatively for something like Sonic, here is a page for that. Should give you plenty of ideas on how plenty of classic platformers handle their jump arcs.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: How to time keypresses

Post by airstruck »

Worth noting, none of those solutions need to track the amount of time the button was pressed.

That sort of thing seems like the way to go, although setting the velocity to an absolute value (especially 0) feels too abrupt for my liking; I generally prefer something like cutting it in half instead, but of course it depends on the game. Setting it to 0 makes more sense if there are spikes right above your head.
PunchyBreloom
Prole
Posts: 7
Joined: Thu Mar 23, 2017 1:21 am

Re: How to time keypresses

Post by PunchyBreloom »

Well thanks guys, I'll give these suggestions a try!

EDIT: I used airtruck's method and it worked fine, thanks!
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: How to time keypresses

Post by airstruck »

Glad it worked for you. Just want to note a couple of things about that code.

Because the velocity is cut in half whenever the key is released while the character is ascending, it's technically possible to cut the jump short(er) if you're able to hit the key multiple times while the player is still ascending. I couldn't hit the key fast enough to notice a difference, but if it's a concern you can introduce some kind of "isJumping" flag (maybe your character has really strong legs or lives on the moon). Of course this also wouldn't be an issue if you set velocity to a fixed amount on key release, as in the examples MrFariator gave.

Also, the method used for acceleration/velocity/position integration is heavier than usual because it's designed to be accurate under a variable-length timestep. If you use a fixed-length timestep, you can get away with a cheaper approximation, like vel=vel+acc*dt; pos=pos+vel*dt. Of course you can still use the integration method in the demo with a fixed-length timestep if you just want that "extra" accuracy.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 86 guests