diff --git a/classes/particles/fallback_particles.gd b/classes/particles/fallback_particles.gd new file mode 100644 index 000000000..92b1ef1b2 --- /dev/null +++ b/classes/particles/fallback_particles.gd @@ -0,0 +1,82 @@ +class_name FallbackParticles +extends GPUParticles2D +## Compatibility class that swaps GPU particles out for CPU particles on devices that don't support it. +## Might be worth making an engine proposal for this kind of thing, since this is somewhat hacky. + +## Flags that ensure that the property is editor-accessible and also stored in the scene file. +## If it's not both of those, then there's no point copying it over. +const USAGE_FLAGS = 6 + +## The replacement CPUParticles2D node. +var _replacement: CPUParticles2D = null + +## If true, _set() and _get() will not redirect to the replacement. +var _dont_redirect: bool = false + + +func _ready(): + # Check if the device is missing a video adapter (GPU) + if OS.get_video_adapter_driver_info().is_empty(): + # Temporarily disable redirection so we can work. + _dont_redirect = true + + # Create a CPU node and copy properties over. + _replacement = CPUParticles2D.new() + _copy_properties() + + # Replace this node. + replace_by.call_deferred(_replacement) + + # Rename the replacement to hide the change. + _replacement.name = name + + # Re-enable redirection. + _dont_redirect = false + + +## Copy properties from the current node to the replacement. +func _copy_properties() -> void: + _replacement.convert_from_particles(self) + + for property in get_property_list(): + var prop_name = property.name + if property.usage != USAGE_FLAGS: + continue + if prop_name in _replacement: + _replacement.set(prop_name, get(prop_name)) + + +## Redirect property setting to the replacement node. +func _set(property, value): + if property == &"_dont_redirect": + return false + + if _replacement == null: + return false + + _replacement.set(property, value) + return true + + +## Redirect property getting to the replacement node. +func _get(property): + if property == &"_dont_redirect": + return null + + if _dont_redirect: + return null + + if _replacement == null: + return null + + if !property in _replacement: + return null + + for prop in get_property_list(): + if prop.name != property: + continue + + if prop.usage != USAGE_FLAGS: + return null + + return _replacement.get(property) diff --git a/classes/particles/generic_particles.gd b/classes/particles/generic_particles.gd new file mode 100644 index 000000000..c97922494 --- /dev/null +++ b/classes/particles/generic_particles.gd @@ -0,0 +1,10 @@ +class_name GenericParticles2D +extends Node2D +## Generic class for GPUParticles2D and CPUParticles2D + +var g_emitting: bool = false: + set(value): + set(&"emitting", value) + g_emitting = value + get: + return get(&"emitting") diff --git a/classes/pickup/coin/coin_particles.gd b/classes/pickup/coin/coin_particles.gd index d8cd52325..2662876fc 100644 --- a/classes/pickup/coin/coin_particles.gd +++ b/classes/pickup/coin/coin_particles.gd @@ -1,10 +1,10 @@ -extends GPUParticles2D +extends GenericParticles2D func _ready(): - emitting = true + g_emitting = true func _process(_delta): - if !emitting: + if !g_emitting: queue_free() diff --git a/classes/pickup/coin/coin_pickup.gd b/classes/pickup/coin/coin_pickup.gd index 037c7166f..3c19f2872 100644 --- a/classes/pickup/coin/coin_pickup.gd +++ b/classes/pickup/coin/coin_pickup.gd @@ -29,7 +29,7 @@ func _add_coins(num: int, player: PlayerCharacter) -> void: func _pickup_effect() -> void: Singleton.get_node("SFX/Coin").play() - var inst: GPUParticles2D = PARTICLE_SCENE.instantiate() + var inst = PARTICLE_SCENE.instantiate() inst.texture = particle_texture if parent_is_root: inst.position = get_parent().position diff --git a/gui/water_meter/water_meter.gd b/gui/water_meter/water_meter.gd index c4fb18fb5..8447977fa 100644 --- a/gui/water_meter/water_meter.gd +++ b/gui/water_meter/water_meter.gd @@ -14,9 +14,9 @@ var icon_bob = 0 @onready var filler: Sprite2D = $Filler @onready var surface: Sprite2D = $Surface @onready var bubble_mask: NinePatchRect = $BubbleMask -@onready var bubbles_big: GPUParticles2D = $BubbleMask/BubblesBig -@onready var bubbles_medium: GPUParticles2D = $BubbleMask/BubblesMedium -@onready var bubbles_small: GPUParticles2D = $BubbleMask/BubblesSmall +@onready var bubbles_big = $BubbleMask/BubblesBig +@onready var bubbles_medium = $BubbleMask/BubblesMedium +@onready var bubbles_small = $BubbleMask/BubblesSmall @onready var label: Label = $WaterMeterLabel @onready var max_sprite: Sprite2D = $Max @onready var power_filler: Sprite2D = $PowerFiller