Skip to content

Commit

Permalink
Improve docs on Background, Audio, Input subsystems and DGH (di…
Browse files Browse the repository at this point in the history
  • Loading branch information
CakeVR authored Mar 10, 2024
1 parent 639948b commit 64ca5cf
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 72 deletions.
64 changes: 39 additions & 25 deletions addons/dialogic/Core/DialogicGameHandler.gd
Original file line number Diff line number Diff line change
Expand Up @@ -22,64 +22,77 @@ enum States {
enum ClearFlags {
FULL_CLEAR = 0, ## Clears all subsystems
KEEP_VARIABLES = 1, ## Clears all subsystems and info except for variables
TIMLEINE_INFO_ONLY = 2 ## Doesn't clear subsystems but current timeline and index
TIMELINE_INFO_ONLY = 2 ## Doesn't clear subsystems but current timeline and index
}

## Reference to the currently executed timeline.
var current_timeline: DialogicTimeline = null
## Copy of the [member current_timeline]'s events.
var current_timeline_events: Array = []

## Index of the event the timeline handeling is currently at.
## Index of the event the timeline handling is currently at.
var current_event_idx: int = 0
## Contains all information that subsystems consider
## relevant for the current situation
## Contains all information that subsystems consider relevant for
## the current situation
var current_state_info: Dictionary = {}
## Current state (see [member States] enum)

## Current state (see [member States] enum).
var current_state := States.IDLE:
get:
return current_state

set(new_state):
current_state = new_state
emit_signal('state_changed', new_state)
state_changed.emit(new_state)

## Emitted when [member current_state] change.
signal state_changed(new_state:States)

## When `true`, many dialogic processes won't continue until it's false again.
## When `true`, many dialogic processes won't continue until it's `false` again.
var paused := false:
set(value):
paused = value

if paused:

for subsystem in get_children():

if subsystem is DialogicSubsystem:
(subsystem as DialogicSubsystem).pause()

dialogic_paused.emit()

else:
for subsystem in get_children():

if subsystem is DialogicSubsystem:
(subsystem as DialogicSubsystem).resume()

dialogic_resumed.emit()

## Emitted when [member paused] changes to true.
## Emitted when [member paused] changes to `true`.
signal dialogic_paused
## Emitted when [member paused] changes to false.
## Emitted when [member paused] changes to `false`.
signal dialogic_resumed


## Emitted when dialog ends (by a timeline end being reached OR end_timeline() being called).
## Emitted when the timeline ends.
## This can be a timeline ending or [method end_timeline] being called.
signal timeline_ended
## Emitted when a timeline was started with [method start] or [method start_timeline].
## Emitted when a timeline starts by calling either [method start]
## or [method start_timeline].
signal timeline_started
## Emitted when an event has just been executed (not necessarily when the event finished).
signal event_handled(resource:DialogicEvent)
## Emitted when an event starts being executed.
## The event may not have finished executing yet.
signal event_handled(resource: DialogicEvent)

## Emitted when the `Signal Event` was reached
signal signal_event(argument:Variant)
## Emitted when `[signal]` effect was reached in text.
signal text_signal(argument:String)
## Emitted when a [class SignalEvent] event was reached.
signal signal_event(argument: Variant)
## Emitted when a signal event gets fired from a [class TextEvent] event.
signal text_signal(argument: String)


# Careful, this section is repopulated automatically at certain moments
# Careful, this section is repopulated automatically at certain moments.
#region SUBSYSTEMS

var Audio := preload("res://addons/dialogic/Modules/Audio/subsystem_audio.gd").new():
Expand Down Expand Up @@ -227,13 +240,13 @@ func preload_timeline(timeline_resource:Variant) -> Variant:

## Clears and stops the current timeline.
func end_timeline() -> void:
clear(ClearFlags.TIMLEINE_INFO_ONLY)
clear(ClearFlags.TIMELINE_INFO_ONLY)
_on_timeline_ended()
timeline_ended.emit()


## Handles the next event.
func handle_next_event(ignore_argument:Variant = "") -> void:
func handle_next_event(_ignore_argument: Variant = "") -> void:
handle_event(current_event_idx+1)


Expand Down Expand Up @@ -269,12 +282,13 @@ func handle_event(event_index:int) -> void:
event_handled.emit(current_timeline_events[event_index])


## Resets dialogics state fully or partially.
## By using the clear flags from the [member ClearFlags] enum you can specify what info should be kept.
## For example at timeline end usually it doesn't clear node or subsystem info
func clear(clear_flags:=ClearFlags.FULL_CLEAR) -> bool:
## Resets Dialogic's state fully or partially.
## By using the clear flags from the [member ClearFlags] enum you can specify
## what info should be kept.
## For example, at timeline end usually it doesn't clear node or subsystem info.
func clear(clear_flags := ClearFlags.FULL_CLEAR) -> bool:

if !clear_flags & ClearFlags.TIMLEINE_INFO_ONLY:
if !clear_flags & ClearFlags.TIMELINE_INFO_ONLY:
for subsystem in get_children():
if subsystem is DialogicSubsystem:
(subsystem as DialogicSubsystem).clear_game_state(clear_flags)
Expand Down
8 changes: 4 additions & 4 deletions addons/dialogic/Editor/TimelineEditor/test_timeline_scene.gd
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ func _ready() -> void:
get_tree().quit()
DialogicUtil.autoload().start(current_timeline)
DialogicUtil.autoload().timeline_ended.connect(get_tree().quit)
DialogicUtil.autoload().signal_event.connect(recieve_event_signal)
DialogicUtil.autoload().text_signal.connect(recieve_text_signal)
DialogicUtil.autoload().signal_event.connect(receive_event_signal)
DialogicUtil.autoload().text_signal.connect(receive_text_signal)

func recieve_event_signal(argument:String) -> void:
func receive_event_signal(argument:String) -> void:
print("[Dialogic] Encountered a signal event: ", argument)

func recieve_text_signal(argument:String) -> void:
func receive_text_signal(argument:String) -> void:
print("[Dialogic] Encountered a signal in text: ", argument)

func _input(event:InputEvent) -> void:
Expand Down
59 changes: 50 additions & 9 deletions addons/dialogic/Modules/Audio/subsystem_audio.gd
Original file line number Diff line number Diff line change
@@ -1,22 +1,57 @@
extends DialogicSubsystem

## Subsystem that manages music and sounds.

signal music_started(info:Dictionary)
signal sound_started(info:Dictionary)

## Subsystem for managing background music and one-shot sound effects.
##
## This subsystem has many different helper methods for managing audio
## in your timeline.
## For instance, you can listen to music changes via [signal music_started].


## Whenever a new background music is started, this signal is emitted and
## contains a dictionary with the following keys: [br]
## [br]
## Key | Value Type | Value [br]
## ----------- | ------------- | ----- [br]
## `path` | [type String] | The path to the audio resource file. [br]
## `volume` | [type float] | The volume of the audio resource that will be set to the [member base_music_player]. [br]
## `audio_bus` | [type String] | The audio bus name that the [member base_music_player] will use. [br]
## `loop` | [type bool] | Whether the audio resource will loop or not once it finishes playing. [br]
signal music_started(info: Dictionary)


## Whenever a new sound effect is set, this signal is emitted and contains a
## dictionary with the following keys: [br]
## [br]
## Key | Value Type | Value [br]
## ----------- | ------------- | ----- [br]
## `path` | [type String] | The path to the audio resource file. [br]
## `volume` | [type float] | The volume of the audio resource that will be set to [member base_sound_player]. [br]
## `audio_bus` | [type String] | The audio bus name that the [member base_sound_player] will use. [br]
## `loop` | [type bool] | Whether the audio resource will loop or not once it finishes playing. [br]
signal sound_started(info: Dictionary)


## Audio player base duplicated to play background music.
##
## Background music is long audio.
var base_music_player := AudioStreamPlayer.new()
## Audio player base, that will be duplicated to play sound effects.
##
## Sound effects are short audio.
var base_sound_player := AudioStreamPlayer.new()


#region STATE
####################################################################################################

func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
## Clears the state on this subsystem and stops all audio.
##
## If you want to stop sounds only, use [method stop_all_sounds].
func clear_game_state(clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
update_music()
stop_all_sounds()


## Loads the state on this subsystem from the current state info.
func load_game_state(load_flag:=LoadFlags.FULL_LOAD) -> void:
if load_flag == LoadFlags.ONLY_DNODES:
return
Expand All @@ -27,11 +62,13 @@ func load_game_state(load_flag:=LoadFlags.FULL_LOAD) -> void:
update_music(info.path, info.volume, info.audio_bus, 0, info.loop)


## Pauses playing audio.
func pause() -> void:
for child in get_children():
child.stream_paused = true


## Resumes playing audio.
func resume() -> void:
for child in get_children():
child.stream_paused = false
Expand Down Expand Up @@ -85,12 +122,13 @@ func update_music(path := "", volume := 0.0, audio_bus := "Master", fade_time :=
fader.tween_callback(prev_node.queue_free)


## Whether music is playing.
func has_music() -> bool:
return !dialogic.current_state_info.get('music', {}).get('path', '').is_empty()


## Plays a given sound file.
func play_sound(path:String, volume := 0.0, audio_bus := "Master", loop := false) -> void:
func play_sound(path: String, volume := 0.0, audio_bus := "Master", loop := false) -> void:
if base_sound_player != null and !path.is_empty():
sound_started.emit({'path':path, 'volume':volume, 'audio_bus':audio_bus, 'loop':loop})
var new_sound_node := base_sound_player.duplicate()
Expand All @@ -110,6 +148,7 @@ func play_sound(path:String, volume := 0.0, audio_bus := "Master", loop := false
new_sound_node.finished.connect(new_sound_node.queue_free)


## Stops all audio.
func stop_all_sounds() -> void:
for node in get_children():
if node == base_sound_player:
Expand All @@ -118,7 +157,9 @@ func stop_all_sounds() -> void:
node.queue_free()


func interpolate_volume_linearly(value:float, node:Node) -> void:
## Converts a linear loudness value to decibel and sets that volume to
## the given [param node].
func interpolate_volume_linearly(value: float, node: Node) -> void:
node.volume_db = linear_to_db(value)


Expand Down
36 changes: 26 additions & 10 deletions addons/dialogic/Modules/Background/subsystem_backgrounds.gd
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
extends DialogicSubsystem

## Subsystem for managing backgrounds.

signal background_changed(info:Dictionary)


##
## 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
####################################################################################################

func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR):
## Empties the current background state.
func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
update_background()


func load_game_state(load_flag:=LoadFlags.FULL_LOAD):
## 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
Expand Down Expand Up @@ -128,7 +143,8 @@ func _on_transition_finished(background_node:DialogicNode_BackgroundHolder, tran
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()
Expand Down Expand Up @@ -160,7 +176,7 @@ func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder

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()

Expand Down
12 changes: 9 additions & 3 deletions addons/dialogic/Modules/Core/subsystem_input.gd
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
extends DialogicSubsystem
## Subsystem that handles input, Auto-Advance, and skipping.
##
## This subsystem can be accessed via GDScript: `Dialogic.Inputs`.

## Subsystem that handles input, autoadvance & skipping.

signal dialogic_action_priority
signal dialogic_action

## Whenever the Auto-Skip timer finishes, this signal is emitted.
## Configure Auto-Skip settings via [member auto_skip].
signal autoskip_timer_finished


Expand All @@ -18,7 +23,8 @@ var auto_advance : DialogicAutoAdvance = null
#region SUBSYSTEM METHODS
################################################################################

func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:

func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
if not is_node_ready():
await ready

Expand Down Expand Up @@ -142,7 +148,7 @@ func _on_autoskip_toggled(enabled: bool) -> void:
## Handles fine-grained Auto-Skip logic.
## The [method _process] method allows for a more precise timer than the
## [Timer] class.
func _process(delta):
func _process(delta: float) -> void:
if _auto_skip_timer_left > 0:
_auto_skip_timer_left -= delta

Expand Down
19 changes: 13 additions & 6 deletions addons/dialogic/Modules/Save/subsystem_save.gd
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
extends DialogicSubsystem

### Subsystem that manages saving and loading data.
## Subsystem to save and load game states.
##
## This subsystem has many different helper methods to save Dialogic or custom
## game data to named save slots.
##
## You can listen to saves via [signal saved]. \
## If you want to save, you can call [method save]. \


## Emitted when a save happened.
## The [param info] contains the following keys:
## - slot_name: The `String` name of the slot that the game state was saved to.
## - is_autosave: `true` if the save was an autosave.
## Emitted when a save happened with the following info:
## [br]
## Key | Value Type | Value [br]
## ----------- | ------------- | ----- [br]
## `slot_name` | [type String] | The name of the slot that the game state was saved to. [br]
## `is_autosave` | [type bool] | `true`, if the save was an autosave. [br]
signal saved(info: Dictionary)


Expand Down
Loading

0 comments on commit 64ca5cf

Please sign in to comment.