UI动画的技巧
- 悬停动画(缩放+旋转)
技巧:分离X/Y轴缩放时间,配合随机旋转方向,使用EASE_OUT + TRANS_BACK曲线。 关键代码:
func hover() -> void: if disabled: return pivot_offset = size / 2.0 var scale_ratio = clampf(width_full_rot / size.x, 0.5, 1.0) var scale_target = 1.0 + (0.2) * scale_ratio if tween and tween.is_running(): tween.kill() tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK) tween.tween_property(self, "scale:x", scale_target, 0.2) tween.parallel().tween_property(self, "scale:y", scale_target, 0.35) tween.parallel().tween_property(self, "rotation_degrees", 5.0 * scale_ratio * [-1.0, 1.0].pick_random(), 0.1) tween.parallel().tween_property(self, "rotation_degrees", 0.0, 0.1).set_delay(0.1) 2. 根据按钮大小调整动画强度
技巧:通过width_full_rot/size.x计算缩放比例,限制为0.5~1.0,防止长按钮旋转过度。 关键代码:
var scale_ratio = clampf(width_full_rot / size.x, 0.5, 1.0) var scale_target = 1.0 + (0.2) * scale_ratio 3. 容器内子元素错序入场动画
技巧:_ready中遍历子节点,设置modulate.a = 0(不改变visible),然后用并行tween加延迟实现错开。 关键代码:
func _ready() -> void: for c in target.get_children(): c.modulate.a = 0.0 # 动画触发 tween.set_parallel(true) var idx = 0 for c in children: tween.tween_property(c, "scale", Vector2.ONE, duration).from(Vector2.ZERO).set_delay(delay_between_elements * idx) tween.tween_property(c, "modulate:a", 1.0, 0.01).set_delay(delay_between_elements * idx) idx += 1 4. 自动补间脚本(基于可见性变化)
技巧:用_set函数捕获属性变化,自动触发补间动画,无需修改原有代码。 关键代码:
@tool extends Control @export var target_property: String = "property"
func _set(property: StringName, value: Variant) -> bool: if property == target_property: if get(property) == value: return false animate() return false return false
func animate() -> void: pivot_offset = size / 2.0 if tween and tween.is_running(): tween.kill() tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK) tween.tween_property(self, "scale:x", 1.2, 0.1) tween.parallel().tween_property(self, "scale:y", 1.2, 0.15) tween.parallel().tween_property(self, "rotation_degrees", 15.0 * [-1.0, 1.0].pick_random(), 0.1) tween.parallel().tween_property(self, "scale:x", 1.0, 0.2).set_delay(0.2) tween.parallel().tween_property(self, "scale:y", 1.0, 0.3).set_delay(0.25) tween.parallel().tween_property(self, "rotation_degrees", 0.0, 0.1).set_delay(0.15) 5. 显示/隐藏自动补间(容器脚本)
技巧:通过show()/hide()函数封装,支持缩放或淡入淡出,用set_parallel(true)和set_delay让子元素依次出现。 关键代码(显示):
func show() -> void: show_started.emit() tween = create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_CUBIC) if anim_type == ANIM_TYPE.SCALE: tween.tween_property(target, "scale", Vector2.ONE, duration).from(Vector2.ZERO) elif anim_type == ANIM_TYPE.FADE: tween.tween_property(target, "modulate:a", 1.0, duration).from(0.0) tween.tween_callback(show_finished.emit)
关键代码(隐藏):
func hide(should_free: bool = false) -> void: hide_started.emit() tween = create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_CUBIC) if anim_type == ANIM_TYPE.SCALE: tween.tween_property(target, "scale", Vector2.ZERO, duration) elif anim_type == ANIM_TYPE.FADE: tween.tween_property(target, "modulate:a", 0.0, duration) if should_free: tween.tween_callback(target.queue_free) 6. 数值变化时的弹跳动画(_set重写)
技巧:重写_set函数,当某个属性值改变时触发一次弹跳动画(缩放+旋转)。 关键代码:
func _set(property: StringName, value: Variant) -> bool: if property == target_property: if get(property) == value: return false animate() return false return false
func animate() -> void: pivot_offset = size / 2.0 if tween and tween.is_running(): tween.kill() tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK) tween.tween_property(self, "scale:x", 1.2, 0.1) tween.parallel().tween_property(self, "scale:y", 1.2, 0.15) tween.parallel().tween_property(self, "rotation_degrees", 15.0 * [-1.0, 1.0].pick_random(), 0.1) tween.parallel().tween_property(self, "scale:x", 1.0, 0.2).set_delay(0.2) tween.parallel().tween_property(self, "scale:y", 1.0, 0.3).set_delay(0.25) tween.parallel().tween_property(self, "rotation_degrees", 0.0, 0.15).set_delay(0.15)
这些技巧的核心思想是复用补间动画预设,通过tween设置并行效果、延迟和曲线(EASE_OUT + TRANS_BACK),并利用_set函数或单独的脚本实现对属性变化的自动响应。

