Nonexistent function in base 'Nil'

Hello! I’m new to game developing on this engine and am having some problems. While most of them I were able to solve with internet, I couldn’t find a solution to this issue that works for me.

Here’s the script that tries to call a function:

extends Node2D

@onready var itemWeapon = $ItemWeapon

var weapon_pistol = ["Pistol", "pistol", 1, 0.3, 5, "pistol", 3, 30, 1, 5, 10, 1000, 0, 10, 0, 0]

func create_weapon(w):
	itemWeapon.create_weapon(w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7], w[8], w[9], w[10], w[11], w[12], w[13], w[14], w[15])

Here’s the ItemWeapon script, which belongs to child node of the first

extends Node2D

class_name ItemWeapon

var WeaponName: String			#name of a weapon
var WeaponType: String 			#type(pistol, rifle, etc)
var ShootsBullet: int		#whether or not spawns bullets
var FireRate: float			#delay between shots in seconds
var AmmoMag: int			#shots before reload
var AmmoType: String		#type of ammo used
var ReloadTime: float		#delay in seconds
var Damage: float			#damage on hit
var Multishot: int			#amount of bullets per shot
var Spread: int				#spread in degrees
var MultishotSpread: int	#spread in degrees
var BulletSpeed: int		#speed of bullet
var CurrentAmmo: int		#ONLY USED WHEN IN HAND
var TimeRange: float		#Time in seconds before bullet dies
var BulletBounce: int		#How many times will bounce
var BulletPenetration: int	#How many times will penetrate

func create_weapon
(weaponName:String,
weaponType:String,
shootsBullet:int,
fireRate:float,
ammoMag:int,
ammoType: String,
reloadTime:float,
damage:float,
multishot:int,
spread:int,
multishotSpread:int,
bulletSpeed:int,
currentAmmo:int,
timeRange:float,
bulletBounce:int,
bulletPenetration:int):
	var newWeapon = ItemWeapon.new()
	newWeapon.WeaponName = weaponName
	newWeapon.weaponType = weaponType
	newWeapon.ShootsBullet = shootsBullet
	newWeapon.FireRate = fireRate
	newWeapon.AmmoMag = ammoMag
	newWeapon.AmmoType = ammoType
	newWeapon.ReloadTime = reloadTime
	newWeapon.Damage = damage
	newWeapon.Multishot = multishot
	newWeapon.Spread = spread
	newWeapon.MultishotSpread = multishotSpread
	newWeapon.BulletSpeed = bulletSpeed
	newWeapon.CurrentAmmo = currentAmmo
	newWeapon.TimeRange = timeRange
	newWeapon.BulletBounce = bulletBounce
	newWeapon.BulletPenetration = bulletPenetration
	
	return newWeapon
	

I know this is not the most elegant style of writing. It works for me in other cases

You might have an issue with so many arguments. I think There may be a limit.

Also that seems horrible to me… I would break the weapon into multiple sub classes. And then use a factory to assemble all the components individually before wrapping it into the main weapon class.

Divide responsibility, instead of a monolith.

It means that the variable you are trying to access is not available yet. Probably because you called the function before the node was ready. Try:

func create_weapon(w):
	if not is_node_ready():
		await ready
	itemWeapon.create_weapon(w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7], w[8], w[9], w[10], w[11], w[12], w[13], w[14], w[15])

But you should not do this like that. You should be using custom resources for data containers. Change your ItemWeapon to a Resource like:

extends Resource

class_name ItemWeapon

## Name of a weapon
@export var WeaponName: String			
## Type(pistol, rifle, etc)
@export var WeaponType: String 			
## Whether or not spawns bullets
@export var ShootsBullet: int		
## Delay between shots in seconds
@export var FireRate: float			
## Shots before reload
@export var AmmoMag: int			
## Type of ammo used
@export var AmmoType: String		
## Delay in seconds
@export var ReloadTime: float		
## Damage on hit
@export var Damage: float			
## Amount of bullets per shot
@export var Multishot: int			
## Spread in degrees
@export var Spread: int				
## Spread in degrees
@export var MultishotSpread: int	
## Speed of bullet
@export var BulletSpeed: int		
## ONLY USED WHEN IN HAND
@export var CurrentAmmo: int		
## Time in seconds before bullet dies
@export var TimeRange: float		
## How many times will bounce
@export var BulletBounce: int		
## How many times will penetrate
@export var BulletPenetration: int	

So you can create the different ItemWeapon from the editor by creating a new Resource in the FileSystem dock right-clicking and selecting Create New / Resource.... Search for ItemWeapon and create an save it in the inspector. Then you can use that Resource file you saved as the ItemWeapon data in your nodes like:

extends Node2D

@export var item_weapon:ItemWeapon

func _ready() -> void:
	$WeaponNameLabel.text = item_weapon.WeaponName
	$WeaponTypeLabel.text = item_weapon.WeaponType
	# more stuff

Bullet class

Mag class

var AmmoMag: int			#shots before reload
var AmmoType: String		#type of ammo used
var ReloadTime: float		#delay in seconds

Should move responsibility somewhere else.

var CurrentAmmo: int		#ONLY USED WHEN IN HAND

The rest could maybe stay, it gets a little tricky.

Can you please elaborate on the first solution? When I tried it, it gave an error higher on dependency tree, “Trying to call an async function without ‘await’.”

I’ve tried to move it higher, but the original issue resurfaced.

I will try to use the second approach if the first one yields no result