To add_child while holding down a key

Godot Version

4.5

Question

I have a function that add_child. I can activate it with input.event is_pressed().

ex.

input.event is_pressed()

activate_add_child()

Now I also want to activate it while that key is being press with a condition changed (eg. bool = true).

ex. something like this

if input.event is_being_pressed()### while holding down key
if bool = true
activate_add_child()

The problem is Event.is_pressed() will only register when button is pressed and having bool in _process will add child every frame.

How should I go about it? Thanks

Adding a child every frame sounds like a bad idea, which is what you seem to describe in the first quote, but it sounds like you’ve accomplished this in the second quote.

Maybe you should describe your big-picture goal? What is the project you are working on that requires adding a child while a button is held down?

if input.event is_pressed(): ### while holding down key
  if bool_var1 == true:
    bool_var1 = false
    activate_add_child()

This will only trigger once.


If you don’t want to modify the boolean condition, you can do this:

class_name XXX
var _triggered = false

func test() -> void:
  if input.event is_pressed():
    if not _triggered and __bool__:
      _triggered = true # Avoid repeated triggering
      activate_add_child()
    pass
  else:
    _triggered = false # After releasing the button, it can be triggered again
    pass
  pass

# 'pass' is not necessary, it is just to make the code appear more aesthetically pleasing in the forum.

@gertkeno @yihrmc

It’s a weapon selection system I have. I made it so that I can change weapon by collecting item or just manually pressing a key to cycle through them. It’s the manual change weapon that I’m trying to make it keep shooting while cycle through them.

if event.is_action_pressed("weapon"):
	shot_type += 1
	if shot_type >=5:
		shot_type = 0

It’s fine if the weapon is a bullet type that can be shot in process, physic_process.

Some weapon though,for example, is a flame thrower.tscn and I have to add_child it once when pressing “Shoot” (MOUSE_BUTTON_LEFT).
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
if shot_type == 2:
activate_flame_thrower()

With this current code when I’m holding down “Shoot” while cycle to shot_type 2 it won’t activate_flame_thrower(). I have to release the “Shoot” button first then press it again for it to work.

Example above shows I’m holding “shoot” button while cycle through weapons. The non-shooting part suppose to be a flame-thrower.

Looks like your code logic is getting complex. Wrapping and designing the code properly will make implementation easier. I wrote a weapon system for you:

# weapon_system.gd

var _weapon_list: Array[Object]
var _weapon_current_index := 0
var _weapon_activated := false

func add_weapon(p_weapon: Object) -> void:
	_weapon_list.append(p_weapon)

func remove_weapon(p_weapon: Object) -> void:
	if not _weapon_list.has(p_weapon):
		return
	if _weapon_list.size() > 1:
		var current_weapon := get_weapon(_weapon_current_index)
		if p_weapon == current_weapon:
			next_weapon()
		pass
	_weapon_list.erase(p_weapon)
	pass

func get_weapon(p_index: int) -> Object:
	if p_index < 0 || p_index >= _weapon_list.size():
		return null
	return _weapon_list[p_index]

## Switch to the next weapon
func next_weapon() -> void:
	if _weapon_list.size() <= 1:
		# When there is no weapon or only one weapon,
		# there is no need to switch.
		return
	var old_weapon := get_weapon(_weapon_current_index)
	_weapon_current_index = (_weapon_current_index + 1) % _weapon_list.size()
	var new_weapon := get_weapon(_weapon_current_index)
	
	if not _weapon_activated:
		# Because '_weapon_activated == false',
		# there was no weapon to fire before,
		# and there is no need to fire a weapon afterwards
		return
		
	# Close the old weapon that is currently firing
	if new_weapon != old_weapon and old_weapon != null:
		old_weapon.call(&"set_activated", false)
		
	# Let the new weapon fire
	new_weapon.call(&"set_activated", true)
	pass

## Set whether to continue firing
func set_weapon_activated(p_activated: bool) -> void:
	if _weapon_activated == p_activated:
		return
	_weapon_activated = p_activated
	var weapon := get_weapon(_weapon_current_index)
	weapon.call(&"set_activated", p_activated)

This is an example of a weapon that requires continuous firing:

# weapon1.gd
extends Node

var _activated := false

func set_activated(p_activated: bool) -> void:
	_activated = p_activated
	
func _physics_process(delta: float) -> void:
	if not _activated:
		return
	# Continuous firing ...
	# ...

This is an example of a flamethrower, a weapon that only has a switch:

# flamethrower.gd
extends Node

func set_activated(p_activated: bool) -> void:
	if p_activated:
		# Open the flamethrower ...
		# ...
		pass
	else:
		# Turn off the flamethrower ...
		# ...
		pass

Then add the weapon class instance to the weapon system, and that’s it.

When the button is pressed, call weapon_system.set_weapon_activated(true);

when the button is released, call weapon_system.set_weapon_activated(false).

2 Likes

Thank you for this. For now though I decided to keep my current weapon system because I wrote it and understand it better. Not to mention other part of game need to be rewrite to accommodate the new system. I consider myself somewhere between novice and intermediate coder so this would take a while to do so.

However I will study your system and try to implement it on another project.

As for the holding down key problem, it’s not really part of the game but for myself to quickly switch weapon for testing during game time. If the key logic is getting too complicated then I can live with some weapon not shooting while holding down the key.:+1:

func _process(dt):
	if Input.is_action_just_pressed("switch_weapon"):
		if Input.is_action_pressed("trigger):
			# switching occured this frame while trigger is held
		else:
			# switching occured this frame, trigger not held
	else:
		if Input.is_action_pressed("trigger"):
			# no switching this frame, trigger is held
2 Likes

So simple :laughing: It works now thanks so much!

Here I put it in the _input(event). Looks a bit odd having “if Input” in the “if event” but it works so…:see_no_evil_monkey:

if event.is_action_pressed("weapon"):
	shot_type += 1
	if shot_type >=6:
		shot_type = 1
	if Input.is_action_pressed("shoot"):
		if shot_type == 3:
			activate_flame_thrower()
		if shot_type == 4:
			activate_laser_raycast3d()