Godot Version
v4.2.1
Question
I wanna make a script that makes a .tscn
file with a variable that contains the basic code. How do you do that?
Can FileAccess
also make a new .tscn
file?
v4.2.1
I wanna make a script that makes a .tscn
file with a variable that contains the basic code. How do you do that?
Can FileAccess
also make a new .tscn
file?
Could you explain a bit more about what you are trying to do?
I believe u can use ResourceSaver — Godot Engine (stable) documentation in English to save tscn files and create new ones but i am not sure if u can store variables with it.
I have a short script that I made for custom importing.
The very last thing it does is save it as a *.tscn
Take a look here:
Is this a sufficient example for your needs? If not, please elaborate on what else you are needing.
Well, there was already FileAccess
, which is described as follows:
This class can be used to permanently store data in the user device’s file system and to read from it. This is useful for store game save data or player configuration files.
Here’s a sample on how to write and read from a file:
func save(content):
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_string(content)
func load():
var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
var content = file.get_as_text()
return content
The file.get_as_text()
, I assume, only generates text files. Is there any other way to make a .tscn
file? That is the question.
get_as_text()
doesn’t generate a text file, it reads from the file as if it were text. Good news is tscn
files are text, you can open them in a normal text editor or use get_as_text
to read them. If you want to create your own you could write line by line a valid .tscn
file using file.store_line
and/or file.store_string
But I don’t think you actually want to re-implement the .tscn
file format. You can create a PackedScene
, store nodes and alter those nodes’ variables then use it’s pack
function and ResourceSaver’s save
to create a .tscn
file. Some games use this technique to save entire complex scenes as if it were a save fille.
It’s hard to tell what your end goal is, could you explain under what circumstances you want to create a tscn file?
I wanted to make a script that generates maps/scenes consisting of objects randomly placed around, with unique identifiers such as “frequency” determining the amount of objects and “color” determining the color of those objects. Those objects are in their own .tscn files, so I have to import them by script.
Using .tscn
files from scripts gives you a couple options, there’s @export
and preload
then you can instantiate()
the packed scene
@export var a_tscn: PackedScene # drag and drop in inspector
var b_tscn: PackedScene = preload("res://your_file_path.tscn")
func _ready() -> void:
var random_number := randf()
if random_number > 0.9:
var new_a = a_tscn.instantiate()
add_child(new_a)
elif random_number < 0.2:
var new_b = b_tscn.instantiate()
add_child(new_b)
Does that preload thing let you write scripts into .tscn
files?
The a_tscn
looks like you have to drag and drop a file in a windows ui, while the b_tscn
needs a preloaded instance.
The tscn files can contain multiple scripts, just like how you make any other script in the editor. or you can apply a script after instantiation.
@export var a_tscn: PackedScene # drag and drop in inspector
var b_tscn: PackedScene = preload("res://your_file_path.tscn")
var a_script: Script = preload("res://your_script_path.gd")
func _ready() -> void:
var random_number := randf()
if random_number > 0.9:
var new_a = a_tscn.instantiate()
new_a.set_script(a_script) # adding a script after instancing
add_child(new_a)
elif random_number < 0.2:
var new_b = b_tscn.instantiate()
add_child(new_b)
Correct, I wouldn’t say a “preloaded instance” since it’s not and instance, but a scene file, instancing comes later, like in the example’s _ready function
Is it possible to create .gd
files with a string?
If so, is it possible for multiline strings, so you can make multiline .gd
scripts?
Yes you can make scripts entirely within scripts. Very rare use case though, I wouldn’t be surprised if there was a easier way to do what you wanted.
var gdscript = GDScript.new()
gdscript.source_code = """extends Node2D
func _init() -> void:
print("init from string")
set_process(true)
func _process(delta) -> void:
position.x += 200 * delta
"""
gdscript.reload()
$TestNode2D.set_script(gdscript)
What does the gdscript.reload()
do?
re-compiles/parses the script, since we’ve made changes to it’s source_code
So, this “recompiles” the script, so it can be used in a .tscn
file?
Not specifically, just recompiles because the source_code
property changed. Otherwise it will try to run the old source_code
which you might have guessed is empty.
I see…
.gd
files are separate from .tscn
files, so you’ll have to set_script(gdscript)
the .gd
files to the .tscn
files to make them work.
However, how does one save a .gd
file to a particular directory?
What I described actually wasn’t using a .gd
file at all, I thought you wanted to avoid using the files?
The .tscn
files are scenes, they can have scripts in built-in or referencing .gd
files. You can save a .gd
file by attaching a script to a node and selecting where you want to save it.
If you are trying to save a generated .gd
script from a String like we’ve talked about, then you will have to use FileAccess and write the source content using FileAccess’ store_string
The .gd
file should automatically be in the same directory as the .tscn
file for which that .gd
file is attached to. So, if it is in a folder $Folder1/Folder2/TestNode2D.set_script(gdscript)
, it should be attached within a folder named Folder2
. Is that a right?
By default, but you can change the path. The tscn
file can reference any and many scripts
So, like just by TestNode2D.set_script(gdscript)
, the .gd
file would be saved alongside the TestNode2d
in a single directory?