Skip to content

Commit

Permalink
feat: allow using deferred calls, and show linked frames
Browse files Browse the repository at this point in the history
Fixes #12
Fixes #9

/spend 6h
  • Loading branch information
Goutte committed Mar 12, 2024
1 parent d531384 commit a7030ad
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 40 deletions.
28 changes: 24 additions & 4 deletions addons/goutte.animated_shape_2d/animated_shape_2d.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@icon("./animated_shape_2d.svg")
extends Node
class_name AnimatedShape2D
#class_name AnimatedCollisionShape2D
#class_name AnimatedSprite2DCollisions
#class_name CollisionShape2DFramer

Expand Down Expand Up @@ -48,6 +49,9 @@ class_name AnimatedShape2D
## and shapes only change per animation.
@export var use_previous_as_fallback := false

## If [code]true[/code], use call_deferred() to set CollisionShape2D properties.
@export var use_deferred_calls := true

## Flip horizontally the collision shapes when the animated sprite is flipped,
## by inverting the scale of their parent Area2D. Only works on collision
## shapes that are children of Area2D, to avoid weird behaviors with physics.
Expand Down Expand Up @@ -118,6 +122,8 @@ func _get_configuration_warnings() -> PackedStringArray:
func setup():
if self.collision_shape == null:
return
if self.shape_frames == null:
return

# We might update the original collision shape's shape, so we duplicate
if self.collision_shape.shape:
Expand All @@ -141,6 +147,8 @@ func get_current_shape_frame() -> ShapeFrame2D:


func update_shape():
if self.shape_frames == null:
return
var shape_frame := get_current_shape_frame()

var shape: Shape2D = null
Expand All @@ -161,8 +169,7 @@ func update_shape():

update_collision_shape_shape(shape)
update_collision_shape_position(position)
#self.collision_shape.disabled = disabled
self.collision_shape.set_deferred(&"disabled", disabled)
update_collision_shape_disabled(disabled)

if self.handle_flip_h and is_collision_shape_parent_flippable():
# Improvement idea: flip the CollisionBody2D itself and mirror its x pos
Expand All @@ -172,6 +179,13 @@ func update_shape():
self.collision_shape_parent.scale.x = self.initial_scale.x


func update_collision_shape_disabled(disabled: bool):
if self.use_deferred_calls:
self.collision_shape.set_deferred(&"disabled", disabled)
else:
self.collision_shape.disabled = disabled


func update_collision_shape_position(new_position: Vector2):
if new_position == self.collision_shape.position:
return
Expand Down Expand Up @@ -253,12 +267,18 @@ func update_collision_shape_shape(new_shape: Shape2D):

# If the update cannot be done, we want a duplicate of the shape
# because we might update it later on.
self.collision_shape.shape = new_shape.duplicate(true)
if use_deferred_calls:
self.collision_shape.set_deferred(&"shape", new_shape.duplicate(true))
else:
self.collision_shape.shape = new_shape.duplicate(true)
return

# Or perhaps just simply REPLACE the shape.
# This triggers (possibly unwanted) extra area_entered signals.
self.collision_shape.shape = new_shape
if use_deferred_calls:
self.collision_shape.set_deferred(&"shape", new_shape)
else:
self.collision_shape.shape = new_shape


# Make the shape properties go towards their target, but not by more than
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions addons/goutte.animated_shape_2d/editor/icons/link.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://chl5rhpr6ngqp"
path="res://.godot/imported/link.png-e080a774f28ccd8863f5e23555455903.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/goutte.animated_shape_2d/editor/icons/link.png"
dest_files=["res://.godot/imported/link.png-e080a774f28ccd8863f5e23555455903.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
37 changes: 37 additions & 0 deletions addons/goutte.animated_shape_2d/editor/linked_frames_feedback.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@tool
extends Node


@export var editor: ShapeFramesBottomPanelControl


func update_for(animation_name: StringName, frame_index: int):
assert(editor.currently_selected_animation_name == animation_name)
# 1. Grab the sprite frame resource of the selected frame
var frame_editor := editor.get_frame_at(frame_index)
var shape_frame := frame_editor.get_shape_frame()
# 2. Iterate over all frames to find linked frames
var linked_frames_editors: Array[ShapeFrameEditor]= []
for some_frame_editor in editor.frames_list:
if shape_frame == null:
continue
if some_frame_editor.get_shape_frame() != shape_frame:
continue
linked_frames_editors.append(some_frame_editor)
# 3. Hide the link marker everywhere
for some_frame_editor in editor.frames_list:
some_frame_editor.hide_link_marker()
# 4. Show the link marker where appropriate
if linked_frames_editors.size() > 1:
for linked_frame_editor in linked_frames_editors:
linked_frame_editor.show_link_marker()


func _on_shape_frames_bottom_panel_control_frame_selected(animation_name: StringName, frame_index: int):
update_for(animation_name, frame_index)


func _on_shape_frames_bottom_panel_control_frame_changed(animation_name, frame_index):
var selected_frame_editor := editor.get_selected_frame()
update_for(selected_frame_editor.animation_name, selected_frame_editor.frame_index)

102 changes: 69 additions & 33 deletions addons/goutte.animated_shape_2d/editor/shape_frame_editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var undo_redo: EditorUndoRedoManager

signal frame_selected
signal frame_deselected
signal changed


## Mandatory dependency injection, since it's best to leave _init() alone.
Expand Down Expand Up @@ -91,6 +92,7 @@ func set_shape_frame(value: ShapeFrame2D):
)
connect_to_shape_frame()
update()
emit_changed()


## Connect to the edited Resource, in order to update the GUI in real time.
Expand All @@ -116,6 +118,14 @@ func select():
%SpriteButton.button_pressed = true


func show_link_marker():
%LinkMarker.show()


func hide_link_marker():
%LinkMarker.hide()


## The crux of the matter ; update the scene according to the data.
func update():
if self.animated_shape == null:
Expand Down Expand Up @@ -231,6 +241,16 @@ func inspect_shape_frame():
EditorInterface.edit_resource(shape_frame)


## The UndoRedo does not like when we use different objects, so we wrap this method here.
#func set_shape_frame(animation_name: StringName, frame_index: int):
#self.animated_shape.shape_frames.set_(animation_name, frame_index)


## The UndoRedo does not like when we use different objects, so we wrap this method here.
func remove_shape_frame():
self.animated_shape.shape_frames.remove_shape_frame(self.animation_name, self.frame_index)


# _____ _
# | __ \ (_)
# | |__) | __ _____ ___ _____ __
Expand Down Expand Up @@ -406,14 +426,18 @@ func get_editor_node_from_path(path: Array) -> Node:
# |______|_|___/\__\___|_| |_|\___|_| |___/
#

## UndoRedo won't accept calling methods on signals, so we'll call this instead.
func emit_changed():
self.changed.emit()

func on_shape_frame_changed():
update()
emit_changed()


func _on_sprite_button_toggled(toggled_on: bool):
if toggled_on:
frame_selected.emit()
self.frame_selected.emit()
preview_shape_frame()
#inspect_shape_frame() # nope, the preview has priority somehow
#inspect_shape_frame.call_deferred() # nope too
Expand All @@ -423,7 +447,7 @@ func _on_sprite_button_toggled(toggled_on: bool):
inspect_shape_frame()
)
else:
frame_deselected.emit()
self.frame_deselected.emit()
remove_preview_of_shape_frame()


Expand All @@ -448,6 +472,7 @@ func _on_create_button_pressed():
update()
connect_to_shape_frame()
inspect_shape_frame()
emit_changed()


func _on_edit_button_pressed():
Expand Down Expand Up @@ -483,34 +508,40 @@ func _on_paste_button_pressed():
self, &"disconnect_from_shape_frame",
)
self.undo_redo.add_do_method(
self.animated_shape.shape_frames, &"set_shape_frame",
self.animation_name, self.frame_index, pasted_shape_frame,
)
self.undo_redo.add_do_method(
self, &"connect_to_shape_frame",
)
self.undo_redo.add_do_method(
self, &"update",
)
self.undo_redo.add_do_method(
self, &"inspect_shape_frame",
self, &"set_shape_frame",
pasted_shape_frame,
)
#self.undo_redo.add_do_method(
#self, &"connect_to_shape_frame",
#)
#self.undo_redo.add_do_method(
#self, &"update",
#)
#self.undo_redo.add_do_method(
#self, &"inspect_shape_frame",
#)
#self.undo_redo.add_do_method(
#self, &"emit_changed",
#)
self.undo_redo.add_undo_method(
self, &"disconnect_from_shape_frame",
)
self.undo_redo.add_undo_method(
self.animated_shape.shape_frames, &"set_shape_frame",
self.animation_name, self.frame_index, previous_shape_frame,
)
self.undo_redo.add_undo_method(
self, &"connect_to_shape_frame",
)
self.undo_redo.add_undo_method(
self, &"update",
)
self.undo_redo.add_undo_method(
self, &"inspect_shape_frame",
self, &"set_shape_frame",
previous_shape_frame,
)
#self.undo_redo.add_undo_method(
#self, &"connect_to_shape_frame",
#)
#self.undo_redo.add_undo_method(
#self, &"update",
#)
#self.undo_redo.add_undo_method(
#self, &"inspect_shape_frame",
#)
#self.undo_redo.add_undo_method(
#self, &"emit_changed",
#)
self.undo_redo.commit_action()
else:
# Same as above, without the UndoRedo shenanigans.
Expand All @@ -520,6 +551,7 @@ func _on_paste_button_pressed():
)
connect_to_shape_frame()
update()
emit_changed()


func _on_delete_button_pressed():
Expand All @@ -535,34 +567,38 @@ func _on_delete_button_pressed():
self, &"disconnect_from_shape_frame",
)
self.undo_redo.add_do_method(
self.animated_shape.shape_frames, &"remove_shape_frame",
self.animation_name, self.frame_index,
self, &"remove_shape_frame",
)
self.undo_redo.add_do_method(
self, &"update",
)
self.undo_redo.add_do_method(
self, &"inspect_shape_frame",
)
self.undo_redo.add_undo_method(
self.animated_shape.shape_frames, &"set_shape_frame",
self.animation_name, self.frame_index, shape_frame,
self.undo_redo.add_do_method(
self, &"emit_changed",
)
self.undo_redo.add_undo_method(
self, &"connect_to_shape_frame",
self, &"set_shape_frame",
shape_frame,
)
#self.undo_redo.add_undo_method(
#self, &"connect_to_shape_frame",
#)
self.undo_redo.add_undo_method(
self, &"update",
)
self.undo_redo.add_undo_method(
self, &"inspect_shape_frame",
)
self.undo_redo.add_undo_method(
self, &"emit_changed",
)
self.undo_redo.commit_action()
else:
# Same as above, but without the UndoRedo shenanigans
disconnect_from_shape_frame()
self.animated_shape.shape_frames.remove_shape_frame(
self.animation_name, self.frame_index,
)
remove_shape_frame()
update()
emit_changed()

Loading

0 comments on commit a7030ad

Please sign in to comment.