godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Scene polymorphism #3742

Open CombustibleLemonade opened 2 years ago

CombustibleLemonade commented 2 years ago

Describe the project you are working on

An online multiplayer FPS.

Describe the problem or limitation you are having in your project

I want to change inherited nodes in extended scenes, but I get an error message saying "can't operate on nodes the current scene inherits from". I think it would make sense if I could replace an instance of scene A with an instance of scene B iff B extends A.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

We consider scenes A, B, C and D. An instance of C is a child node in scene A. Scene B extends scene A, scene D extends scene C.

In this scenario, it should be possible to replace the instance of C in B with an instance of D. D extends C, and as such, an instance of D it should be able to 'behave' as if it were an instance of C.

Allowing specifically this will make sure that base scenes can contain all components that are shared across all inherited scenes, but also that adding new functionality to extended scenes is not restricted. For a detailed example, see below.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Imagine we have a base map scene, called "Map.tscn". We want to include components that exist in every map, such as the spawn point. We might want to include different kinds of spawn points, like a randomized spawn point, or a spawn point where the player can choose where they spawn, or just a spawn point at a specific location. The types of spawn points required may vary, and they require code specific to those spawn points. However, they all have some things in common, such as a spawn method which spawns the player. Thus, we create a base class "SpawnPoint.tscn" which contains only the spawn method. Then we extend this class with something like "LocationSpawnPoint.tscn".

We extend "Map.tscn" with a specific map, for instance "Desert.tscn". Now, we want to replace the SpawnPoint node with a LocationSpawnPoint. Right now, this is not possible.

We could instead not include the spawnpoint scene in the base map scene, but that would make the extension procedure less clear and more error prone. The change in functionality between different types of spawn points could also be made configurable through parameters, but that would make the types of behaviors exhibited by the spawn points inflexible. For me, allowing scene polymorphism would be the most logical and clean solution to this situation (and many others), and I think it would make life for non-programmers/level designers easier, since they have more flexibility to change the behavior of scenes, while at the same time they have less flexibility to mess things up.

The scene configuration would be as follows:

Map.tscn: Map | - SpawnPoint (instance of SpawnPoint.tscn)

Desert.tscn (extends Map.tscn): Map | - LocationSpawnPoint (instance of LocationSpawnPoint.tscn)

LocationSpawnPoint.tscn extends SpawnPoint.tscn

If this enhancement will not be used often, can it be worked around with a few lines of script?

This can be worked around with an editor plugin, but it is not particularly convenient.

Is there a reason why this should be core and not an add-on in the asset library?

Polymorphism is a core concept of OOP, and since scenes are in some sense an analog of classes, I think it would make sense to add polymorphism in this context as a core feature.

Zireael07 commented 2 years ago

That's what I use Editable Children for, just as a workaround.

unfa commented 2 years ago

That's what I use Editable Children for, just as a workaround.

I don't think Editable children let you replace a member node for a different one extending the same class. Does it?

Zireael07 commented 2 years ago

No, but you can use a common superclass and edit some exported values to achieve behavior that's mostly the same but not quite. I've used that trick to create different cards in a card-based game, and different space ships in my space game.

unfa commented 2 years ago

Yes, that's true - it requires you to pack all the possible logic into a single class and drive it with variables. However - this may also mean you'll pretty much have to put all the possible component variants in a single scene. It may not be the cleanest way of doing things for certain uses.