Line2D flickering position every frame

Godot Version

4.7.1 stable Windows 11

Question

I have this code for my loose laser projectiles, which are an Area2D carrying a CollisionShape2D and an Area2D:

@onready var hitbox : CollisionShape2D = $hitbox
@onready var line : Line2D = $Line2D

func activate() -> void:
	print("loose laser activating")
	can_be_grazed = true
	
	visible = true
	line.texture.current_frame = colour
	hitbox.shape.size = Vector2(length * 0.5, thickness * 0.2)
	hitbox.rotation = angle
	line.width = 0.3
	position_queue.clear()
	line.set_points([Vector2.ZERO, Vector2.ZERO])
	origin = global_position
	bullet_instance_id = Node.new()
	
	var growtween : Tween = create_tween()
	growtween.tween_property(line, "width", thickness, 0.2)
	growtween.play()
	hitbox.set("disabled", false)
	
	if not lifespan == null :
		await(get_tree().create_timer(lifespan, false).timeout)
		deactivate()

func deactivate() -> void:
	if not associated_enemy == null :
		associated_enemy.bullet_list.erase(self)
		BulletManager.play_bullet_despawn(global_position, colour)
	reparent(get_tree().get_first_node_in_group(type.to_upper()))
	global_position = Vector2(29999, 29999)
	speed = 0
	acceleration = 0
	target_speed = 0
	angle = 0
	damage = 0
	velocity = Vector2(0,0)
	hitbox.set("disabled", true)
	if not bullet_instance_id == null :
		bullet_instance_id.queue_free()
	bullet_instance_id = null
	set_process_mode(PROCESS_MODE_DISABLED)

And in my global bullet manager, I have this code in _process:

elif bullet.danmaku_category == 1 :
					bullet.speed = move_toward(bullet.speed, bullet.target_speed, bullet.acceleration)
					bullet.velocity = Vector2.from_angle(bullet.angle) * bullet.speed
					bullet.position += bullet.velocity * delta
					bullet.hitbox.position = lerp(Vector2(0,0), bullet.line.points[1], 0.5)
					if bullet.line.points[0].distance_to(bullet.line.points[1]) < bullet.length :
						bullet.line.set_points([0, Vector2.from_angle(bullet.angle + PI) * bullet.global_position.distance_to(bullet.origin)])
					else :
						bullet.line.set_points([0, Vector2.from_angle(bullet.angle + PI) * bullet.length])

In this system, line.points[0] is always (0,0) and the front of the Line2D, and line.points[1] is the back end of the Line2D. It’s supposed to start small, then the front of the line moves until the length of the line is the same as the length variable, and from then on the back of the line follows the front of the line maintaining the length.

This was working fine all the time previously, but after some time of development, it now only works some of the time. Some of these loose lasers will “flicker” position every frame, with the front of the line working as intended, but the back of the line switching between its intended position and sometimes a position off to the side, and sometimes the position where the loose laser originated from.

I tried some print debugging and found out that the if bullet.line.points[0].distance_to(bullet.line.points[1]) < bullet.length condition is not the cause of it, the problem still happens when it is not met.

What is causing this flickering? I don’t know where else to debug, there is nothing else in my project that is setting the points of the loose laser’s Line2D. Any help is appreciated.

Upon further testing, it seems that other Line2Ds are doing the same thing, flickering every frame. It’s not consistent, and there doesn’t seem to be a pattern for when they do and don’t flicker, but it also seems that the more the Line2Ds flicker, the more strange graphical glitches happen, such as sprites having completely different textures, and random magenta shapes.

It seems that clearing and recreating the line every frame was the problem. I replaced the code in the bullet manager with this:

elif bullet.danmaku_category == 1:
					bullet.speed = move_toward(bullet.speed, bullet.target_speed, bullet.acceleration)

					bullet.velocity = Vector2.from_angle(bullet.angle) * bullet.speed
					bullet.position += bullet.velocity * delta

					var travelled_distance : float = bullet.global_position.distance_to(bullet.origin)
					var current_length : float = min(travelled_distance, bullet.length)

					var endpoint : Vector2 = Vector2.from_angle(bullet.angle + PI) * current_length

					bullet.line.set_point_position(1, endpoint)

					bullet.hitbox.position = endpoint * 0.5

This has fixed it.