-
-
Notifications
You must be signed in to change notification settings - Fork 213
/
subsystem_backgrounds.gd
183 lines (147 loc) 路 7.56 KB
/
subsystem_backgrounds.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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