How to create a `.tscn` file?

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?

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.

2 Likes

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?