2

Godot 4.0

I am creating a 2D game that includes different light sources: candle, candelabra, lantern, torch, etc. Each light source is a StaticBody2D with a CollisionShape2D, a Sprite2D and a PointLight2D. They differ in their sprite texturess and in the color, intensity and range of their light.

I intend to have a variety of these objects in my game, and life would be easier for me if I could create a base light and have each type of light (Candle, Torch, Lantern) as its own independent Scene built off of this base.

If I were doing this in OOP, I'd create a base Light class and derive Candle, Lantern and Torch from it, but I'm not sure how I'd do this in Godot since each Scene is a Node tree with child Nodes instead of a class with attributes and I want to derive from the whole tree, not just one node.

I've read through the docs, but either I'm missing something or I'm just not thinking about it right because I haven't been able to puzzle out a way to do this.

I'd rather not just copy my base scene into each light scene.

Any thoughts?

  • Do you really need inheritance, which tends to add complexity? What are the common things you want to factor out into a "base class"? GdScript already supports [duck typing](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_advanced.html#duck-typing), which means you don't need to know a base type to treat all lights uniformly, as long as they have child nodes, properties and methods of the same name. If you want a base class for grouping, then you might better look into the [groups](https://docs.godotengine.org/en/stable/tutorials/scripting/groups.html) feature. – zett42 Apr 06 '23 at 11:03

2 Answers2

2

Godot supports good old OOP classes and inheritance. However, an scene is not a class. Thankfully, Godot also supports both scene inheritance and scene composition.

You are probably familiar with scene composition already: in an scene you can add an instance of another scene. If you enable "editable children" in the context menu of Scene, you can access and modify the children of the instantiated scene.

For scene inheritance, select the saved scene in FileSystem and from the context menu select "New Inherited Scene". Which will create a new scene that derives from the pre-existing one, and you add modifications on top.

Theraot
  • 31,890
  • 5
  • 57
  • 86
  • An inherited scene may be what I need, ALTHOUGH since my lights differ only in the properties of the nodes (light stuff and sprite texture), I wonder now if there's a better way? – Michael Teasdale Apr 06 '23 at 14:32
  • @MichaelTeasdale Instantiate the "light" scene, then right-click, enable "editable children" to be able to change the light properties. Alternatively, in a more object-oriented way, associate a script with the "light" scene, define properties using `@export` and define setters that modify the child nodes. You may have multiple sprites for all different kind of lights and make only one them visible at a time, through the setter of a property. It's more effort upfront, but simplifies using the lights in your game scene. – zett42 Apr 06 '23 at 15:50
  • @zett42 If we are going for more effort upfront, create a custom resource type with all the values you want to change, so you only need to export one property, and make resource files for each case. That would be good if there were tons of kinds lights (for example you would do this for items in an RPG), but is a hard sale for only a handful. – Theraot Apr 06 '23 at 15:54
1

@zett42's mention of @export got me thinking. Since I only have 3 variations of the light, and they differ only in the values of a few attributes, I decided to export an enum and set the value of my attributes based on that enum. This way, I need only 1 light object and maintain the simplicity of setting only one value for each instance.

enum Light_Type {CANDLE, CANDELABRA, LANTERN}
@export var type: Light_Type

@onready var sprite = $Sprite2D
@onready var light_source = $PointLight2D

const light_settings = [{"texture": "res://objects/lights/candle.png",
                        "color": Color8(255, 254, 176, 255), "size": 1},
                        {"texture": "res://objects/lights/candelabra.png", 
                        "color": Color8(255, 100, 100, 255), "size": 1.5},
                        {"texture": "res://objects/lights/lantern.png", 
                        "color": Color8(100, 255, 100, 255), "size": 2}]


func _ready():
    sprite.texture = load(light_settings[type]["texture"])
    light_source.texture_scale = light_settings[type]["size"]
    light_source.color = light_settings[type]["color"]