阻尼弹簧
临界阻尼弹簧和 lerp 跟随器追踪同一个移动目标。弹簧跟得上,lerp 总是落后。
上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。
用到的 Godot 类
Polygon2DLine2DLabel
代码
scripts/main.gd
extends Node
const STIFFNESS: float = 160.0
const LERP_WEIGHT: float = 1.6
const TARGET_SPEED: float = 1.6
const TRACE_POINTS: int = 150
const TRACE_STEP: float = 3.0
const SIZE: Vector2 = Vector2(34, 34)
var damping: float = 2.0 * sqrt(STIFFNESS)
var target_marker: Polygon2D
var spring_marker: Polygon2D
var lerp_marker: Polygon2D
var target_trace: Line2D
var spring_trace: Line2D
var lerp_trace: Line2D
var guide: Line2D
var row_target: float = 0.0
var row_spring: float = 0.0
var row_lerp: float = 0.0
var spring_x: float = 0.0
var spring_velocity: float = 0.0
var lerp_x: float = 0.0
var center_x: float = 0.0
var amplitude: float = 0.0
var elapsed: float = 0.0
func _ready() -> void:
_add_background()
var view: Vector2 = get_viewport().get_visible_rect().size
center_x = view.x * 0.5
amplitude = view.x * 0.29
spring_x = center_x
lerp_x = center_x
row_target = view.y * 0.17
row_spring = row_target + 44.0
row_lerp = row_spring + 44.0
guide = Line2D.new()
guide.width = 2.0
guide.default_color = Color('#2a2f3d')
guide.points = PackedVector2Array([Vector2(0, row_target - 40), Vector2(0, view.y - 40)])
guide.position.x = center_x
add_child(guide)
target_trace = _add_trace(Color('#f3d48d'))
spring_trace = _add_trace(Color('#8da5f3'))
lerp_trace = _add_trace(Color('#8eef97'))
target_marker = _add_marker(Color('#f3d48d'), row_target)
spring_marker = _add_marker(Color('#8da5f3'), row_spring)
lerp_marker = _add_marker(Color('#8eef97'), row_lerp)
_add_label('target', Vector2(40, row_target - 12), Color('#f3d48d'))
_add_label('spring, critically damped', Vector2(40, row_spring - 12), Color('#8da5f3'))
_add_label('lerp toward the target', Vector2(40, row_lerp - 12), Color('#8eef97'))
_add_label('the same target, followed two ways, each trail is the last seconds of travel', Vector2(40, 40), Color('#999999'))
func _process(delta: float) -> void:
elapsed += delta
var target_x: float = center_x + sin(elapsed * TARGET_SPEED) * amplitude
spring_velocity += ((target_x - spring_x) * STIFFNESS - spring_velocity * damping) * delta
spring_x += spring_velocity * delta
lerp_x = lerp(lerp_x, target_x, LERP_WEIGHT * delta)
target_marker.position.x = target_x
spring_marker.position.x = spring_x
lerp_marker.position.x = lerp_x
guide.position.x = target_x
_push(target_trace, target_x, row_target)
_push(spring_trace, spring_x, row_spring)
_push(lerp_trace, lerp_x, row_lerp)
func _push(trace: Line2D, value: float, top: float) -> void:
var points: PackedVector2Array = trace.points
points.insert(0, Vector2(value, top))
if points.size() > TRACE_POINTS:
points.resize(TRACE_POINTS)
for i in points.size():
points[i] = Vector2(points[i].x, top + i * TRACE_STEP)
trace.points = points
func _add_trace(color: Color) -> Line2D:
var trace: Line2D = Line2D.new()
trace.width = 3.0
trace.default_color = Color(color, 0.55)
add_child(trace)
return trace
func _add_marker(color: Color, row: float) -> Polygon2D:
var marker: Polygon2D = _make_rect(SIZE, color)
marker.position = Vector2(center_x, row)
add_child(marker)
return marker
func _add_label(text: String, at: Vector2, color: Color) -> void:
var label: Label = Label.new()
label.text = text
label.position = at
label.add_theme_color_override('font_color', color)
label.add_theme_font_size_override('font_size', 20)
add_child(label)
func _make_rect(size: Vector2, color: Color) -> Polygon2D:
var rect: Polygon2D = Polygon2D.new()
rect.polygon = PackedVector2Array([-size * 0.5, Vector2(size.x, -size.y) * 0.5, size * 0.5, Vector2(-size.x, size.y) * 0.5])
rect.color = color
return rect
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)