You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
7.6 KiB
184 lines
7.6 KiB
6 months ago
|
extends DialogicSubsystem
|
||
|
## Subsystem for managing backgrounds.
|
||
|
##
|
||
|
## This subsystem has many different helper methods for managing backgrounds.
|
||
|
## For instance, you can listen to background changes via
|
||
|
## [signal background_changed].
|
||
|
|
||
|
|
||
|
## Whenever a new background is set, this signal is emitted and contains a
|
||
|
## dictionary with the following keys: [br]
|
||
|
## [br]
|
||
|
## Key | Value Type | Value [br]
|
||
|
## ----------- | ------------- | ----- [br]
|
||
|
## `scene` | [type String] | The scene path of the new background. [br]
|
||
|
## `argument` | [type String] | Information given to the background on its update routine. [br]
|
||
|
## `fade_time` | [type float] | The time the background may take to transition in. [br]
|
||
|
## `same_scene`| [type bool] | If the new background uses the same Godot scene. [br]
|
||
|
signal background_changed(info: Dictionary)
|
||
|
|
||
|
## The default background scene Dialogic will use.
|
||
|
var default_background_scene: PackedScene = load(get_script().resource_path.get_base_dir().path_join('DefaultBackgroundScene/default_background.tscn'))
|
||
|
## The default transition Dialogic will use.
|
||
|
var default_transition: String = get_script().resource_path.get_base_dir().path_join("Transitions/Defaults/simple_fade.gd")
|
||
|
|
||
|
|
||
|
#region STATE
|
||
|
####################################################################################################
|
||
|
|
||
|
## Empties the current background state.
|
||
|
func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
|
||
|
update_background()
|
||
|
|
||
|
## Loads the background state from the current state info.
|
||
|
func load_game_state(_load_flag := LoadFlags.FULL_LOAD) -> void:
|
||
|
update_background(dialogic.current_state_info.get('background_scene', ''), dialogic.current_state_info.get('background_argument', ''), 0.0, default_transition, true)
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
|
||
|
#region MAIN METHODS
|
||
|
####################################################################################################
|
||
|
|
||
|
## Method that adds a given scene as child of the DialogicNode_BackgroundHolder.
|
||
|
## It will call [_update_background()] on that scene with the given argument [argument].
|
||
|
## It will call [_fade_in()] on that scene with the given fade time.
|
||
|
## Will call fade_out on previous backgrounds scene.
|
||
|
##
|
||
|
## If the scene is the same as the last background you can bypass another instantiating
|
||
|
## and use the same scene.
|
||
|
## To do so implement [_should_do_background_update()] on the custom background scene.
|
||
|
## Then [_update_background()] will be called directly on that previous scene.
|
||
|
func update_background(scene := "", argument := "", fade_time := 0.0, transition_path:=default_transition, force := false) -> void:
|
||
|
var background_holder: DialogicNode_BackgroundHolder
|
||
|
if dialogic.has_subsystem('Styles'):
|
||
|
background_holder = dialogic.Styles.get_first_node_in_layout('dialogic_background_holders')
|
||
|
else:
|
||
|
background_holder = get_tree().get_first_node_in_group('dialogic_background_holders')
|
||
|
|
||
|
var info := {'scene':scene, 'argument':argument, 'fade_time':fade_time, 'same_scene':false}
|
||
|
if background_holder == null:
|
||
|
background_changed.emit(info)
|
||
|
return
|
||
|
|
||
|
|
||
|
var bg_set := false
|
||
|
|
||
|
# First try just updating the existing scene.
|
||
|
if scene == dialogic.current_state_info.get('background_scene', ''):
|
||
|
|
||
|
if not force and argument == dialogic.current_state_info.get('background_argument', ''):
|
||
|
return
|
||
|
|
||
|
for old_bg in background_holder.get_children():
|
||
|
if !old_bg.has_meta('node') or not old_bg.get_meta('node') is DialogicBackground:
|
||
|
continue
|
||
|
|
||
|
var prev_bg_node: DialogicBackground = old_bg.get_meta('node')
|
||
|
if prev_bg_node._should_do_background_update(argument):
|
||
|
prev_bg_node._update_background(argument, fade_time)
|
||
|
bg_set = true
|
||
|
info['same_scene'] = true
|
||
|
|
||
|
dialogic.current_state_info['background_scene'] = scene
|
||
|
dialogic.current_state_info['background_argument'] = argument
|
||
|
|
||
|
if bg_set:
|
||
|
background_changed.emit(info)
|
||
|
return
|
||
|
|
||
|
var old_viewport: SubViewportContainer = null
|
||
|
if background_holder.has_meta('current_viewport'):
|
||
|
old_viewport = background_holder.get_meta('current_viewport', null)
|
||
|
|
||
|
var new_viewport: SubViewportContainer
|
||
|
if scene.ends_with('.tscn') and ResourceLoader.exists(scene):
|
||
|
new_viewport = add_background_node(load(scene), background_holder)
|
||
|
elif argument:
|
||
|
new_viewport = add_background_node(default_background_scene, background_holder)
|
||
|
else:
|
||
|
new_viewport = null
|
||
|
|
||
|
var trans_script: Script = load(DialogicResourceUtil.guess_special_resource("BackgroundTransition", transition_path, default_transition))
|
||
|
var trans_node := Node.new()
|
||
|
trans_node.set_script(trans_script)
|
||
|
trans_node = (trans_node as DialogicBackgroundTransition)
|
||
|
trans_node.bg_holder = background_holder
|
||
|
trans_node.time = fade_time
|
||
|
|
||
|
if old_viewport:
|
||
|
trans_node.prev_scene = old_viewport.get_meta('node', null)
|
||
|
trans_node.prev_texture = old_viewport.get_child(0).get_texture()
|
||
|
old_viewport.get_meta('node')._custom_fade_out(fade_time)
|
||
|
old_viewport.hide()
|
||
|
# TODO We have to call this again here because of https://github.com/godotengine/godot/issues/23729
|
||
|
old_viewport.get_child(0).render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||
|
trans_node.transition_finished.connect(old_viewport.queue_free)
|
||
|
if new_viewport:
|
||
|
trans_node.next_scene = new_viewport.get_meta('node', null)
|
||
|
trans_node.next_texture = new_viewport.get_child(0).get_texture()
|
||
|
new_viewport.get_meta('node')._update_background(argument, fade_time)
|
||
|
new_viewport.get_meta('node')._custom_fade_in(fade_time)
|
||
|
else:
|
||
|
background_holder.remove_meta('current_viewport')
|
||
|
|
||
|
add_child(trans_node)
|
||
|
if fade_time == 0:
|
||
|
trans_node.transition_finished.emit()
|
||
|
_on_transition_finished(background_holder, trans_node)
|
||
|
else:
|
||
|
trans_node.transition_finished.connect(_on_transition_finished.bind(background_holder, trans_node))
|
||
|
# We need to break this connection if the background_holder get's removed during the transition
|
||
|
background_holder.tree_exited.connect(trans_node.disconnect.bind("transition_finished", _on_transition_finished))
|
||
|
trans_node._fade()
|
||
|
|
||
|
background_changed.emit(info)
|
||
|
|
||
|
|
||
|
func _on_transition_finished(background_node:DialogicNode_BackgroundHolder, transition_node:DialogicBackgroundTransition) -> void:
|
||
|
if background_node.has_meta("current_viewport"):
|
||
|
if background_node.get_meta("current_viewport").get_meta("node", null) == transition_node.next_scene:
|
||
|
background_node.get_meta("current_viewport").show()
|
||
|
background_node.material = null
|
||
|
background_node.color = Color.TRANSPARENT
|
||
|
transition_node.queue_free()
|
||
|
|
||
|
## Adds sub-viewport with the given background scene as child to
|
||
|
## Dialogic scene.
|
||
|
func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder) -> SubViewportContainer:
|
||
|
var v_con := SubViewportContainer.new()
|
||
|
var viewport := SubViewport.new()
|
||
|
var b_scene := scene.instantiate()
|
||
|
if not b_scene is DialogicBackground:
|
||
|
printerr("[Dialogic] Given background scene was not of type DialogicBackground! Make sure the scene has a script that extends DialogicBackground.")
|
||
|
v_con.queue_free()
|
||
|
viewport.queue_free()
|
||
|
b_scene.queue_free()
|
||
|
return null
|
||
|
|
||
|
parent.add_child(v_con)
|
||
|
v_con.hide()
|
||
|
v_con.stretch = true
|
||
|
v_con.size = parent.size
|
||
|
v_con.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
|
|
||
|
v_con.add_child(viewport)
|
||
|
viewport.transparent_bg = true
|
||
|
viewport.disable_3d = true
|
||
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||
|
|
||
|
viewport.add_child(b_scene)
|
||
|
b_scene.viewport = viewport
|
||
|
b_scene.viewport_container = v_con
|
||
|
|
||
|
parent.set_meta('current_viewport', v_con)
|
||
|
v_con.set_meta('node', b_scene)
|
||
|
|
||
|
return v_con
|
||
|
|
||
|
## Whether a background is set.
|
||
|
func has_background() -> bool:
|
||
|
return !dialogic.current_state_info.get('background_scene', '').is_empty() or !dialogic.current_state_info.get('background_argument','').is_empty()
|
||
|
|
||
|
#endregion
|