Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add switch_scene resource #298

Merged
merged 1 commit into from
Nov 6, 2024
Merged

Add switch_scene resource #298

merged 1 commit into from
Nov 6, 2024

Conversation

vanessa-chang
Copy link
Contributor

@vanessa-chang vanessa-chang commented Nov 1, 2024

Add a new block that allows the user to switch to another scene via a specified scene file path.

https://phabricator.endlessm.com/T35706

type = 2
variant_type = 4
display_template = "switch the scene to {file_path: STRING}"
code_template = "get_tree().change_scene_to_file({file_path})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People more expert in Godot than me: is there some way we can refer to the other scene other than by file path?

Copy link
Member

@wjt wjt Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm imagining here is: can we make it possible to drag a tscn file onto the canvas and then have a block representing a different scene? Or a dropdown list of all tscn files in the project, except the current one and scenes that are part of the plugin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another way to do is to export a PackedScene variable packed scene. It will allows the user to assign the scene in the inspector. Should we update and use this approach instead? (Although I'm not the expert)
During my research, I found three ways to switch scenes: T35706. Hopefully, we can get more input from the experts!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is right to do this in the block coding canvas (as you have done) not to go to the inspector. I was hoping we could do something similar to how we can drop nodes into the canvas to get a block that represents that node.

I did some brief experiments with this... If you have a node that exports a variable of type PackedScene, then assign a scene to it, it gets represented as (wrapped for legibility):

[ext_resource type="PackedScene"
              uid="uid://c2pcat3ejl74o"
              path="res://Scene2.tscn"
              id="2_g4qc4"]

I feel like it ought to be possible to define a value block that gets serialised in a way that refers to an external scene in this way. Then this switch_scene block would accept a parameter of type PackedScene. And for bonus points we would give it a dropdown of all scenes in the project, like we do for parameters of type node or group.

Unfortunately block parameter types are expressed as Variant.Type enum members and a PackedScene is just an OBJECT. There's no analogue to NODE_PATH.

As well as the drag-and-drop idea, another reason it may be nice to store the reference to another scene in a way that Godot itself understands to be a reference to a file rather than just a string is that Godot knows how to update all such references if you rename the scene.

Anyway... What I'm suggesting is of course all way more work than adding a switch_scene block whose parameter is a string. And having the block at all would make a whole world of things possible which currently aren't. So all my suggestions here should probably be considered further work for another time…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm imagining here is: can we make it possible to drag a tscn file onto the canvas and then have a block representing a different scene? Or a dropdown list of all tscn files in the project, except the current one and scenes that are part of the plugin?

Yeah, in the same way as the more sophisticated alternative to drag&drop sounds that I described in #166 (comment)

Unfortunately block parameter types are expressed as Variant.Type enum members and a PackedScene is just an OBJECT. There's no analogue to NODE_PATH.

I think that we should add a class_name field to the block definition, that will pair with the variant_type field for the case where the variant is of type OBJECT. This is the same Godot has for typed arrays:

Then when dragging from the Filesystem to the block canvas:

  • If the resource is a sound, add a value block of variant type OBJECT and class name AudioStream.
  • If the resource is a tscn or scn, add a value block of variant type OBJECT and class name PackedScene.

In the same way, the holes or slots can be enhaced to allow a specific class name when the variant type is OBJECT. Then we could do:

  • "play sound" block: Has a slot that supports a value block of variant type OBJECT and class name AudioStream.
  • "switch scene" block: Has a slot that supports a value block of variant type OBJECT and class name PackedScene.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, a PackedScene is a Resource. SceneTree (what you get from get_tree()) provides 2 methods for changing scenes - from a file path, and from a PackedScene.

In code you might do it like this:

func change_scene(scene: Variant):
    if scene is String:
        get_tree().change_scene_to_file(scene)
    elif scene is PackedScene:
        get_tree().change_scene_to_packed(scene)
    else:
        push_error("Can only change scene from String or PackedScene")

With blocks we kinda need to be specific about what kind of Variant the parameter is, so we'd need to do one or the other. @manuq has some suggestions on handling that if we want to use PackedScenes.

I like the idea of loading a PackedScene with change_scene_to_packed, but then you'd have to tackle the whole part of creating a scene with a block using load. It would be very similar to the get_node block, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think #305 helps get_tree().change_scene_to_file(scene) :)

addons/block_code/blocks/communication/switch_scene.tres Outdated Show resolved Hide resolved
@dbnicholson
Copy link
Member

Having said everything about using a PackedScene, I think it's best to address @wjt's comments and get this in using change_scene_to_file using a String. If we have time later, we can add support for loading a scene as a block and using that as the argument to the switch_scene block. I'm confident we can add a migration should do the work to handle PackedScenes.

This is a basic scene-switching block using a string.

If we have time later, we can make further improvements by adding a
block for loading a scene and using that as the argument to the
switch_scene block to implement PackedScene.

https://phabricator.endlessm.com/T35706
Copy link
Contributor

@manuq manuq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works!

@manuq manuq merged commit 909ac54 into main Nov 6, 2024
3 checks passed
@manuq manuq deleted the switching-scene-block branch November 6, 2024 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants