From 5af0e549e6120d3f79589b6c06709856b9d2362d Mon Sep 17 00:00:00 2001 From: Askarus Date: Thu, 11 Nov 2021 11:04:56 +0100 Subject: [PATCH 1/2] This branch contains multiple bugfixes and improvements. There are comments in the code which explain the changes made but needs to be removed when merging into main Bugfixes: 1. _leave did not reset the character position after the animation finished. _enter on the other side needs the sprite to start from its original position. I fixt that by resetting the sprite when the tween finishes. 2. Pressing ui_accept causes animations to be skipped. As the same action is required to advance text, every animation except the first one was skipped. I removed that animation skip functionality, as it's required in my opinion and solves that issue. ------ Improvements: 1. There can now be 4 characters on screen instead of 2. The added ones are named left_center and right_center 2. Now only the talking character gets focus and is displayed in color. All the others are grey. 3. Characters can leave the screen now and talk from the off without becoming visible again. I added a new animation called -hidden- for that cause. --- godot/Characters/CharacterDisplayer.gd | 140 ++++++++++++++++++++--- godot/Characters/CharacterDisplayer.tscn | 17 ++- 2 files changed, 139 insertions(+), 18 deletions(-) diff --git a/godot/Characters/CharacterDisplayer.gd b/godot/Characters/CharacterDisplayer.gd index c65e7ec..6d00f6b 100644 --- a/godot/Characters/CharacterDisplayer.gd +++ b/godot/Characters/CharacterDisplayer.gd @@ -7,53 +7,128 @@ extends Node signal display_finished ## Maps animation text ids to a function that animates a character sprite. -const ANIMATIONS := {"enter": "_enter", "leave": "_leave"} -const SIDE := {LEFT = "left", RIGHT = "right"} +const ANIMATIONS := {"enter": "_enter", "leave": "_leave", "hidden": "_hidden"} +const SIDE := {LEFT = "left", LEFT_CENTER = "left_center", RIGHT = "right", RIGHT_CENTER = "right_center"} const COLOR_WHITE_TRANSPARENT = Color(1.0, 1.0, 1.0, 0.0) +const COLOR_SPRITE_NOT_TALKING = Color(0.27451, 0.27451, 0.27451) +const COLOR_SPRITE_FOCUSED = Color(1.0, 1.0, 1.0) ## Keeps track of the character displayed on either side. -var _displayed := {left = null, right = null} +var _displayed := {left = null, left_center = null, right = null, right_center = null} +var _focused := "" onready var _tween: Tween = $Tween onready var _left_sprite: Sprite = $Left onready var _right_sprite: Sprite = $Right +onready var _left_center_sprite: Sprite = $LeftCenter +onready var _right_center_sprite: Sprite = $RightCenter func _ready() -> void: _left_sprite.hide() _right_sprite.hide() + _left_center_sprite.hide() + _right_center_sprite.hide() _tween.connect("tween_all_completed", self, "_on_Tween_tween_all_completed") - +# NOTE: +# This code does not make sense +# As soon as you press ui_accept the animation is skipped +# That always happens when the player presses Enter/Space to advance the text +# That way animations will never play except for the first animation or when animations play automatically +# func _unhandled_input(event: InputEvent) -> void: # If the player presses enter before the character animations ended, we seek to the end. - if event.is_action_pressed("ui_accept") and _tween.is_active(): - _tween.seek(INF) +# if event.is_action_pressed("ui_accept") and _tween.is_active(): +# _tween.seek(INF) + pass -func display(character: Character, side: String = SIDE.LEFT, expression := "", animation := "") -> void: +func display(character: Character, side: String = "", expression := "", animation := "") -> void: # assert(side in SIDE.values()) - + # Keeps track of a character that's already displayed on a given side - var sprite: Sprite = _left_sprite if side == SIDE.LEFT else _right_sprite + var sprite: Sprite = _left_sprite + + if side == SIDE.LEFT: + sprite = _left_sprite + elif side == SIDE.LEFT_CENTER: + sprite = _left_center_sprite + elif side == SIDE.RIGHT: + sprite = _right_sprite + elif side == SIDE.RIGHT_CENTER: + sprite = _right_center_sprite + if character == _displayed.left: sprite = _left_sprite elif character == _displayed.right: sprite = _right_sprite + elif character == _displayed.left_center: + sprite = _left_center_sprite + elif character == _displayed.right_center: + sprite = _right_center_sprite else: _displayed[side] = character - + + _determine_focus(character.id, side, sprite) + if _focused == "narrator": + # Focus none and return. + focus_sprite() + return + sprite.texture = character.get_image(expression) - + + focus_sprite(sprite) # Needs to be done before the animation plays. Don't know why exactly + if animation != "": call(ANIMATIONS[animation], side, sprite) - + sprite.show() +func _determine_focus(character_id: String, side: String, sprite: Sprite) -> void: + if character_id == "narrator": + # We have no other information than the character id to determine the narrator + _focused = "narrator" + elif side != "": + # If there is a side specified, we want to focus that + _focused = side + elif side == "": + # If no side is specified, we need to determine which sprite is talking + # We need that to cover the following case + # - Character enters side -> gets focus + # - Narrator talks -> character looses focus + # - Character talks again -> no side specified, but the character needs focus + if sprite == _left_sprite: + _focused = "left" + elif sprite == _left_center_sprite: + _focused = "left_center" + elif sprite == _right_sprite: + _focused = "right" + elif sprite == _right_center_sprite: + _focused = "right_center" + + +# Fade all sprites to gray and make the non focused one colored +func focus_sprite(sprite: Sprite = null) -> void: + _left_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING + _left_sprite.modulate = COLOR_SPRITE_NOT_TALKING + _right_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING + _right_sprite.modulate = COLOR_SPRITE_NOT_TALKING + + if _focused == SIDE.LEFT: + _left_sprite.modulate = COLOR_SPRITE_FOCUSED + elif _focused == SIDE.LEFT_CENTER: + _left_center_sprite.modulate = COLOR_SPRITE_FOCUSED + elif _focused == SIDE.RIGHT: + _right_sprite.modulate = COLOR_SPRITE_FOCUSED + elif _focused == SIDE.RIGHT_CENTER: + _right_center_sprite.modulate = COLOR_SPRITE_FOCUSED + + ## Fades in and moves the character to the anchor position. func _enter(from_side: String, sprite: Sprite) -> void: - var offset := -200 if from_side == SIDE.LEFT else 200 + var offset := -200 if (from_side == SIDE.LEFT or from_side == SIDE.LEFT_CENTER) else 200 var start := sprite.position + Vector2(offset, 0.0) var end := sprite.position @@ -61,6 +136,7 @@ func _enter(from_side: String, sprite: Sprite) -> void: _tween.interpolate_property( sprite, "position", start, end, 0.5, Tween.TRANS_QUINT, Tween.EASE_OUT ) + _tween.interpolate_property(sprite, "modulate", COLOR_WHITE_TRANSPARENT, Color.white, 0.25) _tween.start() @@ -69,9 +145,17 @@ func _enter(from_side: String, sprite: Sprite) -> void: sprite.position = start sprite.modulate = COLOR_WHITE_TRANSPARENT - +# +# NOTE +# _enter and _leave do not play well together +# _enter takes the original sprite position as a starting point and starts from an offset +# _leave however moves the sprite to an offset and does not reset it to its +# original position afterwards +# -> This will breake _enter as it takes the offset as its original starting position now +# +# func _leave(from_side: String, sprite: Sprite) -> void: - var offset := -200 if from_side == SIDE.LEFT else 200 + var offset := -200 if from_side == SIDE.LEFT or SIDE.LEFT_CENTER else 200 var start := sprite.position var end := sprite.position + Vector2(offset, 0.0) @@ -89,9 +173,33 @@ func _leave(from_side: String, sprite: Sprite) -> void: Tween.EASE_OUT, 0.25 ) + + _tween.connect("tween_all_completed", self, "_on_tween_leave_completed", [from_side, start]) + _tween.start() _tween.seek(0.0) - +# sprite.modulate = COLOR_WHITE_TRANSPARENT + + +# Resets the sprite position after a character left +func _on_tween_leave_completed(side: String, original_sprite_position: Vector2) -> void: + _tween.disconnect("tween_all_completed", self, "_on_tween_leave_completed") + if side == SIDE.LEFT: + _left_sprite.position = original_sprite_position + elif side == SIDE.LEFT_CENTER: + _left_center_sprite.position = original_sprite_position + elif side == SIDE.RIGHT: + _right_sprite.position = original_sprite_position + elif side == SIDE.RIGHT_CENTER: + _right_center_sprite.position = original_sprite_position + + +# This "animation" is used to allow a character that left the screen to say something +# The sprite is transparent, so it can not show an other character +# This adds not an additional hidden character to the existing 5 +func _hidden(from_side: String, sprite: Sprite) -> void: + sprite.modulate = COLOR_WHITE_TRANSPARENT + func _on_Tween_tween_all_completed() -> void: emit_signal("display_finished") diff --git a/godot/Characters/CharacterDisplayer.tscn b/godot/Characters/CharacterDisplayer.tscn index f3932ec..8981a6f 100644 --- a/godot/Characters/CharacterDisplayer.tscn +++ b/godot/Characters/CharacterDisplayer.tscn @@ -10,12 +10,25 @@ __meta__ = { "_edit_vertical_guides_": [ 1920.49 ] } +[node name="LeftCenter" type="Sprite" parent="."] +modulate = Color( 0.27451, 0.27451, 0.27451, 1 ) +position = Vector2( 560.631, 659.441 ) +texture = ExtResource( 2 ) + [node name="Left" type="Sprite" parent="."] -position = Vector2( 330.836, 655.203 ) +modulate = Color( 0.27451, 0.27451, 0.27451, 1 ) +position = Vector2( 279.836, 655.203 ) texture = ExtResource( 2 ) +[node name="RightCenter" type="Sprite" parent="."] +modulate = Color( 0.27451, 0.27451, 0.27451, 1 ) +position = Vector2( 1417.01, 655.203 ) +texture = ExtResource( 3 ) +flip_h = true + [node name="Right" type="Sprite" parent="."] -position = Vector2( 1592.01, 655.203 ) +modulate = Color( 0.27451, 0.27451, 0.27451, 1 ) +position = Vector2( 1664.01, 655.203 ) texture = ExtResource( 3 ) flip_h = true From 60b21e72f7708f262b5c7e9e94f1e672647544c8 Mon Sep 17 00:00:00 2001 From: Askarus Date: Mon, 15 Nov 2021 08:35:53 +0100 Subject: [PATCH 2/2] Fixed a bug where a character appears after it left the screen when an other one gets focus. MAde the game to quit and not end in a black screen when the last scene gets played --- godot/Characters/CharacterDisplayer.gd | 20 +++++++++++++++----- godot/Main.gd | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/godot/Characters/CharacterDisplayer.gd b/godot/Characters/CharacterDisplayer.gd index 6d00f6b..323fb5c 100644 --- a/godot/Characters/CharacterDisplayer.gd +++ b/godot/Characters/CharacterDisplayer.gd @@ -111,10 +111,16 @@ func _determine_focus(character_id: String, side: String, sprite: Sprite) -> voi # Fade all sprites to gray and make the non focused one colored func focus_sprite(sprite: Sprite = null) -> void: - _left_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING - _left_sprite.modulate = COLOR_SPRITE_NOT_TALKING - _right_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING - _right_sprite.modulate = COLOR_SPRITE_NOT_TALKING + + # We need to make sure not to display a sprite that has left the screen + if _displayed.left_center != null: + _left_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING + if _displayed.left != null: + _left_sprite.modulate = COLOR_SPRITE_NOT_TALKING + if _displayed.right_center != null: + _right_center_sprite.modulate = COLOR_SPRITE_NOT_TALKING + if _displayed.right != null: + _right_sprite.modulate = COLOR_SPRITE_NOT_TALKING if _focused == SIDE.LEFT: _left_sprite.modulate = COLOR_SPRITE_FOCUSED @@ -155,7 +161,7 @@ func _enter(from_side: String, sprite: Sprite) -> void: # # func _leave(from_side: String, sprite: Sprite) -> void: - var offset := -200 if from_side == SIDE.LEFT or SIDE.LEFT_CENTER else 200 + var offset := -200 if (from_side == SIDE.LEFT or from_side == SIDE.LEFT_CENTER) else 200 var start := sprite.position var end := sprite.position + Vector2(offset, 0.0) @@ -192,6 +198,10 @@ func _on_tween_leave_completed(side: String, original_sprite_position: Vector2) _right_sprite.position = original_sprite_position elif side == SIDE.RIGHT_CENTER: _right_center_sprite.position = original_sprite_position + + # We want sprites to be able to leave and reappear somewhere else + # This is also needed to not show invisible sprites when an other one gets focus + _displayed[side] = null # This "animation" is used to allow a character that left the screen to say something diff --git a/godot/Main.gd b/godot/Main.gd index 5fc54a8..c22b408 100644 --- a/godot/Main.gd +++ b/godot/Main.gd @@ -53,6 +53,7 @@ func _play_scene(index: int) -> void: func _on_ScenePlayer_scene_finished() -> void: # If the scene that ended is the last scene, we're done playing the game. if _current_index == SCENES.size() - 1: + get_tree().quit() return _play_scene(_current_index + 1)