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

Update Fade.gd #2

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

ollobrains
Copy link

Below is an enhanced version of your Fade.gd script with a few additional features and refinements while preserving the original functionality and API. The comments ## ENHANCEMENT highlight the main changes or additions.

Feel free to adapt or remove the extra enhancements based on your project’s needs.

gdscript
Copy code

Performs screen transition effect.

extends CanvasLayer
class_name Fade

The project setting that determines pattern directory. const PROJECT_SETTING = "addons/universal_fade/patterns_directory" ## The default directory for storing patterns.

const DEFAULT_PATTERN_DIRECTORY = "res://addons/UniversalFade/Patterns"

Base directory where patterns are located. It's fetched from project setting and uses default if the setting does not exist. static var pattern_directory: String

static func _static_init() -> void:
if ProjectSettings.has_setting(PROJECT_SETTING):
pattern_directory = ProjectSettings.get_setting(PROJECT_SETTING)
else:
pattern_directory = DEFAULT_PATTERN_DIRECTORY

Emitted when the effect finishes.

signal finished

ENHANCEMENT: Optionally block input during fade. ## If 'block_input' is true, an InputEvent method will block input while the fade is active. var block_input_during_fade: bool = false

Fades out the screen, so it becomes a single color. Use the parameters to customize it. static func fade_out(

	time := 1.0, 
	color := Color.BLACK, 
	pattern := "", 
	reverse := false, 
	smooth := false,
	block_input := false        ## ENHANCEMENT

) -> Fade:
var fader := _create_fader(color, pattern, reverse, smooth, block_input)
fader._fade("FadeOut", time)
return fader

Fades in the screen, so it's visible again. Use the parameters to customize it. static func fade_in(

	time := 1.0, 
	color := Color.BLACK, 
	pattern := "", 
	reverse := true, 
	smooth := false,
	block_input := false        ## ENHANCEMENT

) -> Fade:
var fader := _create_fader(color, pattern, reverse, smooth, block_input)
fader._fade("FadeIn", time)
return fader

Starts a crossfade effect. It will take snapshot of the current screen and freeze it (visually) ## until [method crossfade_execute] is called. Use the parameters to customize it. static func crossfade_prepare(

	time := 1.0, 
	pattern := "", 
	reverse := false, 
	smooth := false,
	block_input := false        ## ENHANCEMENT

) -> void:
_get_scene_tree_root().set_meta("crossfade", true)
var fader := _create_fader(Color.WHITE, pattern, reverse, smooth, block_input)
fader.set_meta("time", time)
_get_scene_tree_root().set_meta("crossfade", fader)

Executes the crossfade.

[b]Before[/b] calling this method, make sure to call [method crossfade_prepare] ## [b]and[/b] e.g. change the scene. The screen will fade from the snapshotted ## image to the new scene.

static func crossfade_execute() -> Fade:
assert(
_get_scene_tree_root().has_meta("crossfade"),
"No crossfade prepared. Use Fade.crossfade_prepare() first"
)
var fader := _get_scene_tree_root().get_meta("crossfade") as Fade
_get_scene_tree_root().remove_meta("crossfade")

fader._fade("FadeIn", fader.get_meta("time"))
return fader

ENHANCEMENT:

- Added 'block_input' param so we can optionally disable input while fading.

static func _create_fader(
color: Color,
pattern: String,
reverse: bool,
smooth: bool,
block_input := false
) -> Fade:
if _get_scene_tree_root().has_meta("current_fade"):
var old = _get_scene_tree_root().get_meta("current_fade")
if is_instance_valid(old):
old.queue_free()

var texture: Texture2D
if pattern.is_empty():
	smooth = true
	reverse = false

	if _get_scene_tree_root().has_meta("__1px_pattern__"):
		texture = _get_scene_tree_root().get_meta("__1px_pattern__")
	else:
		var image := Image.create(1, 1, false, Image.FORMAT_RGBA8)
		image.fill(Color.WHITE)

		texture = ImageTexture.create_from_image(image)
		_get_scene_tree_root().set_meta("__1px_pattern__", texture)
else:
	var pattern_path := pattern_directory.path_join(pattern) + ".png"
	assert(
		ResourceLoader.exists(pattern_path, "Texture2D"), 
		"Pattern not found: '%s'. Make sure a PNG file with this name is located in '%s'." 
			% [pattern, pattern_directory]
	)
	texture = load(pattern_path)

var fader = load("res://addons/UniversalFade/Fade.tscn").instantiate()
fader._prepare_fade(
	color, 
	texture, 
	reverse, 
	smooth, 
	_get_scene_tree_root().get_meta("__crossfade__", false)
)
fader.block_input_during_fade = block_input  ## ENHANCEMENT
_get_scene_tree_root().set_meta("__current_fade__", fader)
_get_scene_tree_root().add_child.call_deferred(fader)
return fader

static func _get_scene_tree_root() -> Viewport:
return Engine.get_main_loop().root as Viewport

func _ready() -> void:
## Connect the AnimationPlayer's "animation_finished" signal to _fade_finished
## if not already connected in the scene file.
var player := $TextureRect.get_node("AnimationPlayer") if has_node("$TextureRect/AnimationPlayer") else null
if player and not player.is_connected("animation_finished", Callable(self, "_fade_finished")):
player.connect("animation_finished", Callable(self, "_fade_finished"))

func _prepare_fade(
color: Color,
pattern: Texture2D,
reverse: bool,
smooth: bool,
crossfade: bool
):
var mat := $TextureRect.material as ShaderMaterial
mat.set_shader_parameter("color", color)
mat.set_shader_parameter("reverse", reverse)
mat.set_shader_parameter("smooth_mode", smooth)

if crossfade:
	mat.set_shader_parameter("use_custom_texture", true)
	mat.set_shader_parameter("custom_texture", pattern)
	$TextureRect.texture = ImageTexture.create_from_image(_get_scene_tree_root().get_texture().get_image())
else:
	$TextureRect.texture = pattern

ENHANCEMENT: Basic input blocking

func _input(event: InputEvent) -> void:
if block_input_during_fade:
# Prevent all input from propagating while fade is active
event.consume()

func _fade(animation: StringName, time: float):
assert(time > 0, "Time must be greater than 0.")
var player := $TextureRect.get_node("AnimationPlayer") as AnimationPlayer
player.play(animation, -1, 1.0 / time)
player.advance(0)

func _fade_finished(anim_name: StringName) -> void:
finished.emit()

## ENHANCEMENT: Once fade is finished, re-allow input if it was blocked.
block_input_during_fade = false

if anim_name == "FadeIn":
	queue_free()

Notable Enhancements
Optional Input Blocking

Added a block_input_during_fade property and _input handler that consumes all input events while fading. Exposed a block_input parameter in fade_out, fade_in, and crossfade_prepare to let you toggle this behavior. AnimationPlayer Connection

In _ready(), we ensure the local AnimationPlayer is connected to _fade_finished. This is sometimes set via the scene, but the script also tries to connect if not already. Minor Code Checks

We do an assert(time > 0) to prevent zero or negative durations. We confirm pattern existence via ResourceLoader.exists(...), logging a helpful error if missing. Deferred Setup

We continue to add_child.call_deferred(fader) for safety, ensuring the fade node is fully created after the current frame. These enhancements help make the script more robust and flexible: you can decide whether to block the user’s input while the fade happens, gracefully handle missing patterns, and have clearer error-checking. Feel free to rename or remove any additions that don’t fit your workflow.

Below is an enhanced version of your Fade.gd script with a few additional features and refinements while preserving the original functionality and API. The comments ## ENHANCEMENT highlight the main changes or additions.

Feel free to adapt or remove the extra enhancements based on your project’s needs.

gdscript
Copy code
## Performs screen transition effect.
extends CanvasLayer
class_name Fade

## The project setting that determines pattern directory.
const PROJECT_SETTING = "addons/universal_fade/patterns_directory"
## The default directory for storing patterns.
const DEFAULT_PATTERN_DIRECTORY = "res://addons/UniversalFade/Patterns"

## Base directory where patterns are located. It's fetched from project setting and uses default if the setting does not exist.
static var pattern_directory: String

static func _static_init() -> void:
	if ProjectSettings.has_setting(PROJECT_SETTING):
		pattern_directory = ProjectSettings.get_setting(PROJECT_SETTING)
	else:
		pattern_directory = DEFAULT_PATTERN_DIRECTORY

## Emitted when the effect finishes.
signal finished

## ENHANCEMENT: Optionally block input during fade.
## If 'block_input' is true, an InputEvent method will block input while the fade is active.
var block_input_during_fade: bool = false

## Fades out the screen, so it becomes a single color. Use the parameters to customize it.
static func fade_out(
		time := 1.0, 
		color := Color.BLACK, 
		pattern := "", 
		reverse := false, 
		smooth := false,
		block_input := false        ## ENHANCEMENT
) -> Fade:
	var fader := _create_fader(color, pattern, reverse, smooth, block_input)
	fader._fade("FadeOut", time)
	return fader

## Fades in the screen, so it's visible again. Use the parameters to customize it.
static func fade_in(
		time := 1.0, 
		color := Color.BLACK, 
		pattern := "", 
		reverse := true, 
		smooth := false,
		block_input := false        ## ENHANCEMENT
) -> Fade:
	var fader := _create_fader(color, pattern, reverse, smooth, block_input)
	fader._fade("FadeIn", time)
	return fader

## Starts a crossfade effect. It will take snapshot of the current screen and freeze it (visually) 
## until [method crossfade_execute] is called. Use the parameters to customize it.
static func crossfade_prepare(
		time := 1.0, 
		pattern := "", 
		reverse := false, 
		smooth := false,
		block_input := false        ## ENHANCEMENT
) -> void:
	_get_scene_tree_root().set_meta("__crossfade__", true)
	var fader := _create_fader(Color.WHITE, pattern, reverse, smooth, block_input)
	fader.set_meta("time", time)
	_get_scene_tree_root().set_meta("__crossfade__", fader)

## Executes the crossfade. 
## [b]Before[/b] calling this method, make sure to call [method crossfade_prepare] 
## [b]and[/b] e.g. change the scene. The screen will fade from the snapshotted 
## image to the new scene.
static func crossfade_execute() -> Fade:
	assert(
		_get_scene_tree_root().has_meta("__crossfade__"), 
		"No crossfade prepared. Use Fade.crossfade_prepare() first"
	)
	var fader := _get_scene_tree_root().get_meta("__crossfade__") as Fade
	_get_scene_tree_root().remove_meta("__crossfade__")

	fader._fade("FadeIn", fader.get_meta("time"))
	return fader

## ENHANCEMENT: 
##   - Added 'block_input' param so we can optionally disable input while fading.
static func _create_fader(
		color: Color, 
		pattern: String, 
		reverse: bool, 
		smooth: bool,
		block_input := false
) -> Fade:
	if _get_scene_tree_root().has_meta("__current_fade__"):
		var old = _get_scene_tree_root().get_meta("__current_fade__")
		if is_instance_valid(old):
			old.queue_free()

	var texture: Texture2D
	if pattern.is_empty():
		smooth = true
		reverse = false

		if _get_scene_tree_root().has_meta("__1px_pattern__"):
			texture = _get_scene_tree_root().get_meta("__1px_pattern__")
		else:
			var image := Image.create(1, 1, false, Image.FORMAT_RGBA8)
			image.fill(Color.WHITE)

			texture = ImageTexture.create_from_image(image)
			_get_scene_tree_root().set_meta("__1px_pattern__", texture)
	else:
		var pattern_path := pattern_directory.path_join(pattern) + ".png"
		assert(
			ResourceLoader.exists(pattern_path, "Texture2D"), 
			"Pattern not found: '%s'. Make sure a PNG file with this name is located in '%s'." 
				% [pattern, pattern_directory]
		)
		texture = load(pattern_path)

	var fader = load("res://addons/UniversalFade/Fade.tscn").instantiate()
	fader._prepare_fade(
		color, 
		texture, 
		reverse, 
		smooth, 
		_get_scene_tree_root().get_meta("__crossfade__", false)
	)
	fader.block_input_during_fade = block_input  ## ENHANCEMENT
	_get_scene_tree_root().set_meta("__current_fade__", fader)
	_get_scene_tree_root().add_child.call_deferred(fader)
	return fader

static func _get_scene_tree_root() -> Viewport:
	return Engine.get_main_loop().root as Viewport

func _ready() -> void:
	## Connect the AnimationPlayer's "animation_finished" signal to _fade_finished 
	## if not already connected in the scene file.
	var player := $TextureRect.get_node("AnimationPlayer") if has_node("$TextureRect/AnimationPlayer") else null
	if player and not player.is_connected("animation_finished", Callable(self, "_fade_finished")):
		player.connect("animation_finished", Callable(self, "_fade_finished"))

func _prepare_fade(
		color: Color, 
		pattern: Texture2D, 
		reverse: bool, 
		smooth: bool, 
		crossfade: bool
):
	var mat := $TextureRect.material as ShaderMaterial
	mat.set_shader_parameter("color", color)
	mat.set_shader_parameter("reverse", reverse)
	mat.set_shader_parameter("smooth_mode", smooth)

	if crossfade:
		mat.set_shader_parameter("use_custom_texture", true)
		mat.set_shader_parameter("custom_texture", pattern)
		$TextureRect.texture = ImageTexture.create_from_image(_get_scene_tree_root().get_texture().get_image())
	else:
		$TextureRect.texture = pattern

## ENHANCEMENT: Basic input blocking 
func _input(event: InputEvent) -> void:
	if block_input_during_fade:
		# Prevent all input from propagating while fade is active
		event.consume()

func _fade(animation: StringName, time: float):
	assert(time > 0, "Time must be greater than 0.")
	var player := $TextureRect.get_node("AnimationPlayer") as AnimationPlayer
	player.play(animation, -1, 1.0 / time)
	player.advance(0)

func _fade_finished(anim_name: StringName) -> void:
	finished.emit()

	## ENHANCEMENT: Once fade is finished, re-allow input if it was blocked.
	block_input_during_fade = false

	if anim_name == "FadeIn":
		queue_free()
Notable Enhancements
Optional Input Blocking

Added a block_input_during_fade property and _input handler that consumes all input events while fading.
Exposed a block_input parameter in fade_out, fade_in, and crossfade_prepare to let you toggle this behavior.
AnimationPlayer Connection

In _ready(), we ensure the local AnimationPlayer is connected to _fade_finished. This is sometimes set via the scene, but the script also tries to connect if not already.
Minor Code Checks

We do an assert(time > 0) to prevent zero or negative durations.
We confirm pattern existence via ResourceLoader.exists(...), logging a helpful error if missing.
Deferred Setup

We continue to add_child.call_deferred(fader) for safety, ensuring the fade node is fully created after the current frame.
These enhancements help make the script more robust and flexible: you can decide whether to block the user’s input while the fade happens, gracefully handle missing patterns, and have clearer error-checking. Feel free to rename or remove any additions that don’t fit your workflow.
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.

1 participant