Make Godot "Script Variables" control appearance in 2D editor?

Viewed 297

I have a "Player" scene, which holds everything about a player, the sprite, the animations, the shadow, and a collection of other things.

A script variable 1,2,3,4, etc.. controls which image/texture/sprite data is loaded, to control the appearance.

But when I drop them on the 2D editor, they all have the default image, so they all look identical. Which is confusing. Whats the best way to make each player appear different in the editor?

This code in the player script is good at allowing setting a player number, and loading a different image set, but it doesn't show in the 2D editor. Changing the character number makes the image change at runtime:

export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")

func _ready():
    if characterNumber == 1:
        get_node("Sprite").set_texture(player1) 
    if characterNumber == 2:
        get_node("Sprite").set_texture(player2) 

Alternatively, I could have multiple sprites in a generic player scene, and turn them on and off depending on the characterNumber, but again, the same problem occurs, the change isn't visible until runtime.

One idea is multiple children scenes, but I cant work out how to turn sprites on or off depending on a variable or some other type of setting.

What am I doing wrong?

2 Answers

In your script your want to make it a 'tool' so it can execute inside your editor, and not only when you launch the game.

see https://docs.godotengine.org/en/stable/tutorials/plugins/running_code_in_the_editor.html

In your case, you might use something like the following: (make sure to do "Scene -> Reload saved scene" to reload the constructor if your change the node's property)... a more ergonomic (but takes more processing) solution is to put it in the _process func

tool
export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")

func _ready():
    if Engine.editor_hint:
        if characterNumber == 1:
            print("executing custom in editor logic")

    if characterNumber == 1:
        get_node("Sprite").set_texture(player1) 
    if characterNumber == 2:
        get_node("Sprite").set_texture(player2) 

func _process(_delta):

    if Engine.editor_hint:
        # only rotate the object if we set the character number to 1
        if characterNumber == 1:
            rotate(Vector3(0,1,0), deg2rad(15*_delta))
        set_my_texture() #quick n dirty way for fast reload

func set_my_texture():
    if characterNumber == 1:
        get_node("Sprite").set_texture(player1) 
    if characterNumber == 2:
        get_node("Sprite").set_texture(player2)

Ryu's approach of using a tool script would work. You can use Engine.editor_hint to identify when your script is running in the editor.

By the way, combine it with setget, so you can define a setter function that will run when you modify the variable. You should not need _process, which would be running every frame.


Anyway, let me cover a few alternatives:

  • You can make inherited scenes (from the context menu of an existing scene in the FileSystem panel choose "New Inherited Scene"), and there modify it however you want. You can change properties such as the texture of sprites, or you can add other scene instances as children. This solves the problem of placing an instance of a particular variation of your scene, and being able to tell it apart in the editor, without the need to run your script on the editor.

  • If you have all the textures you want in single atlas/sprite sheet, you can use an AnimatedSprite, except you are not going to use it to animate. Instead put all the textures in a single animation, and then change the frame to pick the texture you want. This gets close to what you want in that you just change a number (the frame).

  • For completeness I'll also mention that you can use an AtlasTexture to load a texture form an sprite sheet. On the texture of your Sprite (for example), select "New AtlasTexture", then atlas of the AtlasTexture load your sprite sheet, and set region to take the area of the texture atlas you want. I suggest setting the size (width and height of the region) first. This approach will also work for anywhere you might need a texture, although tweaking the region is more work that simply setting a number. By the way, AnimatedTexture can serve a similar role, but it does not give you a way to specify the frame you want.

And yes, you could control any of these form a tool script.


Addendum: by the way, you know you can enable "Editable Children" on the scene instances on the Scene panel, right? It is in the context menu. That lets you edit the instances directly. I wanted to mention it, just in case that helps you.

Related