Skip to content

Commit 17846a0

Browse files
committed
feat: improve the responsiveness of the shape change
There was a "lag" in the shape update because we did not hook the animation_changed signal. Now we do, and it's waaay smoother. We also added an "update" mode that does not replace the whole shape, but only updates its properties, and therefore does not trigger extra "entered" signals. Fixes #5 /spend 2h30
1 parent b2866b2 commit 17846a0

File tree

1 file changed

+80
-9
lines changed

1 file changed

+80
-9
lines changed

Diff for: addons/goutte.animated_shape_2d/animated_shape_2d.gd

+80-9
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@
33
extends Node
44
class_name AnimatedShape2D
55

6-
# _ _ _ _____ _
7-
# /\ (_) | | | |/ ____| |
8-
# / \ _ __ _ _ __ ___ __ _| |_ ___ __| | (___ | |__ __ _ _ __ ___
9-
# / /\ \ | '_ \| | '_ ` _ \ / _` | __/ _ \/ _` |\___ \| '_ \ / _` | '_ \ / _ \
10-
# / ____ \| | | | | | | | | | (_| | || __/ (_| |____) | | | | (_| | |_) | __/
11-
# /_/ \_\_| |_|_|_| |_| |_|\__,_|\__\___|\__,_|_____/|_| |_|\__,_| .__/ \___|
12-
# | |
13-
# v0.1.3-20231231 |_|
146
## Animates a CollisionShape2D for each frame of an AnimatedSprite2D.
157
## You can put this pretty much anywhere you want in your scene.
168

@@ -49,6 +41,19 @@ class_name AnimatedShape2D
4941
@export var handle_flip_h := true
5042

5143

44+
enum SHAPE_UPDATE_MODE {
45+
## Update the existing shape resource properties in the CollisionShape2D,
46+
## but only if shape types are compatible.
47+
UPDATE,
48+
## Always replace the existing shape resource in the CollisionShape2D.
49+
## This may trigger additional [code]entered[/code] signals.
50+
REPLACE,
51+
}
52+
53+
## How the Shape2D resource is updated between frames.
54+
@export var update_shape_mode := SHAPE_UPDATE_MODE.UPDATE
55+
56+
5257
var fallback_shape: Shape2D
5358
var fallback_position: Vector2
5459
var fallback_disabled: bool
@@ -76,12 +81,16 @@ func setup():
7681
if self.collision_shape == null:
7782
return
7883
self.fallback_shape = self.collision_shape.shape
84+
if self.update_shape_mode == SHAPE_UPDATE_MODE.UPDATE:
85+
# We're going to update the original collision shape's shape, so we copy
86+
self.fallback_shape = self.collision_shape.shape.duplicate(true)
7987
self.fallback_position = self.collision_shape.position
8088
self.fallback_disabled = self.collision_shape.disabled
8189
self.collision_shape_parent = self.collision_shape.get_parent()
8290
if self.collision_shape_parent != null:
8391
self.initial_scale = self.collision_shape_parent.scale
8492

93+
self.animated_sprite.animation_changed.connect(update_shape)
8594
self.animated_sprite.frame_changed.connect(update_shape)
8695

8796

@@ -106,7 +115,7 @@ func update_shape():
106115
position = self.fallback_position
107116
disabled = self.fallback_disabled
108117

109-
self.collision_shape.shape = shape
118+
update_collision_shape_shape(shape)
110119
self.collision_shape.position = position
111120
self.collision_shape.disabled = disabled
112121
if self.handle_flip_h and is_collision_shape_parent_flippable():
@@ -117,6 +126,68 @@ func update_shape():
117126
self.collision_shape_parent.scale.x = self.initial_scale.x
118127

119128

129+
func update_collision_shape_shape(new_shape: Shape2D):
130+
if new_shape == self.collision_shape.shape:
131+
return
132+
133+
if (
134+
self.update_shape_mode == SHAPE_UPDATE_MODE.UPDATE
135+
and
136+
self.collision_shape.shape != null
137+
and
138+
new_shape != null
139+
):
140+
if (
141+
(self.collision_shape.shape is RectangleShape2D)
142+
and
143+
(new_shape is RectangleShape2D)
144+
):
145+
self.collision_shape.shape.size = new_shape.size
146+
return
147+
148+
if (
149+
(self.collision_shape.shape is CircleShape2D)
150+
and
151+
(new_shape is CircleShape2D)
152+
):
153+
self.collision_shape.shape.radius = new_shape.radius
154+
return
155+
156+
if (
157+
(self.collision_shape.shape is CapsuleShape2D)
158+
and
159+
(new_shape is CapsuleShape2D)
160+
):
161+
self.collision_shape.shape.height = new_shape.height
162+
self.collision_shape.shape.radius = new_shape.radius
163+
return
164+
165+
if (
166+
(self.collision_shape.shape is SegmentShape2D)
167+
and
168+
(new_shape is SegmentShape2D)
169+
):
170+
self.collision_shape.shape.a = new_shape.a
171+
self.collision_shape.shape.b = new_shape.b
172+
return
173+
174+
if (
175+
(self.collision_shape.shape is WorldBoundaryShape2D)
176+
and
177+
(new_shape is WorldBoundaryShape2D)
178+
):
179+
self.collision_shape.shape.distance = new_shape.distance
180+
self.collision_shape.shape.normal = new_shape.normal
181+
return
182+
183+
# If the update cannot be done, we want to duplicate the shape
184+
# because we might update it later on.
185+
self.collision_shape.shape = new_shape.duplicate(true)
186+
return
187+
188+
self.collision_shape.shape = new_shape
189+
190+
120191
## We don't want to flip PhysicsBodies because it creates odd behaviors.
121192
## Override this method if that's what you want for some reason.
122193
func is_collision_shape_parent_flippable() -> bool:

0 commit comments

Comments
 (0)