How to do different actions depending on if an input is held or pressed

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By balaazs

so i am making a game where bullets are used to open doors/used as currency and i want to make it so when you press R you put bullets into the remaining holes in the revolver cylinder (basically reserveBullets = reserveBullets + (bulletsInCylinder - 6)) but i want to make it so when you hold R it ejects from the cylinder into your reserve to be used as keys/currency (reserveBullets = reserveBullets + bulletsInCylinder/bulletsInCylinder = 0) but i can’t figure out a way of doing it without the press action lagging.

My current method:


@onready var timer = $1secTimer 

var reserveBullets = 12
var bulletsInCylinder = 4

func _physics_process(delta):
	if Input.is_action_just_pressed("reload"):
		timer.start
		await(timer.timeout)
		if Input.is_action_pressed("reload"):
			reserveBullets = reserveBullets + bulletsInCylinder
			bulletsInCylinder = 0
		else:
			reserveBullets = reserveBullets + (bulletsInCylinder - 6)
:bust_in_silhouette: Reply From: jgodfrey

Here’s a first stab that I think does what you’re describing. However, it’s way more complicated than is likely necessary and can probably be refactored / simplified with some thought.

var threshold_time = 0.2
var timer = 0
var action_started = false

func _physics_process(delta):
	if Input.is_action_just_pressed("reload"):
		action_started = true
		
	if Input.is_action_pressed("reload") and action_started:
		timer += delta
		
	if timer >= threshold_time and action_started:
		action_started = false
		timer = 0
		print("hold")

	if Input.is_action_just_released("reload"):
		if timer < threshold_time and action_started:
			print("press")
		action_started = false
		timer = 0

The threshold_time controls how long the reload key needs to be held down to trigger the “hold” message. If the reload key is pressed and released in less time than threshold_time, that triggers the “press” message.

So, you can add your own logic in place of the two print statements…

Note - I just edited the above code to make a minor simplification…

jgodfrey | 2023-07-01 15:21

3 Likes

I was in a bit of a mental hole with this problem myself, and I wanted to add to the forum what I believe to be a good solution with appropriate cancelling for cases in which the user stops pressing one of two opposing directions (they should move in the direction of the button still held). It is written to work within a standard _process call.

This additionally takes care of removing a visual “jitter” that would otherwise occur if both are held:


#preamble
var hold_minimum: float = 0.2
var hold_timer: float = 0.0
var action_started: bool= false

func some_func(delta)
#left
	if Input.is_action_just_pressed("left") or (Input.is_action_pressed("left") and Input.is_action_just_released("right")): #move left
		hold_timer = 0
		print("go left once. (NO *delta here)")
		action_started = true
	if Input.is_action_pressed("left") and action_started == true:
		hold_timer += delta
	if hold_timer >= hold_minimum and action_started and Input.is_action_pressed("left"):
		print("go left repeatedly (*delta statement here)")
	
#right
	if Input.is_action_just_pressed("right") or (Input.is_action_pressed("right") and Input.is_action_just_released("left")): #move right
		hold_timer = 0
		print("go right once. (NO *delta here)")
		action_started = true
	if Input.is_action_pressed("right") and action_started == true:
		hold_timer += delta
	if hold_timer >= hold_minimum and action_started and Input.is_action_pressed("right"):
		print("go right repeatedly (*delta statement here)")
	
	#both
	if Input.is_action_pressed("right") and Input.is_action_pressed("left"):
		action_started = false

If there is a better solution to this please let me know. I’m interested.