After some work, I have come to a simple answer:
set and _getpropertylist are used in saving a file. You cannot keep _set and _getproperty_list from being called after a file is saved.
This was my first attempt and object composition: The art of splitting scripts according to the work they do for better maintenance. But there are several SUPPORTED, NON-BUGGY ways of doing this same thing. Here is a list for those who come after me who want to do some beautiful object composition:
Yeah, so, Godot has nodes containing nodes. Nothing beats that. A "parent" can consider all children as accessible variables. It's guaranteed that those nodes will exist and can be reached from a consistent path. If you need to split functionality (such as when a Mario hero needs to split movement logic from damage and HP logic), this is what I consider the best way:
RootNode (Script: enemyController)
-> Health (Script: playerHealth)
The rootnode can call damage()
on the $Health
when needed.
This also fixes the "Export properties" problem above, as each node can specify its own export properties which can be accessed in the editor.
Subclassing! Useful when you want to extend existing behavior with slight alterations. For instance, my problem was with a movement method that needed the slight addition of a frame() function. This is different depending on the enemy type. Goombas, Koopas, and Bowser all move different ways, even though basic things like dying, freezing and respawning are the same for all of them. Since an enemy freezing and an enemy moving belong to the same type of script, and depend on the same variables, it makes no sense to split them into two nodes. Instead, I solved the problem using a template method that gets overriden!
Superclass:
extends KinematicBody2D
func _physics_process(delta):
self.frame(sprite, delta)
func frame(sprite : Sprite, delta):
pass
Subclass:
extends "res://enemy/Scripts/EnemyController.gd"
func frame(sprite : Sprite, delta):
# Moving functionality
This is what I was doing above, and it IS useful in some cases.
This option is useful if the script being accessed changes during RUNTIME. The movement logic for enemies and the health logic for a player do not change after the game starts. This is why giving them nodes to attach to is safe and useful. It also allows for editting export variables! BUT if a script is swapped out with others on the fly, you're not going to be specifying export variables for them, are you?
Example: A Mario hero needs to have a script for shooting fireflowers. It has a presspowerbutton function. BUT that script needs to get swapped out with a tanooki power script. In this case, having your script contain an "export(Resource) var power" variable and assigning instantiated classes on the fly is the best solution.
onready var body : KinematicBody2D = get_node("..")
export(Resource) var defaultPower = preload("res://items/fireFlowerPower.gd")
onready var power = defaultPower.new(body)
func change_to_tanooki():
var script = preload("res://items/tanookiPower.gd")
power = script.new(body)
This does not have problems when saving the scripts because the scripts are not depended on or used until runtime. That is when defaultPower is instantiated. In cases like this, the scripts MAY use variables, but they all use the same set, like how the Power scripts would probably use the player's rigidbody.