尝试将Line2D循环检测器更新至4.0版本时,遇到了问题。

huangapple go评论121阅读模式
英文:

Attempt to update Line2D loop detector to 4.0, I am met with issues

问题

Quick explanation: 这个脚本之前由Theraot创建,他慷慨地为我创建了这个脚本几年前。今天我尝试更新和改进它!它大致工作,除了我遇到的一些奇怪问题。

问题1:我最初在脚本中遇到的问题是每个部分的长度不相等,这是由于鼠标速度导致的,玩家可以快速移动鼠标,这会创建巨大的部分。我尝试通过首先计算需要多少个部分来修复这个问题,并尝试为新部分创建一个插值点,但它不起作用,就像它在滞后。

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

# 检查当前距离是否大于部分距离
if distance > Segment_Distance:
    var distanceDifference = distance - Segment_Distance
    var segmentsToAdd = int(distanceDifference / Segment_Distance)
    # 当鼠标远离倒数第二个点时,想要添加部分
    # 但我不确定该怎么做,我尝试使用插值点
    # 但它会出现故障

    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:
    # 如果距离不大于部分距离,我们只需更新点的最后位置为鼠标位置
    Points[-1] = Mouse_Position
    Update_Segment(Points[-2], Mouse_Position)

问题2:当创建一个循环并创建一个新的初始点时,会有多余的部分,而且新的初始点似乎要么丢失要么完全不绘制,不确定。process_loop函数超出了我的理解范围,所以我不太明白它。

问题3:有时候创建一个循环时,一个部分点会到达0,0,我不知道为什么,这偶尔会发生。

完整脚本可以复制并粘贴到任何场景中,只要它附加到Node2D上。

英文:

Quick explanation: This script was previously made by Theraot who graciously created this script for me a few years a go, Today I attempted to update it and improve it! it work-ish apart from these weird issues I am met with.

Issue 1: A issue I had originally with the script was that each segment was not equal length this was because of the mouse speed, the player could move the mouse very fast and it would create huge segments, I have attempted to fix this issue by first calculating how many segments are needed, and I have tried creating a interpolated point for the new segment but it does not work it glitches out like its lagging behind.

	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)

Issue 2: When a loop is created and a new initial point is created there is left over segments and also the new initial point also seems to either missing or completely not drawing it, not sure, The process_loop function is over my head so I dont really understand it.

尝试将Line2D循环检测器更新至4.0版本时,遇到了问题。

Issue 3: Sometimes when a loop is created one segment point? goes to 0,0 and I dont know why, this happens occasionally.
尝试将Line2D循环检测器更新至4.0版本时,遇到了问题。

Full script can be copy and pasted into any scene as long as its attached to a 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()

答案1

得分: 0

我找到的解决方案如下。

问题1(解决方法):

在快速移动时,线段的长度会变得不同,主要问题是进程和物理进程更新得不够快,以至于无法检测到已经移动超过某个距离,从而创建不等长的线段,解决方法是禁用垂直同步(Vsync),禁用垂直同步会使整个程序运行得非常快,缺点是无法使用垂直同步,我还尝试添加插值线段,但它们存在错误且无法正常工作。

问题2:

在创建循环时,一些线段仍然会显示,并且一些线段的点会出错并变为0,0。解决方法是使用一个复制数组,从3.0版本到4.0版本,将数组分配给变量不会创建副本,而是引用它,解决方法是使用array.duplicate。这可以解决这些问题。

帮助:

如果有人能帮助我弄清楚为什么我尝试修复问题1时添加插值线段没有起作用,请启用垂直同步以查看问题并快速移动鼠标,否则禁用它以使其运行更流畅。

代码:

extends Node2D

var MouseMotion : Vector2 = Vector2.ZERO
var Looper : Line2D # The line renderer
var LinePoints : PackedVector2Array = PackedVector2Array()
var LineWidth : int = 10 # Line thickness also used for collision
var SegmentNode: Node2D # Holds segments that make a loop
var LoopNode : Node2D # Holds the loop when a detection is made
@export var MaxPoints : int = 45 # How many points that should only render.
@export var MinDistance : int = 30 # Segment length.

func _ready() -> void:
    Looper = Line2D.new()
    Looper.name = "Line2D"
    add_child(Looper)
    
    SegmentNode = Node2D.new()
    SegmentNode.name = "SegmentNode"
    add_child(SegmentNode)
    
    LoopNode = Node2D.new()
    LoopNode.name = "LoopNode"
    add_child(LoopNode)

func _input(event):
    if event is InputEventMouseMotion:
        MouseMotion = event.position

func _process(delta: float) -> void:
    if Input.is_action_pressed("LeftClick"):
        ProcessLine(MouseMotion)
    elif Input.is_action_just_released("LeftClick"):
        ClearPoints(LinePoints.size())

func ProcessLine(MousePosition : Vector2) -> void:
    # 省略部分代码以节省空间

func ClearPoints(Index : int):
    # 省略部分代码以节省空间

func CreateSegment(start: Vector2, end: Vector2) -> void:
    # 省略部分代码以节省空间

func UpdateSegment(start: Vector2, end: Vector2) -> void:
    # 省略部分代码以节省空间

static func rotated_rectangle_points(start: Vector2, end: Vector2, width: float) -> Array:
    # 省略部分代码以节省空间

static func create_collision_polygon(points: Array) -> CollisionPolygon2D:
    # 省略部分代码以节省空间

func ProcessLoop() -> void:
    # 省略部分代码以节省空间

func CreateLoop(FirstIndex:int, SecondIndex:int) -> void:
    # 省略部分代码以节省空间

func ClearLoop() -> void:
    # 省略部分代码以节省空间

这是你提供的代码的翻译部分。如果需要更多帮助或有其他问题,请随时提出。

英文:

The solution I have found are these.

Issue 1 (Work-around):

When moving fast the segments become difference lengths, the main issue was that the process and physics process dont update quick enough for it to detect that its past a distance intern creating unequal segments, solution disable Vsync, disabling Vsync makes the whole program run super fast, disadvantage cant use Vsync, I also attempted on adding interpolated segments but they are buggy and dont work.

Issue 2:

When creating a loop some of the segments would still show and also some segment points would error out and go to 0,0. Solution was to make it use a duplicate array, it seems from 3.0 to 4.0 assigning an array to a variable does not create a duplicate instead it references it, solution array.duplicate. this fixes these issues.

Help:

I would love it if someone can help me figure out why my attempt at fixing issue 1 did not work with adding interpolated segments, please enable Vsync to see issue and move the mouse fast, else disable it to make it work better.

Code:

extends Node2D
var MouseMotion : Vector2 = Vector2.ZERO
var Looper : Line2D # The line renderer
var LinePoints : PackedVector2Array = PackedVector2Array()
var LineWidth : int = 10 # Line thickness also used for collision
var SegmentNode: Node2D # Holds segments that make a loop
var LoopNode : Node2D # Holds the loop when a detection is made
@export var MaxPoints : int = 45 # How many points that should only render.
@export var MinDistance : int = 30 # Segment length.
func _ready() -> void:
Looper = Line2D.new()
Looper.name = "Line2D"
add_child(Looper)
SegmentNode = Node2D.new()
SegmentNode.name = "SegmentNode"
add_child(SegmentNode)
LoopNode = Node2D.new()
LoopNode.name = "LoopNode"
add_child(LoopNode)
func _input(event):
if event is InputEventMouseMotion:
MouseMotion = event.position
func _process(delta: float) -> void:
if Input.is_action_pressed("LeftClick"):
ProcessLine(MouseMotion)
elif Input.is_action_just_released("LeftClick"):
ClearPoints(LinePoints.size())
func ProcessLine(MousePosition : Vector2) -> void:
if LinePoints.size() == 0:
LinePoints.append(MousePosition)
LinePoints.append(MousePosition)
CreateSegment(MousePosition,MousePosition)
elif LinePoints.size() == 1:
LinePoints.append(MousePosition)
CreateSegment(LinePoints[-2],MousePosition)
elif LinePoints.size() > MaxPoints:
ClearPoints(LinePoints.size() - MaxPoints)
else:
var Distance = LinePoints[-2].distance_to(MousePosition)
var distanceDifference = Distance - MinDistance
var NumSegments = int(distanceDifference / MinDistance)
for i in range(NumSegments):
var newPoint = LinePoints[-2] + (MousePosition - LinePoints[-2]).normalized() * MinDistance
LinePoints.append(newPoint)
CreateSegment(LinePoints[-2], newPoint)
LinePoints[-1] = MousePosition
UpdateSegment(LinePoints[-2], MousePosition)
Looper.points = LinePoints
ProcessLoop()
func ClearPoints(Index : int):
for _clear in range(Index):
if LinePoints.size() > 0:
LinePoints.remove_at(0)
var segments = SegmentNode.get_children()
for i in range(Index):
if segments.size() > 0:
SegmentNode.remove_child(segments[0])
segments[0].queue_free()
segments.remove_at(0)
Looper.points = LinePoints
ProcessLoop()
func CreateSegment(start: Vector2, end: Vector2) -> void:
var points = rotated_rectangle_points(start, end, LineWidth)
var segment = Area2D.new()
segment.add_to_group("BattlePlayer")
var collision = create_collision_polygon(points)
segment.add_child(collision)
SegmentNode.add_child(segment)
func UpdateSegment(start: Vector2, end: Vector2) -> void:
var points = rotated_rectangle_points(start, end, LineWidth)
var segment = SegmentNode.get_child(SegmentNode.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 ProcessLoop() -> void:
var segments = SegmentNode.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:
CreateLoop(candidate_index,index)
ClearPoints(LinePoints.size())
return
func CreateLoop(FirstIndex:int, SecondIndex:int) -> void:
ClearLoop()
var Loop = Area2D.new()
var Points = LinePoints.duplicate()
Points.resize(SecondIndex)
for PointIndex in FirstIndex + 1:
Points.remove_at(0)
var Collision = create_collision_polygon(Points)
Loop.add_child(Collision)
LoopNode.add_child(Loop)
func ClearLoop() -> void:
for Loop in LoopNode.get_children():
if is_instance_valid(Loop):
Loop.queue_free()

huangapple
  • 本文由 发表于 2023年7月13日 00:33:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76672740.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定