Node changing parent inexplicably

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Revolvolutionary

Hello all. I’m new to godot so sorry if this has a really basic solution I’m missing.

I expect my project to be fairly code-heavy, so I want to have a specific node that handles user input. Currently, I have a class that changes the resolution of the screen, which works fine. (it also adjusts the background to match and so on. it is called resolutionController.) I have created a node called keyboardController, and a script to match, to handle all my input.

I’m struggling to get to the root of the problem. The symptom is this: keyboard controller cannot access the resolutionController node. I have tried using get_node(), I have tried using find_node(), I have tried making the resolutionController node a child of the keyboardController node. I have tried moving get_node() to after the button press, I have tried having it inside _ready() and storing the resolutionController node in a variable.

I have noticed a couple things while bashing my head against this bug. keyboardController._ready() is being run twice, which I have further determined is because it is being moved from being a child of the scene node to being a child of the viewport. I have also determined that get_node() is actually finding the right node, which I figured out by printing the node. Both resolutionController and the node that keyBoardController.get_node() found have the same ID [ Node : 1190 ] (or a different number depending on startup.) But when I go to access the variables inside resolutionController from keyboardController, it fails.

Here are both files in full. the exact error I get when I run them is attempt to call function 'get_max_resolution' in base 'null instance on null instance on line 21 of keyboardController.

keyboardController:

extends Node

# Called when the node enters the scene tree for the first time.
func _ready():
	print_debug("keyboardController parent is: ", get_parent());

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass

func _input(event):
	if event.is_action_pressed("ui_home"):
		toggleResolution();
	if event.is_action_pressed("ui_cancel"):
		get_tree().quit();

func toggleResolution():
	var resolutionController = get_node("resolutionController");
	print_debug("keyboardController found: ", resolutionController);
	if OS.get_window_size().x < 1080:
		resolutionController.setResolution(resolutionController.get_max_resolution());
	else:
		resolutionController.setResolution(resolutionController.get_min_resolution());

(this shouldn’t be relevant but I will include it here for completeness)
resolutionController:

extends Node

# Declare member variables here. Examples:
# var a = 2
# var b = "text"
var bkg_node;
var bkg_x;
var bkg_y;

var minResolution = Vector2(960, 540);
var maxResolution = Vector2(1920, 1080);
func get_min_resolution(): return minResolution;
func get_max_resolution(): return maxResolution;

# Called when the node enters the scene tree for the first time.
func _ready():
	
	#init the files we need to work
	bkg_node = get_node("../../background");
	bkg_x = bkg_node.texture.get_width();
	bkg_y = bkg_node.texture.get_height();
	
	#set a default resolution. 1600x900 is one of my faves
	setResolution(Vector2(1600, 900));
	
	print_debug("resolutionController is: ", self);
	print_debug("resolutionController parent is: ", get_parent());
	print_debug("resolutionController grandparent is: ", get_parent().get_parent());

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass

func setResolution(newResolution):
	OS.set_window_size(Vector2(newResolution.x, newResolution.y));
	
	bkg_node.set_offset(Vector2((newResolution.x-bkg_x)/2, 
								(newResolution.y-bkg_y)/2));
	
	OS.center_window();
	
#TODO: set_borderless_window(value) for fullscreen

Thanks for your help everyone. I’m open to different solutions / a better way of doing things but I am somewhat attached to having a single class that handles all the input. I want to avoid spaghetti as much as I can.

:bust_in_silhouette: Reply From: Revolvolutionary

I have discovered that I had the keyboardController script attached to both my keyboardController node and my scene root node. SIlly me! Hopefully this can help somebody else.

Hello, this is mine script and the error is: Attempt to call function ‘store_line’ in base ‘null instance’ on a null instance.
The script:
extends Node

const SAVE_PATH = “users://savegame.bin”

func saveGame():
var file = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
var data: Dictionary = {
“playerHP”: Game.playerHP,
“Gold”: Game.Gold,
}
var jstr = JSON.stringify(data)
file.store_line(jstr)

func loadGame():
var file = FileAccess.open(SAVE_PATH, FileAccess.READ)
I’m new at Godot and I have no idea how to solve it.