extends Node2D @export var broadth = 250 @export var move_dir = -1 @export var angular_speed = 0.25 @export var hp = 400 var angle = 0.0 if move_dir == 1 else PI @onready var segments : Array[Node] = $Segments.get_children() @onready var segment_count = segments.size() var paused = false var pause_time = 0.1 var iframes = 0.2 var iframe_time = 0 var check_grounded_delay = 8 func _ready() -> void: for segment in segments: segment.segment_damaged.connect(hurt) func _physics_process(delta: float) -> void: iframe_time = max(0, iframe_time - delta) if not paused: angle -= TAU * delta * angular_speed * move_dir if(angle > PI or angle < 0): paused = true await get_tree().create_timer(pause_time).timeout paused = false angle = fmod(angle + PI, PI) var y = position.length() var ratio = - move_dir * broadth / (2 * y) var rot_angle = - 2 * asin(ratio) position = position.rotated(rot_angle) if(move_dir == 1 and angle < 1 or move_dir == -1 and angle > PI - 1): var y = position.length() var ratio = - move_dir * broadth / (2 * y) var rot_angle = - 2 * asin(ratio) $RayCast2D.global_position = position.rotated(rot_angle) $RayCast2D.rotation = rot_angle if(move_dir == 1 and angle < 0.5 or move_dir == -1 and angle > PI - 0.5): if(not $RayCast2D.has_overlapping_bodies()): paused = true await get_tree().create_timer(pause_time).timeout paused = false move_dir *= -1 for i in range(segment_count): var segment_pos_data = calculate_segment_location_and_rotation(i) segments[i].position = segment_pos_data.position segments[i].rotation = segment_pos_data.rotation if check_grounded_delay > 0: check_grounded_delay -= delta elif not $RayCast2D2.has_overlapping_bodies(): queue_free() func calculate_segment_location_and_rotation (i) -> Dictionary: var aerial_end_location = Vector2.from_angle(-angle) * broadth var gravicenter = (aerial_end_location + Vector2(0, -broadth) + Vector2.ZERO) / 3 var ax = gravicenter.x var ay = gravicenter.y var bx = aerial_end_location.x var by = aerial_end_location.y var cx = 0 var cy = 0 var d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) var ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d var uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d var center = Vector2(ux, uy) var radius = center.length() var switch_arc_dir = false if ux < 0: switch_arc_dir = !switch_arc_dir if center.angle() > 1: switch_arc_dir = !switch_arc_dir var angle1 = - PI + center.angle() var angle2 = - PI + (center-aerial_end_location).angle() if(switch_arc_dir): angle1 += TAU if radius < 10000000: return {"position": center + radius * Vector2.from_angle((i * angle1 + (segment_count - 1 - i) * angle2)/(segment_count - 1)) , "rotation": (i * angle1 + (segment_count - 1 - i) * angle2)/ (segment_count - 1) + PI/2} else: return {"position" : Vector2.UP * broadth * i / (segment_count - 1), "rotation" : 3 * PI / 2} func hurt(damage : int, _dir): if iframe_time <= 0: hp -= damage $AudioStreamPlayer2D.play() if(hp<=0): for child in get_children(): if not child is AudioStreamPlayer2D: child.queue_free() await $AudioStreamPlayer2D.finished queue_free() else: iframe_time = iframes