@tool extends Node2D @export var area_size := Vector2(500, 150): 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_node := $Node2D @onready var remote_sprite := %Sprite2D @onready var sign_mark := %Sign as Sign var velocity := 2.0 var interacted_x = -10000 func _draw() -> void: 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 = [Vector2(300, 0), Vector2(400, 20), Vector2(350, 40), Vector2(300, 60), Vector2(250, 80), Vector2(200, 100), Vector2(150, 120), Vector2(100, 140), Vector2(60, 150), Vector2(0, 150)] var current_position = Vector2.ZERO var weight := 0.0 func _ready() -> void: if Engine.is_editor_hint(): return # 手动配置运动点 # # init points # for i in range(5): # bezier_points.append(_rand_point()) sign_mark.enabled = visible sign_mark.interacted.connect(_on_interacted) visibility_changed.connect(_on_visibility_changed) interacted_x = ArchiveManager.archive.ground_archive().get_value( name, "interacted_x", interacted_x ) if interacted_x > -10000: remote_node.position = Vector2(interacted_x, area_size.y) remote_sprite.material = null func _on_visibility_changed() -> void: sign_mark.enabled = visible func _next_point() -> void: # remove the first point bezier_points.remove_at(0) # # add a new point # bezier_points.append(_rand_point()) func _on_interacted() -> void: if interacted_x == -10000: _set_current_x_as_interacted_x() var inspect_texture = preload("res://asset/art/scene/c01/s07_书店外/纸片_正面.png") SceneManager.get_inspector().pop_prop_inspection("", inspect_texture, true) func _set_current_x_as_interacted_x() -> void: interacted_x = remote_node.position.x remote_node.position.y = area_size.y remote_sprite.material = null ArchiveManager.archive.ground_archive().set_pair(name, "interacted_x", interacted_x) if GlobalConfig.DEBUG: print("interacted_x:", interacted_x) # 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() or not visible or interacted_x > -10000: return # 如果不到 4 个点,跳过 if bezier_points.size() < 4: return weight += velocity * delta if weight >= 1.0: weight = 0.0 _next_point() # 当不到 4 个点时,落到地上 if bezier_points.size() < 4: remote_node.position.y = area_size.y _set_current_x_as_interacted_x() return 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_node.position = p # bezier 插值获得角度 remote_sprite.rotation = lerp_angle(remote_sprite.rotation, p1.angle_to(p2), delta) remote_sprite.skew = -remote_sprite.rotation * 0.5