Sharky_rex
Sharky_rex

Reputation: 1

Running a godot gdscript about an fps shooter game

i'm using this tutorial on youtube(https://www.youtube.com/watch?v=pgMiiUSRvSM&t=1304s) to make an fps shooter game in godot and i'm quite new to it when i tried to run the script i have an error in the weapon_manager.gd script saying, Attempt to call function 'update_weapon_ui, in base 'null instance' on a null instance

this is the screenshot of my node tree that this script is attached to enter image description here

extends Spatial

# All weapons in the game
var all_weapons = {}

# carrying weapons
var weapons = {}

# HUD
var hud

var current_weapon
var current_weapon_slot = "Empty"

var changing_weapon = false
var unequipped_weapon = false

var weapon_index = 0

func _ready():
    
    hud = owner.get_node("HUD")
    
    all_weapons = {
        "Unarmed" : preload("res://weapons/Unarmed.tscn"),
         'Pistol' : preload("res://weapons/Pistol.tscn"),
        "Rifle" : preload("res://weapons/Rifle.tscn")
    }
    
    weapons = {
        "Empty" : $Unarmed,
        "Primary" : $Rifle,
        "Secondary" : $Pistol
    }
    
    # Initialize references for each weapons
    for w in weapons:
        if weapons[w] != null:
            weapons[w].weapon_manager = self
            weapons[w].player = owner
            weapons[w].visible = false
    
    # Set current weapon to unarmed
    current_weapon = weapons["Empty"]
    change_weapon("Empty")
    
    # Disable process
    set_process(false)



# Process will be called when changing weapons
func _process(delta):
    
    if unequipped_weapon == false:
        if current_weapon.is_unequip_finished() == false:
            return
        
        unequipped_weapon = true
        
        current_weapon = weapons[current_weapon_slot]
        current_weapon.equip()
    
    if current_weapon.is_equip_finished() == false:
        return
    
    changing_weapon = false
    set_process(false)



func change_weapon(new_weapon_slot):
    
    if new_weapon_slot == current_weapon_slot:
        current_weapon.update_ammo() # Refresh
        return
    
    if weapons[new_weapon_slot] == null:
        return
    
    current_weapon_slot = new_weapon_slot
    changing_weapon = true
    
    weapons[current_weapon_slot].update_ammo() # Updates the weapon data on UI, as soon as we change a weapon
    update_weapon_index()
    
    # Change Weapons
    if current_weapon != null:
        unequipped_weapon = false
        current_weapon.unequip()
    
    set_process(true)




# Scroll weapon change
func update_weapon_index():
    match current_weapon_slot:
        "Empty":
            weapon_index = 0
        "Primary":
            weapon_index = 1
        "Secondary":
            weapon_index = 2

func next_weapon():
    weapon_index += 1
    
    if weapon_index >= weapons.size():
        weapon_index = 0
    
    change_weapon(weapons.keys()[weapon_index])

func previous_weapon():
    weapon_index -= 1
    
    if weapon_index < 0:
        weapon_index = weapons.size() - 1
    
    change_weapon(weapons.keys()[weapon_index])




# Update HUD
func update_hud(weapon_data):
    var weapon_slot = "1"
    
    match current_weapon_slot:
        "Empty":
            weapon_slot = "1"
        "Primary":
            weapon_slot = "2"
        "Secondary":
            weapon_slot = "3"
    
    hud.update_weapon_ui(weapon_data, weapon_slot)

i tried to rewatch the tutorial and see what i miss but it didn't work i don't understand why this has an error

Upvotes: 0

Views: 103

Answers (1)

Theraot
Theraot

Reputation: 40315

The error is telling you that hud is null, which means that the following line failed:

hud = owner.get_node("HUD")

You should also get an error about that.

That failed because isn't a node called HUD as direct child of the root of the edited scene that has the node that the shown script attached.

To clarify, owner is the root of the edited scene (Player in this case). And get_node("HUD") is looking for a direct child with the name property set to "HUD".

I'll give you three solution from more efficient to less efficient.


The first solution is to move HUD so it is a direct child of Player. Then the following line should work:

hud = owner.get_node("HUD")

A variant of this would be to use the fixed path for the current location of HUD instead of moving HUD. Then you need this code:

hud = owner.get_node("Camroot/HUD")

Notice that the parameter of get_node is the path to get to the node you want in the scene tree.


The second solution is to use Scene Unique Nodes. To do that open the context menu on HUD on Scene, and select "% Access as Unique Name". That will allow you to get it like this:

hud = owner.get_node("%HUD")

Yet another option is to export a NodePath:

export var hud_path:NodePath

Which you can set to the correct node in the inspector. And then you do this to retrieve it:

hud = owner.get_node(hud_path)

A wildly different approach to do this is by adding the HUD to a node group, which you can do in the Node panel Groups tab. For example if it is in the "hub" you could do this:

hud = get_tree().get_nodes_in_group("hub")[0]

Notice that this is not limited to the currently edited scene, and also that it get_nodes_in_group gives us an array and with [0] I'm getting the first element (assuming there is one). A more proper usage would get the array and check if it is empty.

As you can imagine, node groups work better if you are interested in a, well... group of nodes, instead of a single one.


The third solution is to use find_node:

hud = owner.find_node("%HUD")

Then it will iterate over all the nodes in the scene until it finds one called "HUD".

Upvotes: 0

Related Questions