So the problem i'm having is that whenever i press the fire button once it gets called multiple times. I have tried using _process and _physics_process and both give me the same issue.

Here is some backstory of what i'm trying to do:
Basicly i have a WeaponManager scene that handles shooting and ammo. Whenever the ammo reaches zero it instantly starts reloading because the function is getting called multiple times from one click. The interaction should be that ammo reaches zero and if you try to shoot with zero ammo it will go into reloading. But because the function being called multiple times from one press it will go into reloading instantly when it reaches zero,

`extends CharacterBody2D


@onready var weapon_manager: WeaponManager = $WeaponManager

var can_cycle_weapon = true


func _physics_process(delta):
	if Input.is_action_just_pressed("equipWeapon"):
		weapon_manager.equip_weapon()
	
	if Input.is_action_pressed("Fire"):
		weapon_manager.fire_weapon()
		
	if Input.is_action_pressed("unequipWeapon"):
		weapon_manager.unequip_weapon()
		
	if Input.is_action_just_pressed("reload"):
		weapon_manager.reload()


func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_WHEEL_UP and can_cycle_weapon:
			weapon_manager.cycle_weapon(1)
			can_cycle_weapon = false
			await get_tree().create_timer(0.3).timeout
			can_cycle_weapon = true
		elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and can_cycle_weapon:
			weapon_manager.cycle_weapon(-1)
			can_cycle_weapon = false
			await get_tree().create_timer(0.3).timeout
			can_cycle_weapon = true`

Maybe use a bool is_reloading and set it to true the first time when trying to fire with empty magazine and then check if firing and magazine is empty if it is already reloading.

    trizZzle I probably should have posted the WeaponManager right away but i have bools checking for ammo in the gun. Total ammo is the ammo in the inventory and equiped_weapon.ammunition_component.active_ammo_count is the ammo that's currently loaded into the gun.

    func fire_weapon():
    	if firearm_no_ammo && total_ammo > 0:
    		reload()
    		firearm_no_ammo = false
    	elif equiped_weapon && !is_reloading && !firearm_no_ammo:
    		if equiped_weapon.ammunition_component.active_ammo_count > 0:
    			equiped_weapon.fire()
    			firearm_no_ammo = false
    		elif equiped_weapon.ammunition_component.active_ammo_count == 0:
    			firearm_no_ammo = true
    			return
    if Input.is_action_pressed("Fire"):
        weapon_manager.fire_weapon()

    This is going to run really quickly unless there’s some constraint (e.g. like a cool down timer) in fire_weapon

    I guess I misunderstood your question.
    So you want to have the player stop pressing fire and then pressing it again to trigger a reload when magazine is empty?
    But when he still holds fire when the magazine becomes empty no reload should be triggered?

    In that case I would create something like that:

    if Input.is_action_pressed("Fire"):
    		if weapon is !singleshot_weapon and magazine ammo > 0:
                        fire
    
    if Input.is_action_just_pressed("Fire"):
                    if magazine ammo 0:
                           reload
                    elif weapon is singleshot_weapon:
                           fire

    Something like that.

      trizZzle Sorry the problem is that it starts reloading as soon as it reaches zero ammo. Meaning it reloads right after firing the last bullet (without an additional key-press). It should only reload when you attempt to fire while it has 0 ammo. The problem is that the process function i guess calls fire_weapon function multiple times per key-press? Not sure how to fix.

      • xyz replied to this.

        verypogu The method fire_weapon() shouldn't be calling reload() because firing is not reloading. Instead, the function that handles the input should call either one or the other depending on the ammo state. This seems like a nitpick but, as you can see, it confused you enough to lose control over what is happening. Let your functions do only what their name suggests. It'll make your code more readable and its logic easier to follow.

        Also get rid of the abstract weapon_manager because it doesn't represent anything in the real world. Soldiers do not carry any "weapon managers" into fight. They only have weapons that can fire and reload. So your class structure should represent that in the simplest possible way, without funky abstract go-betweens that produce bugs 🙂

          xyz That functions should only be responsible for i guess a single task? Makes alot of sense. In regards to inputs, for me at the time it felt nice if the WeaponManager handled most of the logic so i didnt need to check anything inside of the WeaponManager from the Player script if that makes sense. Do you mean you don't like the name "Weapon Manager"? Or do you mean that you don't like the fact that it handles both firing/reloading/ammo/equiping weapons?
          Thanks!

          • xyz replied to this.

            verypogu The WeaponManager is abstract and thus doesn't really represent anything that exists in your simulated world. It just complicates your modeling by introducing more objects than necessary and with that - more potential bugs. All in the name of looking like you're doing some fancy oo stuff.

            Keep it simple: a weapon should fire and count ammo and the player should equip weapons, reload them and press the trigger. Just like in real world. "Managers" in oo programming are like middle managers in corporations - useless, annoying busybodies that do more harm than good.

            verypogu
            Here's how I'd model a weapon that doesn't need a manager, doctor or lawyer. It can work as a single shot or auto weapon with adjustable fire rate and reloading time and also reloads itself when out of ammo. All that player object now needs to do is call trigger_pressed() or trigger_released() when the fire button is pressed/released:

            class_name Weapon extends Node
            
            # stats
            var fire_delay: float = .2
            var reload_delay: float = 1.2
            var ammo_max: int = 10
            
            # current state
            var firing: bool = false
            var reloading: bool = false
            var delay: float # firing or reloading timer
            var ammo: int = ammo_max
            
            func _process(dt):
            	delay = delay-dt if delay >= 0.0 else delay
            	if delay < 0.0:
            		if reloading:
            			ammo = ammo_max
            			print("RELOAD DONE")
            			reloading = false
            			delay = 0.0
            			
            		elif firing:
            			ammo -= 1
            			print("FIRE (ammo left: " , ammo, ")")
            			if ammo:
            				delay = fire_delay
            			else:
            				reload()
            
            func trigger_pressed():
            	if ammo:
            		delay = 0.0
            		firing = true
            	else:
            		reload()
            	
            func trigger_released():
            	firing = false
            	
            func reload():
            	if not reloading:
            		reloading = true
            		delay = reload_delay
            		print("RELOADING...")

              xyz Yeah that simplifies alot and makes everything easier actually. When would it make sense to use a Manager? Maybe like a Dialogue Manager? Ability Manager?

              I'm pretty new to gamedev/programming. Thanks!

                verypogu When would it make sense to use a Manager?

                Almost never imho. Where did you get this idea of "managers" in the first place?

                  xyz When i first got into Godot i followed a vampire-survivor course and the author made an Experience Manager for player levels, Upgrade Manager that handles player upgrades for abilities and an Enemy Manager for spawning enemies.

                  So that's basicly where i got the idea from.
                  Do you think any of these would be a good example for when to use a Manager?

                  • xyz replied to this.

                    verypogu Do you think any of these would be a good example for when to use a Manager?

                    Nope. All of them sound completely redundant. Looks like something from "everything is an object" school of thinking which I don't subscribe to. Classes are meant to represent instantiable types. If you don't need an instantiable type - you don't need a class.

                    The code can always be organized so that's not encumbered with this "manager" way of thinking. If Experience and Upgrades (from your examples) are properties of a player then the Player class should be responsible for managing them. If Enemies are properties of a level then the Level class should manage their spawning etc. No need to invent some "manager" intermediaries and overcomplicate the system with their existence.

                    I mean just look at your problem in this thread. Has using a weapon manager made things simpler to handle and debug or did it actually contribute to the tangle you ended up in?

                    In problem solving, it's always advisable to follow the principle of Occam's razor. In the context of class system design that'd mean introducing only the classes that are absolutely necessary.

                      xyz Alright that makes sense. I do see now that the WeaponManager makes the code more complex than it has to be and there is no reason for a WeaponManager to even exist. Because right now the Player interacts with the WeaponManager, that then interacts with the Weapon and then the Weapon shoots the bullet. It all would be easier if the Player directly interacts with the Weapon.

                      Another question if i may. I have watched some videos about building out scenes with node components.

                      So for example the Guns have an ammunition_component that stores the current ammo and also sets the max_ammo. A ranged_weapon_stats_component that has variables like max_range and damage. recoil_component.

                      My enemies have a shake_component that handles shaking when a monster is hit and a flash_component that makes them flash for a brief second when hit etc.

                      This to me feels like it makes the code more readable as everything is split up in parts and also more "modular" because if i want to put a flash_component on the player for when he gets hit it's very easy to just add that component to the player.

                      Now some of these do seem a bit redundant to me maybe the ammunition_component is not necassery aswell as the ranged_weapon_stats_component as the main script could have those variables. But do you think this is a good way to structure your project?

                      Thanks again!

                      • xyz replied to this.

                        verypogu When would it make sense to use a Manager?

                        I have ONE in my custom editor plugin for my RPG, a "DatabaseManager" for dynamic objects (characters, items, doors, etc) and dialogue.

                        verypogu Having reusable components is always good, but here too you have to take care not to overdo and overdesign it. Just because something can be made a component, it doesn't mean it should. Exercise economy here as well and be sure that introduction of a component actually simplifies things. Similarly to having too many classes, too many components can create chaos.

                        Unlike some other engines, Godot doesn't have an explicit ECS system. Its equivalent of a component is a scene. So everything that should function as a reusable, self contained component - should be a scene.

                        Your weapon example sure sounds like an overkill. You insist on turning every tiny bit of functionality into a component, just because you can. This is not a very wise design choice as you'd end up with too many of too small components. This is cumbersome to manage mentally, and it also makes statements in your code long and repetitive.

                        Godot's architecture is based mainly on node class inheritance. In many cases it may be better to pack the shared functionality into a base class instead of scattering it among the components. But decision on how to approach it really depends on the system you're trying to model and your stance on the eternal oo conundrum: Is-a vs Has-a

                        To go back to your weapon example, that's definitely too many tiny components. This would be better handled via a base class that holds all of the ranged weapon common functionality. Also, no need to use the word component in component names. It just contributes to annoying longwindedness. Now if you throw in several nested levels of such components and a "manager" or two on top of it, then you'll likely end up having to write a lot of extremely long and similar looking statements just to address some basic properties. For example:

                        player.weapon_manager.equipped_weapon.ammunition_component.current_ammo -= 1
                        enemy.health_manager.current_hp -= player.weapon_manager.equipped_weapon.ranged_weapon_stats_component.damage

                        Doing this a lot will make your code excruciatingly hard to read and understand. Especially when it starts to grow larger. Instead, you should design your class/components structure as well as your naming conventions so it results in simple, easy to read and understand statements like this:

                        player.weapon.ammo -= 1
                        enemy.hp -= player.weapon.damage