144 lines
4.7 KiB
GDScript
144 lines
4.7 KiB
GDScript
extends Node2D
|
|
|
|
@export var line_width: float = 25.0
|
|
@export var allowed_distance: float = 60.0
|
|
@export var selected_shape: String = "rombo"
|
|
@export var shape_scale: float = 1.0
|
|
@export var margin_ratio: float = 0.1
|
|
|
|
var shape_points: PackedVector2Array
|
|
var current_progress := 0
|
|
var fail_count := 0
|
|
var tracking := false
|
|
var shape_presets := {}
|
|
|
|
func _ready():
|
|
get_viewport().connect("size_changed", Callable(self, "_on_viewport_resized"))
|
|
_create_shape_presets()
|
|
_draw_selected_shape()
|
|
|
|
func _draw_selected_shape():
|
|
var screen_size = get_viewport().get_visible_rect().size
|
|
var center = screen_size / 2.0
|
|
var min_dim = min(screen_size.x, screen_size.y)
|
|
var scale = (min_dim * shape_scale * (1.0 - margin_ratio * 2)) / 2
|
|
|
|
if shape_presets.has(selected_shape):
|
|
var original = shape_presets[selected_shape]
|
|
var interpolated = _interpolate_shape(original, 100, true)
|
|
shape_points = PackedVector2Array()
|
|
for point in interpolated:
|
|
var scaled_point = center + (point * scale)
|
|
shape_points.append(scaled_point)
|
|
else:
|
|
print("⚠️ Forma no encontrada:", selected_shape)
|
|
return
|
|
|
|
$ShapeLine.points = shape_points
|
|
$ShapeLine.width = line_width
|
|
$ShapeLine.default_color = Color.GRAY
|
|
$ShapeLine.texture = null
|
|
|
|
$ProgressLine.clear_points()
|
|
$ProgressLine.points = []
|
|
$ProgressLine.width = line_width
|
|
$ProgressLine.default_color = Color.GREEN
|
|
$ProgressLine.texture = null
|
|
|
|
current_progress = 0
|
|
fail_count = 0
|
|
tracking = false
|
|
|
|
func _on_viewport_resized():
|
|
_draw_selected_shape()
|
|
|
|
func _unhandled_input(event):
|
|
if event is InputEventScreenTouch or event is InputEventMouseButton:
|
|
if event.pressed:
|
|
tracking = true
|
|
current_progress = 0
|
|
fail_count = 0
|
|
$ProgressLine.clear_points()
|
|
else:
|
|
tracking = false
|
|
|
|
elif (event is InputEventScreenDrag or event is InputEventMouseMotion) and tracking:
|
|
if current_progress >= shape_points.size():
|
|
return
|
|
|
|
var pos = event.position
|
|
var nearest_point = -1
|
|
var min_distance = allowed_distance
|
|
|
|
for i in range(current_progress, shape_points.size()):
|
|
var dist = pos.distance_to(shape_points[i])
|
|
if dist < min_distance:
|
|
min_distance = dist
|
|
nearest_point = i
|
|
|
|
if nearest_point != -1:
|
|
current_progress = nearest_point
|
|
$ProgressLine.add_point(shape_points[nearest_point])
|
|
|
|
if current_progress >= shape_points.size() - 1:
|
|
tracking = false
|
|
print("✅ ¡Forma completada!")
|
|
print("❌ Errores:", fail_count)
|
|
else:
|
|
fail_count += 1
|
|
print("❌ Fuera de la línea. Total:", fail_count)
|
|
|
|
func _create_shape_presets():
|
|
shape_presets = {
|
|
"cuadrado": [Vector2(-1, -1), Vector2(1, -1), Vector2(1, 1), Vector2(-1, 1)],
|
|
"triangulo": [Vector2(0, -1), Vector2(1, 1), Vector2(-1, 1)],
|
|
"casa": [Vector2(-1, 1), Vector2(-1, 0), Vector2(0, -1), Vector2(1, 0), Vector2(1, 1)],
|
|
"paraguas": [Vector2(-1, 0.5), Vector2(1, 0.5), Vector2(0, -1), Vector2(-1, 0.5), Vector2(0, 1)],
|
|
"diamante": [Vector2(0, -1), Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0)],
|
|
"linea": [Vector2(-1, 0), Vector2(1, 0)],
|
|
"rectangulo": [Vector2(-1, -0.5), Vector2(1, -0.5), Vector2(1, 0.5), Vector2(-1, 0.5)],
|
|
"rombo": [Vector2(0, -1), Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0)],
|
|
"circulo": generate_circle(Vector2.ZERO, 1),
|
|
"estrella": generate_star(Vector2.ZERO, 1),
|
|
"corazon": generate_heart(Vector2.ZERO, 1)
|
|
}
|
|
|
|
func _interpolate_shape(points: PackedVector2Array, density: int = 100, closed: bool = true) -> PackedVector2Array:
|
|
var interpolated := PackedVector2Array()
|
|
var count = points.size()
|
|
for i in range(count):
|
|
var a = points[i]
|
|
var b = points[(i + 1) % count] if closed or i < count - 1 else null
|
|
if b != null:
|
|
for j in range(density):
|
|
var t = float(j) / density
|
|
interpolated.append(a.lerp(b, t))
|
|
return interpolated
|
|
|
|
func generate_circle(center: Vector2, radius: float, segments: int = 64) -> PackedVector2Array:
|
|
var points := PackedVector2Array()
|
|
for i in range(segments + 1):
|
|
var angle = 2.0 * PI * float(i) / float(segments)
|
|
points.append(center + Vector2(cos(angle), sin(angle)) * radius)
|
|
return points
|
|
|
|
func generate_star(center: Vector2, radius: float, spikes: int = 5) -> PackedVector2Array:
|
|
var points := PackedVector2Array()
|
|
var inner_radius = radius * 0.5
|
|
for i in range(spikes * 2):
|
|
var r = radius if i % 2 == 0 else inner_radius
|
|
var angle = PI / float(spikes) * i
|
|
points.append(center + Vector2(cos(angle), sin(angle)) * r)
|
|
points.append(points[0])
|
|
return points
|
|
|
|
func generate_heart(center: Vector2, size: float) -> PackedVector2Array:
|
|
var points := PackedVector2Array()
|
|
for t in range(0, 360, 10):
|
|
var rad = deg_to_rad(t)
|
|
var x = size * 16 * pow(sin(rad), 3)
|
|
var y = -size * (13 * cos(rad) - 5 * cos(2 * rad) - 2 * cos(3 * rad) - cos(4 * rad))
|
|
points.append(center + Vector2(x, y))
|
|
points.append(points[0])
|
|
return points
|