Problem
I am trying to instantiate a scene which i give to my scriped via an export variable of type PackedScene. I set up the variable and loaded the scene in the inspector as explained in the "first 3D game" tutorial.
But it is null and i can not find out why it wont load the scene through the Inspector.
If i try loading it directly through ia resource path it works. I printed the var in the _ready()
and the _process()
functions.
Any idea what causes this and how it can be fixed or avoided?
The code can be seen in the image as well as the loaded scene.
Link-to-img.
Here the same part as code cell:
@export var weapon0 = PackedScene.new()
@onready var weapon1: PackedScene = preload("res://scenes/Weapons/base_weapon.tscn")
## initialize stast for player ship
func _init():
var ship = ShipVariables.new(8, 5, 100, 0, 50, 0.2)
super._init(ship)
func _ready():
#ingametarget = get_tree().get_root().get_node("main/test")
# Create Weapon
print("ready:")
print(weapon0)
print(weapon1)
print("----------------------------")
Console Output:
ready:
<null>
<PackedScene#-9223372009608575851>
----------------------------
process:
<null>
-------
Both weapon0
and weapon1
load the same scene as resource. (I also tested using load
instead of preload
and without using @onready
annotation both works as well only the @export var
won't work.)
Additonal Code in case it is relevant:
Full PlayerShip class:
extends "res://scenes/BaseShip.gd"
var ingametarget
#@export var weapon: PackedScene
@export var ammo = PackedScene.new()
@export var weapon0 = PackedScene.new()
@onready var weapon1: PackedScene = preload("res://scenes/Weapons/base_weapon.tscn")
## initialize stast for player ship
func _init():
var ship = ShipVariables.new(8, 5, 100, 0, 50, 0.2)
super._init(ship)
func _ready():
ingametarget = get_tree().get_root().get_node("main/test")
# Create Weapon
print("ready:")
print(weapon0)
print(weapon1)
var testnode = get_node("weaponslot1")
print(testnode)
print("----------------------------")
#instantiate_weapon(weapon0)
#set_projectile_for_weapon("weapon0", ammo)
# Get the gravity from project settings
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
## Get the input from the player based on the four axis (left right top bottom)
## returns it as 2D Vector (note y component is the z component if used in 3D)
## y itself (up) is empty in this vector
func get_player_input() -> Vector2:
var input = Input.get_vector("move_left", "move_right", "move_top", "move_bottom")
return input
func _physics_process(delta):
velocity = calc_velocity(get_player_input())
move_and_slide()
func _process(delta):
## debugging stuff with "b"
if Input.is_action_just_pressed("debug_btn"):
print("process:")
print(weapon0)
print("-------")
#print("shooting")
#shoot_weapon(ingametarget.position)
#print(ingametarget.position)
#transform = transform.looking_at(ingametarget.position)
The BaseShip class:
extends CharacterBody3D
#Stats
var ship_vars : ShipVariables
## init function that can be called by inheriting scenes to set vars
func _init(ship_vars_class):
self.ship_vars = ship_vars_class
## Load the weapon scene
## instanciate the weapon in a weapon slot
func instantiate_weapon(w0: PackedScene) -> void:
# set in variable class
self.ship_vars.load_weapon0_scenes(w0)
# instantiate
var weapon0 = self.ship_vars.weapon_0.instantiate()
weapon0.name = "weapon0"
###instance.transform.looking_at(target) # or look_at ?
$weaponslot1.add_child(weapon0)
## Assign projectile/ammo to weapon
## Load the weapon scene
## instanciate the weapon in a weapon slot
func set_projectile_for_weapon(weaponname: String, projectile: PackedScene) -> void:
get_node(weaponname).set_projectile(projectile)
## Caluclate vector to be applied with move_and_slide
## Using normalized target_position or inputs and speed
func calc_velocity(input_dir) -> Vector3:
# transform.basis: local coordinate system traveling with the object
# Multiplying with transform.basis, means that the local system is used
# therefor pressing forward moves in the look direction instead of global z
var direction = (self.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
# apply velocity based in input dir
# for other direction apply slow
if direction.x:
velocity.x += direction.x * ship_vars.move_speed * ship_vars.acceleration
velocity.x = clamp(velocity.x, -ship_vars.move_speed, ship_vars.move_speed)
else:
velocity.x = move_toward(velocity.x, 0, ship_vars.break_speed)
if direction.z:
velocity.z += direction.z * ship_vars.move_speed * ship_vars.acceleration
velocity.z = clamp(velocity.z, -ship_vars.move_speed, ship_vars.move_speed)
else:
velocity.z = move_toward(velocity.z, 0, ship_vars.break_speed)
return velocity
## rotate ship to face the target
func rotate_to(target: Vector3) -> void:
return
## shoot the loaded weapon with given projectile
func shoot_weapon(target: Vector3) -> void:
# shoot without target (add dummy target)
self.ship_vars.weapon_0.shoot(target)
## apply taken damage
func take_damage(damage: float) -> void:
ship_vars.health -= damage
## delete character upon death and do effects
func die() -> void:
return
## handle things like collision with other ships
## calculate dmg based on armor and mass from both ships
## emitted from this ships CollisionShape if its a ship
func on_collision_enter():
return
## handle hits from projectiles
## signal emitted from this ships CollisonShape if its a projectile
func on_projectile_recieved():
return
The BaseWeapon class:
extends StaticBody3D
#Stats
var weapon_vars : WeaponVariables
## init function that can be called by inheriting scenes to set vars
func _init(): #weapon_vars_class
self.weapon_vars = WeaponVariables.new(1, 50, 1, 0, 0, false)
func set_projectile(_projectile):
self.weapon_vars.load_projectile_scenes(_projectile)
## shoot the assigned projectile with the set variables
func shoot(target: Vector3):
if not self.weapon_vars.auto_aim:
# forward is (0,0,-1)
target = ($BulletSpawn.transform.basis * Vector3(0,0,-1)).normalized()
var bullet = self.weapon_vars.projectile # preload("res://MyScene.tscn")
var instance = bullet.instantiate()
instance.transform.looking_at(target) # or look_at ?
get_tree().get_root().add_child(instance)
"""
self.atk_speed = _atk_speed
self.range = _range
self.projectile_count = _projectile_count
self.projectile_spread = _projectile_spread
self.projectile_delay = _projectile_delay
self.auto_aim = _auto_aim
"""
The ShipVariables class:
class_name ShipVariables #, "res://assets/image.png"
#class ShipVariables:
var move_speed : float
var turn_speed : float
var health : float
var armor : float
var mass : float
var break_speed : float
## in percentage of speed
var acceleration : float
# scenes to load #@export
var weapon_0 : PackedScene
## Init a new ship variabel class containing:
## move_speed
## turn_speed
## health
## armor
## mass
## acceleration
func _init(_move_speed: float, _turn_speed: float,_health: float, _armor: float, _mass: float,
_acceleration: float):
self.move_speed = _move_speed
self.turn_speed = _turn_speed
self.health = _health
self.armor = _armor
self.mass = _mass
self.break_speed = _move_speed * 0.05
self.acceleration = _acceleration
func load_weapon0_scenes(weapon: PackedScene):
self.weapon_0 = weapon
The WeaponVariables class:
class_name WeaponVariables #, "res://assets/image.png"
#class ShipVariables:
var atk_speed : float
var range : float # m
var projectile_count: int
var projectile_spread : float # random spray in percentage 0% = laser
var projectile_delay : float # How fast consecutive projectiles shoot in s
var auto_aim : bool # aim the weapon
#var homing_projectile # doesnt make sense here add to projectile
# scenes to load #@export
var projectile : PackedScene
## Init a new weapon variabel class containing:
func _init(_atk_speed: float, _range: float, _projectile_count: int, _projectile_spread: float,
_projectile_delay: float, _auto_aim: bool):
self.atk_speed = _atk_speed
self.range = _range
self.projectile_count = _projectile_count
self.projectile_spread = _projectile_spread
self.projectile_delay = _projectile_delay
self.auto_aim = _auto_aim
func load_projectile_scenes(_projectile: PackedScene):
self.projectile = _projectile
(there are similar questions:
here and here here
but none gives a solution)