Recurso Curve
Una Curve construida punto a punto y leída con sample(t). La gráfica se dibuja del mismo recurso que mueve el cuadrado, junto a otro movido solo por el tiempo.
El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.
Clases de Godot usadas
CurveLine2DPolygon2D
El código
scripts/main.gd
extends Node
const DURATION: float = 2.0
const GRAPH_ORIGIN: Vector2 = Vector2(150, 520)
const GRAPH_SIZE: Vector2 = Vector2(400, 300)
const TRACK_LEFT: float = 690.0
const TRACK_RIGHT: float = 1150.0
const TRACK_Y: float = 340.0
const LINEAR_Y: float = 470.0
const SAMPLES: int = 96
const POINTS: Array = [
{at = Vector2(0.0, 0.0), left = 0.0, right = 2.6},
{at = Vector2(0.32, 1.15), left = 0.9, right = -0.4},
{at = Vector2(0.58, 0.86), left = -0.2, right = 0.4},
{at = Vector2(0.8, 1.05), left = 0.3, right = -0.1},
{at = Vector2(1.0, 1.0), left = -0.2, right = 0.0},
]
var curve: Curve
var marker: Polygon2D
var playhead: Line2D
var box: Polygon2D
var linear_box: Polygon2D
var elapsed: float = 0.0
func _ready() -> void:
_add_background()
_add_label('a Curve built by code, read with sample(t)', Vector2(40, 40), Color('#999999'))
_add_label('driven by curve.sample(t)', Vector2(690, 262), Color('#f3d48d'))
_add_label('driven by t alone', Vector2(690, 392), Color('#4a5162'))
curve = Curve.new()
curve.min_value = -0.2
curve.max_value = 1.3
for point in POINTS:
curve.add_point(point.at, point.left, point.right)
_add_frame()
var plot: Line2D = Line2D.new()
plot.width = 4.0
plot.default_color = Color('#8da5f3')
for i in SAMPLES + 1:
var t: float = float(i) / SAMPLES
plot.add_point(_graph_point(t, curve.sample(t)))
add_child(plot)
playhead = Line2D.new()
playhead.width = 1.0
playhead.default_color = Color('#4a5162')
playhead.add_point(_graph_point(0.0, curve.min_value))
playhead.add_point(_graph_point(0.0, curve.max_value))
add_child(playhead)
marker = _make_circle(11.0, Color('#8eef97'))
add_child(marker)
_add_rail(TRACK_Y)
_add_rail(LINEAR_Y)
box = _make_square(58.0, Color('#f3d48d'))
add_child(box)
linear_box = _make_square(44.0, Color('#2a2f3d'))
add_child(linear_box)
print('the curve overshoots past 1, so the top square passes the rail end and comes back')
func _process(delta: float) -> void:
elapsed = fmod(elapsed + delta, DURATION)
var t: float = elapsed / DURATION
var value: float = curve.sample(t)
marker.position = _graph_point(t, value)
box.position = Vector2(lerpf(TRACK_LEFT, TRACK_RIGHT, value), TRACK_Y)
linear_box.position = Vector2(lerpf(TRACK_LEFT, TRACK_RIGHT, t), LINEAR_Y)
playhead.set_point_position(0, _graph_point(t, curve.min_value))
playhead.set_point_position(1, _graph_point(t, curve.max_value))
func _graph_point(t: float, value: float) -> Vector2:
var normalized: float = (value - curve.min_value) / (curve.max_value - curve.min_value)
return GRAPH_ORIGIN + Vector2(GRAPH_SIZE.x * t, -GRAPH_SIZE.y * normalized)
func _add_rail(at_y: float) -> void:
var rail: Line2D = Line2D.new()
rail.width = 3.0
rail.default_color = Color('#2a2f3d')
rail.add_point(Vector2(TRACK_LEFT, at_y))
rail.add_point(Vector2(TRACK_RIGHT, at_y))
add_child(rail)
func _add_frame() -> void:
var border: Line2D = Line2D.new()
border.width = 2.0
border.default_color = Color('#2a2f3d')
border.closed = true
border.add_point(GRAPH_ORIGIN + Vector2(0, -GRAPH_SIZE.y))
border.add_point(GRAPH_ORIGIN + Vector2(GRAPH_SIZE.x, -GRAPH_SIZE.y))
border.add_point(GRAPH_ORIGIN + Vector2(GRAPH_SIZE.x, 0))
border.add_point(GRAPH_ORIGIN)
add_child(border)
for value in [0.0, 1.0]:
var guide: Line2D = Line2D.new()
guide.width = 1.0
guide.default_color = Color('#333a4a')
guide.add_point(_graph_point(0.0, value))
guide.add_point(_graph_point(1.0, value))
add_child(guide)
_add_label('%.1f' % value, _graph_point(0.0, value) - Vector2(42, 14), Color('#4a5162'))
func _make_circle(radius: float, color: Color) -> Polygon2D:
var points: PackedVector2Array = PackedVector2Array()
for i in 24:
var angle: float = TAU * i / 24
points.append(Vector2(cos(angle), sin(angle)) * radius)
var circle: Polygon2D = Polygon2D.new()
circle.polygon = points
circle.color = color
return circle
func _make_square(size: float, color: Color) -> Polygon2D:
var square: Polygon2D = Polygon2D.new()
square.polygon = PackedVector2Array(
[
Vector2(-size, -size) * 0.5,
Vector2(size, -size) * 0.5,
Vector2(size, size) * 0.5,
Vector2(-size, size) * 0.5,
]
)
square.color = color
return square
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)
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)
add_child(label)