120 lines
3.0 KiB
GDScript3
120 lines
3.0 KiB
GDScript3
|
@tool
|
|||
|
extends Node2D
|
|||
|
|
|||
|
@export var velocity := 0.1
|
|||
|
@export var remote_node: Node2D:
|
|||
|
set(val):
|
|||
|
remote_node = val
|
|||
|
if is_node_ready():
|
|||
|
if remote_node:
|
|||
|
remote_transform.remote_path = remote_node.get_path()
|
|||
|
else:
|
|||
|
remote_transform.remote_path = ""
|
|||
|
|
|||
|
@export var area_size := Vector2(400, 50):
|
|||
|
set(val):
|
|||
|
area_size = val
|
|||
|
queue_redraw()
|
|||
|
@export var gizmo_outline_color := Color(0.5, 0.3, 0.4, 0.8):
|
|||
|
set(val):
|
|||
|
gizmo_outline_color = val
|
|||
|
queue_redraw()
|
|||
|
|
|||
|
@onready var remote_transform := $RemoteTransform2D as RemoteTransform2D
|
|||
|
|
|||
|
|
|||
|
func _draw() -> void:
|
|||
|
remote_transform.remote_path = remote_node.get_path()
|
|||
|
if Engine.is_editor_hint():
|
|||
|
# draw gizmo
|
|||
|
var area_rect = Rect2(Vector2.ZERO, area_size)
|
|||
|
# fill
|
|||
|
var fill_color = gizmo_outline_color
|
|||
|
fill_color.a = 0.4
|
|||
|
draw_rect(area_rect, fill_color)
|
|||
|
# outline
|
|||
|
draw_rect(area_rect, gizmo_outline_color, false, 1.0)
|
|||
|
|
|||
|
|
|||
|
# 最多保持 4 个点; 先生成两个在左侧,再生成两个在右侧,然后再回到左侧,以此循环,形成左右摇摆的闭合路径
|
|||
|
var bezier_points = []
|
|||
|
var current_position = Vector2.ZERO
|
|||
|
var weight := 0.0
|
|||
|
|
|||
|
|
|||
|
func _ready() -> void:
|
|||
|
# init points
|
|||
|
for i in range(4):
|
|||
|
bezier_points.append(_rand_point())
|
|||
|
|
|||
|
|
|||
|
func _new_point() -> void:
|
|||
|
# remove the first point
|
|||
|
bezier_points.remove_at(0)
|
|||
|
# add a new point
|
|||
|
bezier_points.append(_rand_point())
|
|||
|
|
|||
|
|
|||
|
var _generated_points = -1
|
|||
|
|
|||
|
|
|||
|
func _rand_point() -> Vector2:
|
|||
|
_generated_points += 1
|
|||
|
# upleft,mid,downright,upright,mid,downleft,...
|
|||
|
match _generated_points % 6:
|
|||
|
0:
|
|||
|
_generated_points = 0
|
|||
|
# upleft
|
|||
|
return Vector2(
|
|||
|
randf_range(0, area_size.x * 0.3), randf_range(area_size.y * 0.6, area_size.y)
|
|||
|
)
|
|||
|
1:
|
|||
|
# upleft to center
|
|||
|
return Vector2(
|
|||
|
randf_range(area_size.x * 0.4, area_size.x * 0.6),
|
|||
|
randf_range(area_size.y * 0.3, area_size.y * 0.7)
|
|||
|
)
|
|||
|
2:
|
|||
|
# center to downright
|
|||
|
return Vector2(
|
|||
|
randf_range(area_size.x * 0.7, area_size.x), randf_range(0, area_size.y * 0.4)
|
|||
|
)
|
|||
|
3:
|
|||
|
# downright to upright
|
|||
|
return Vector2(
|
|||
|
randf_range(area_size.x * 0.7, area_size.x),
|
|||
|
randf_range(area_size.y * 0.6, area_size.y)
|
|||
|
)
|
|||
|
4:
|
|||
|
# upright to center
|
|||
|
return Vector2(
|
|||
|
randf_range(area_size.x * 0.4, area_size.x * 0.6),
|
|||
|
randf_range(area_size.y * 0.3, area_size.y * 0.7)
|
|||
|
)
|
|||
|
_:
|
|||
|
# center to downleft
|
|||
|
return Vector2(randf_range(0, area_size.x * 0.3), randf_range(0, area_size.y * 0.4))
|
|||
|
|
|||
|
|
|||
|
# 从 bezier_points 中取出 4 个点,然后进行贝塞尔曲线插值
|
|||
|
# 设置到 remote_transform 的 position 与 rotation
|
|||
|
# 速度为 velocity,权重为 weight
|
|||
|
func _process(delta: float) -> void:
|
|||
|
if Engine.is_editor_hint():
|
|||
|
return
|
|||
|
weight += velocity * delta
|
|||
|
if weight >= 1.0:
|
|||
|
weight = 0.0
|
|||
|
_new_point()
|
|||
|
|
|||
|
var p0 = bezier_points[0]
|
|||
|
var p1 = bezier_points[1]
|
|||
|
var p2 = bezier_points[2]
|
|||
|
var p3 = bezier_points[3]
|
|||
|
|
|||
|
var p = p1.cubic_interpolate(p2, p0, p3, weight)
|
|||
|
# var p = p1.bezier_interpolate(p0, p3, p2, weight)
|
|||
|
remote_transform.position = p
|
|||
|
# bezier 插值获得角度
|
|||
|
remote_transform.rotation = lerp_angle(remote_transform.rotation, p1.angle_to(p2), delta)
|