The topic name is a bit misleading but I wasn’t sure how to summarize it.
I’m currently making a tower defense game to learn the tool. I have referenced several tutorials but I’m not actually following any of them but am instead trying to translate the way they show things being done into the way I would organize things.Typically for a project like this I’d make an abstract class for things like mobs, towers, ect. and then make child classes to implement. However, I haven’t figured out how to do this with godot and going off the various tutorials I’ve seen it seems more common to load in prepackaged scenes. Attempting to architecture for this, I decided to make a single scene for what would be the abstract class and then have a second function called ‘build’ which fires after ‘_ready’ that would populate all of the specifics (I consider it likely that there’s a better way to do this but it should be fine for the purpose of learning).
However, I’m running into what looks like an inconsistency that I don’t understand. I have a ‘Main’ scene, I have a ‘Level’ scene whose ‘build’ function involves loading in a json file and populating a tile layer and a data structure that defines the mobs that will spawn, and I have a ‘Mob’ Scene which is a character body 2d and has a build function that populates the mob stats based on a type enum. Each scene has a script attached to the root object and no other scripts. The issue I’m having is that I can easily in the Main scene call build for the Level Scene and it has no issue loading the json and creating the map, creating path2d objects, ect, however for some reason when the Level build function attempts to call the Mob build function, the following error is thrown:
’Invalid call. Nonexistent function ‘build’ in base 'CharacterBody2D (mob.tscn::GDScript_iva0e)’
As far as I can tell, I’m doing the exact same thing in both cases with the only notable difference I can see being that the Mob has CharacterBody2D as the object the script is attached to while both the other scenes are Node2D however Node 2D doesn’t have a ‘build’ function either.
In both cases the use pattern looks something like this:
#At script hea@onready @onready var level/mob = preload()
# in a function
var my_level_or_mob = level/mob.instantiate()
get_node(<sub node of scene>).add_child(my_level_or_mob)
my_level_or_mob(<relevant parameters>)
I’m not understanding why in the Main scene I can instantiate a Level scene and access the build function in it’s script whereas when in the Level scene if I instantiate a Mob scene I cannot call the build function in it’s script and get told that the base object doesn’t have the function
I dont know if i read your post correctly, but if i did, then your problem might be that you didn’t define what the func build would do within the CharecterBody2D’s script?
It also might be a problem with the way your nodes are set up.
I do have build functions defined in both Level and Mob. Also, I can instantiate mobs I just can’t call the function I put into their script.
Could you elaborate on what you mean by ‘the way your nodes are set up’? The one difference I could identify is that the root of the Mob scene is a CharacterBody2D whereas the other scenes both have a Node2D as their root.
well, and im assuming the mob is an enemy here and not a player, but character bodies are only supposed to be used for physics controlled bodies. You would use other bodies depending on each thing you need (static body, rigid body, etc.) for anything that isn’t the player.
By my statement, I meant how your nodes are parented. I ran into a similar problem following this tutorial: “Beginner Godot Tutorial - How to Make Pong with AI by Coding With Russ” around 15:20 (and ran into a problem is used for the lack of a better term). Since I see you’re using tutorials to figure out mechanics ill cite this.
Basically, he says in the root node, you need to start the function to be able to run it, he uses a timer to tell the code when to run. That may be a problem you’re having?
Null usually means, though, that the node can not access (or can not run) a certain type of code, at least in my (admittedly limited) experience. I would use a static body, I would never recommend using node 2ds for anything but the root node of a main game scene, that’s bad practice (yet again, at least in my experience)
Mobs refer to the creatures that attack the tower in a tower defense. I’m not having any issues with Null pointers.
The relevant points on the tree are as follows:
Scene 1 (main scene)
Main (Node 2d) [attached script]
–Level(Node2d)
Scene 3: (mob scene)
Mob (CharacterBody2D) [attached script]
The script in the Main, has the Level scene preloaded and calls instantiate() on it, makes it a child to the Level Node, and then calls its build function. Level has the Mob scene preloaded in the exact same fashion and during it’s build function it calls the build function in the Mob Scene however unlike when the main scene calls it’s own build function, when it calls the build function in the Mob scenes script I get the Nonexistent function error. Note, I don’t have any issues generating the mob or attaching it to the FollowPath2D as a child, it’s only calling the build function that results in an issue.
You should post the code you are actually using and screenshots from your scene hierachies.
Right now I can only guess that there is no script attached to the mob scene.
After some testing, I think you must be right. Change I make to the mob script don’t seem to be getting registered at all when I run the program (for instance if I change the mobs speed and run the program with the mob build() line commented out it still moves at the old speed). However,
I am greatly confused as to how it’s possible though I do have a guess as to when it would have happened. Partway through writing the mob script (notably before I would have added the build() line), I decided to move everything related to Mobs to a subfolder. As part of that, I changed the @preload line to point to the new location and all other references. The program appears to be acting as if the Level scene is still somehow loading a cached version of the Mob scene from before I moved it and before I wrote the build function however I don’t see anything that would act as a cache anywhere and it sure looks to me when I look at my scene trees and script list like everything is hooked up.
A question on etiquette for this particular forum. When I tried posting screenshots, I was told that only one piece of embedded media was allowed per post. It it frowned on to mass post to include multiple screenshots or is there an expectation that I collage them together into a single image?
Update: Issue resolved, though my question about forum etiquette above still stands. Also, there was something very unclear about the IDE GUI that seems worth pointing out
I moused over the script icon attached to the mob scene and it showed the correct location in the directory structure so I assumed that it should be pointed to the correct script. However, just to try it I clicked on it and it opened up a new script that wasn’t on my list and was in fact some kind of cached version of the mob script from before I moved it. I deattached that script, and reattached the existing script and instantly the more up to date version of the code I’d written was active. However, not only was it not clear to me that the old version of the script was the one attached but also, I still have no idea where the cached version exists. I can’t find it anywhere in the project directory.
It was using an embedded script. Those are stored within the scene’s mob.tscn file.
Cached data are stored in the project’s hidden .godot folder, though they didn’t seem to be the issue here.
About forum etiquette: I’ve never seen anyone complaining about too many posts for multiple screenshots. Merging them into a single picture would make it harded to view them, so I wouldn’t recommend that.
So scripts are both embedded into the scene and saved as a separate file and in my case the script in the file and the script in the scene somehow became desynced when I moved them?
No, it’s either or. Either an external .gd file is used and the .tscn file has a link to that file, or the whole script is stored as an embedded script inside the .tscn file.
If I had to guess, moving the files caused the .tscn to lose the .gd script, and thus replaced it with an embedded script from cached data. But I’m not sure about this.