| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- class_name Block
- extends AnimatableBody2D
- ## One arc-shaped segment of a ring around the core.
- const GAP := 4.0 # px between neighbouring tiles, drawn only (collision has no gap)
- const CORNER := 4.0 # corner rounding radius in px
- const BREAK_SECONDS := 0.15 # fade-out time, after a short flash
- var indestructible := false
- var color := Params.COLOR_BLUE
- var _polygon := PackedVector2Array()
- ## 0 to 1: how far the tile is washed towards white while breaking.
- var _flash := 0.0:
- set(value):
- _flash = value
- queue_redraw()
- func _init(inner: float, outer: float, begin: float, end: float, is_indestructible: bool) -> void:
- sync_to_physics = false
- collision_layer = Params.LAYER_BLOCKS
- collision_mask = 0
- indestructible = is_indestructible
- var collision := CollisionPolygon2D.new()
- collision.polygon = _sector(inner, outer, begin + 1.0 / outer, end - 1.0 / outer, 0.0)
- add_child(collision)
- _polygon = _round_corners(_sector(inner + GAP / 2.0, outer - GAP / 2.0, begin, end, GAP / 2.0))
- if indestructible:
- color = Params.COLOR_ORANGE
- else:
- color = Color8(
- int(102 * (randf() / 5.0 + 0.5)),
- int(217 * (randf() / 5.0 + 0.5)),
- int(239 * (randf() / 5.0 + 0.5)))
- ## Flashes and fades out, then frees itself. Stops colliding right away.
- func destroy() -> void:
- collision_layer = 0
- var tween := create_tween()
- tween.tween_property(self, "_flash", 0.8, BREAK_SECONDS / 3.0)
- tween.tween_property(self, "modulate:a", 0.0, BREAK_SECONDS)
- tween.parallel().tween_property(self, "scale", Vector2.ONE * 1.04, BREAK_SECONDS)
- tween.tween_callback(queue_free)
- func _draw() -> void:
- var fill := color.lerp(Color.WHITE, _flash)
- draw_colored_polygon(_polygon, fill)
- # Polygons have no antialiasing of their own; a smooth outline softens the edge.
- var outline := _polygon.duplicate()
- outline.append(_polygon[0])
- draw_polyline(outline, fill, 1.0, true)
- ## Ring segment between two radii. [param gap] trims each side by that many pixels,
- ## so the space between neighbours has the same width at every radius.
- static func _sector(inner: float, outer: float, begin: float, end: float, gap: float) -> PackedVector2Array:
- var steps := maxi(2, int((end - begin) * sqrt(outer) / 1.5))
- var outer_arc := _arc(outer, begin + gap / outer, end - gap / outer, steps)
- return outer_arc + _arc(inner, end - gap / inner, begin + gap / inner, steps)
- ## Shrinks then regrows the polygon with round joins, which rounds its corners.
- static func _round_corners(polygon: PackedVector2Array) -> PackedVector2Array:
- var shrunk := Geometry2D.offset_polygon(polygon, -CORNER)
- if shrunk.is_empty():
- return polygon
- var rounded := Geometry2D.offset_polygon(shrunk[0], CORNER, Geometry2D.JOIN_ROUND)
- return polygon if rounded.is_empty() else rounded[0]
- static func _arc(radius: float, from: float, to: float, steps: int) -> PackedVector2Array:
- var points := PackedVector2Array()
- for i in steps + 1:
- var angle := lerpf(from, to, float(i) / steps)
- points.append(Vector2(sin(angle), cos(angle)) * radius)
- return points
|