Files
orzo/core/spine_dialogic_portrait.gd

88 lines
3.2 KiB
GDScript

@tool
class_name SpineDialogicPortrait
extends DialogicPortrait
#region EXPORTS
@export_group("Main")
## Path to the .tres SpineSkeletonDataResource file.
@export_file var spine_skeleton_data_file := ""
func _ready() -> void:
$SpineSprite.animation_completed.connect(_on_animation_completed)
# Just a signal connection example
func _on_animation_completed(spine_sprite: Object, animation_state: SpineAnimationState, track_entry: SpineTrackEntry) -> void:
print(track_entry)
pass
#region DIALOGIC PORTRAIT OVERRIDES
## If the next portrait uses the same scene, reuse this instance rather than
## creating a new one (allows smooth animation transitions).
func _should_do_portrait_update(_character: DialogicCharacter, _portrait: String) -> bool:
return true
## Called by Dialogic when the portrait is first shown or changed.
## [param passed_character] — the DialogicCharacter resource.
## [param passed_portrait] — the portrait name (e.g. "Idle", "Walk").
##
## Export overrides (like spine_skeleton_data_file) are applied by Dialogic
## *before* this method is called.
func _update_portrait(passed_character: DialogicCharacter, passed_portrait: String) -> void:
apply_character_and_portrait(passed_character, passed_portrait)
# Load the skeleton data file (export override from character portrait config).
if not spine_skeleton_data_file.is_empty() and ResourceLoader.exists(spine_skeleton_data_file):
var skel_res := load(spine_skeleton_data_file)
if skel_res:
$SpineSprite.skeleton_data_res = skel_res
# Anchor the SpineSprite at the root origin. Dialogic treats the portrait
# root's (0,0) as the bottom-center pivot. Scale is applied by the portrait
# container, so we reset the SpineSprite's own scale to 1.
$SpineSprite.position = Vector2.ZERO
$SpineSprite.scale = Vector2.ONE
# Play the animation matching the portrait name (loop on track 0).
var anim_name := passed_portrait
var loop := anim_name == "walk"
$SpineSprite.get_animation_state().set_animation(anim_name, loop, 0)
## Returns the bounding rectangle of this portrait relative to the root node.
## The root node's origin (0,0) is the spine skeleton's root bone.
## Dialogic uses this rect to compute the scale/offset for the portrait.
func _get_covered_rect() -> Rect2:
if not is_instance_valid($SpineSprite):
return Rect2()
# Use the skeleton's own bounds — the rect is in the skeleton's local
# space, relative to the root bone at (0,0).
return $SpineSprite.get_skeleton().get_bounds()
## Called by Dialogic when the character should be mirrored (e.g. facing left
## on a right-side position).
func _set_mirror(mirror: bool) -> void:
if not is_instance_valid($SpineSprite):
return
# Mirror by flipping the skeleton horizontally.
$SpineSprite.get_skeleton().set_scale_x(-1.0 if mirror else 1.0)
## Called when this character becomes the active speaker.
func _highlight() -> void:
if not is_instance_valid($SpineSprite):
return
# Visual feedback: brighten slightly when speaking.
$SpineSprite.modulate = Color(1.2, 1.2, 1.2, 1.0)
## Called when this character stops being the active speaker.
func _unhighlight() -> void:
if not is_instance_valid($SpineSprite):
return
$SpineSprite.modulate = Color(1.0, 1.0, 1.0, 1.0)