You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Line2D循环检测器至4.0版本遇三类问题求助

背景说明

此脚本由Theraot于数年前开发,近期尝试升级优化后虽能勉强运行,但存在三类异常问题:

问题1:线段长度修复后出现卡顿

原脚本存在鼠标移动过快生成超长线段的问题,我通过计算所需线段数量、创建插值点修复后,出现卡顿滞后异常。相关代码如下:

var distance = Points[-2].distance_to(Mouse_Position)

# Check if the current distance is greater then segment distance
if distance > Segment_Distance:
    var distanceDifference = distance - Segment_Distance
    var segmentsToAdd = int(distanceDifference / Segment_Distance)
    # Want to add segments for when the mouse is far away from the second to last point
    # but I am not sure what to do, I attempted using a interpolated point
    # but it glitches out
    
    for i in range(segmentsToAdd):
        var newPoint = Points[-2] + (Mouse_Position - Points[-2]).normalized() * Segment_Distance
        Points.append(newPoint)
        Create_Segment(Points[-2], newPoint)

    Points[-1] = Mouse_Position
    Update_Segment(Points[-2], Mouse_Position)
else:
    # if the distance is not greater then we simply update the last position of the point to mouse
    Points[-1] = Mouse_Position
    Update_Segment(Points[-2], Mouse_Position)

问题2:循环创建后残留线段且初始点异常

创建循环并生成新初始点时,会残留多余线段,且新初始点可能缺失或未绘制。对Process_Loop函数逻辑理解不足,无法排查问题。
循环残留线段与初始点异常

问题3:循环创建时偶发点跳至(0,0)

创建循环时,偶尔会出现某线段点跳至(0,0)的情况,原因不明。
线段点跳至(0,0)异常

完整脚本

以下完整脚本可直接粘贴到任意Node2D节点上运行:

extends  Node2D


# Variables
var Line : Line2D # Holds the line created
var Line_Width : int = 10 # We use this for collision thickness
var Segment_Distance : int = 50 # The Distance of each segment also how we create a new one
var Segments : Node2D # Creates a segment when enough distance is made also holds area2Ds
var Loop : Node2D # Holds the first created loop until a new loop is created
var Points : PackedVector2Array = PackedVector2Array() # Holds all the points for the line2D
var Max_Points : int = 50 # To stop having multiple points on the screen 


func _ready() -> void:
    # Create Nodes to hold each part of the line loop detection
    Line = Line2D.new()
    Line.name = "Line"
    Line.width = Line_Width
    add_child(Line)
    
    Segments = Node2D.new()
    Segments.name = "Segments"
    add_child(Segments)
    
    Loop = Node2D.new()
    Loop.name = "Loop"
    add_child(Loop)

func _process(delta: float) -> void:
    if Input.is_action_pressed("Left_Click"):
        Process_Line(get_global_mouse_position())
    if Input.is_action_just_released("Left_Click"):
        Clear_All()

func Process_Line(Mouse_Position: Vector2) -> void:
    # Get the size of points
    var Point_Count = Points.size()
    if Point_Count == 0: # Checks if its 0, we add 2 points for the start and current position
        Points.append(Mouse_Position)
        Points.append(Mouse_Position)
        Create_Segment(Mouse_Position, Mouse_Position) # Create a segment to connect area2D
    elif Point_Count == 1:
        Points.append(Mouse_Position)
        Create_Segment(Points[-2], Mouse_Position)
    elif Point_Count > Max_Points:
        Clear(Point_Count - Max_Points)
    else:
        var distance = Points[-2].distance_to(Mouse_Position)
        
        # Check if the current distance is greater then segment distance
        if distance > Segment_Distance:
            var distanceDifference = distance - Segment_Distance
            var segmentsToAdd = int(distanceDifference / Segment_Distance)
            # Want to add segments for when the mouse is far away from the second to last point
            # but I am not sure what to do, I attempted using a interpolated point
            # but it glitches out
            
            for i in range(segmentsToAdd):
                var newPoint = Points[-2] + (Mouse_Position - Points[-2]).normalized() * Segment_Distance
                Points.append(newPoint)
                Create_Segment(Points[-2], newPoint)

            Points[-1] = Mouse_Position
            Update_Segment(Points[-2], Mouse_Position)
        else:
            # if the distance is not greater then we simply update the last position of the point to mouse
            Points[-1] = Mouse_Position
            Update_Segment(Points[-2], Mouse_Position)
    # Apply the points array to the line2D points
    Line.points = Points
    # What does the loop detection currently buggy.
    Process_Loop()

func Create_Segment(start: Vector2, end: Vector2) -> void:
    # Get the rotation of the points
    var points = rotated_rectangle_points(start, end, Line_Width)
    var segment = Area2D.new()
    segment.add_to_group("Player_Looper") # Add segment to a group to detect stuff
    var collision = create_collision_polygon(points)
    segment.add_child(collision)
    Segments.add_child(segment)
    
func Update_Segment(start: Vector2, end: Vector2) -> void:
    var points = rotated_rectangle_points(start, end, Line_Width)
    var segment = Segments.get_child(Segments.get_child_count() - 1) as Area2D
    var collision = segment.get_child(0) as CollisionPolygon2D
    collision.set_polygon(points)

static func rotated_rectangle_points(start: Vector2, end: Vector2, width: float) -> Array:
    var diff = end - start
    var normal = diff.rotated(TAU / 4).normalized()
    var offset = normal * width * 0.5
    return [start + offset, start - offset, end - offset, end + offset]

static func create_collision_polygon(points: Array) -> CollisionPolygon2D:
    var result = CollisionPolygon2D.new()
    result.set_polygon(points)
    return result

func Process_Loop() -> void:
    var segments = Segments.get_children()
    for index in range(segments.size() - 1, 0, -1):
        var segment = segments[index]
        var candidates = segment.get_overlapping_areas()
        for candidate in candidates:
            var candidate_index = segments.find(candidate)
            if candidate_index == -1:
                continue

            if abs(candidate_index - index) > 1:
                push_loop(candidate_index, index)
                Clear(index)
                return

func push_loop(first_index:int, second_index:int) -> void:
    Clear_Loop()
    var loop = Area2D.new()
    var points = Points
    points.resize(second_index)
    for point_index in first_index + 1:
        points.remove_at(0)

    var collision = create_collision_polygon(points)
    loop.add_child(collision)
    Loop.add_child(loop)

func Clear_All() -> void:
    # Clears the points and segments and also clear loops
    Clear(Points.size())
    Clear_Loop()

func Clear(index) -> void:
    # Loop through the points array and remove each one based on index
    for _clear in range(index):
        if Points.size() > 0:
            Points.remove_at(0)
    
    # Get the current segments and also remove each segment
    var segments = Segments.get_children()
    for i in range(index):
        if segments.size() > 0:
            Segments.remove_child(segments[0])
            segments[0].queue_free()
            segments.remove_at(0)

    Line.points = Points

func Clear_Loop() -> void:
    for loop in Loop.get_children():
        if is_instance_valid(loop):
            loop.queue_free()

内容的提问来源于stack exchange,提问作者Dragon20C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 10:49:58