#include "cylinder_shape.hpp" #include "defines.hpp" #include #include // Para rand() void CylinderShape::generatePoints(int num_points, float screen_width, float screen_height) { num_points_ = num_points; radius_ = screen_height * CYLINDER_RADIUS_FACTOR; height_ = screen_height * CYLINDER_HEIGHT_FACTOR; // Inicializar timer de tumbling con valor aleatorio (3-5 segundos) tumble_timer_ = 3.0f + (rand() % 2000) / 1000.0f; // Las posiciones 3D se calculan en getPoint3D() usando ecuaciones paramétricas del cilindro } void CylinderShape::update(float delta_time, float screen_width, float screen_height) { // Recalcular dimensiones por si cambió resolución (F4) radius_ = screen_height * CYLINDER_RADIUS_FACTOR; height_ = screen_height * CYLINDER_HEIGHT_FACTOR; // Actualizar ángulo de rotación en eje Y (siempre activo) angle_y_ += CYLINDER_ROTATION_SPEED_Y * delta_time; // Sistema de tumbling ocasional if (is_tumbling_) { // Estamos en tumble: animar angle_x hacia el objetivo tumble_duration_ += delta_time; float tumble_progress = tumble_duration_ / 1.5f; // 1.5 segundos de duración if (tumble_progress >= 1.0f) { // Tumble completado angle_x_ = tumble_target_; is_tumbling_ = false; tumble_timer_ = 3.0f + (rand() % 2000) / 1000.0f; // Nuevo timer (3-5s) } else { // Interpolación suave con ease-in-out float t = tumble_progress; float ease = t < 0.5f ? 2.0f * t * t : 1.0f - (-2.0f * t + 2.0f) * (-2.0f * t + 2.0f) / 2.0f; angle_x_ = ease * tumble_target_; } } else { // No estamos en tumble: contar tiempo tumble_timer_ -= delta_time; if (tumble_timer_ <= 0.0f) { // Iniciar nuevo tumble is_tumbling_ = true; tumble_duration_ = 0.0f; // Objetivo: PI/2 radianes (90°) o -PI/2 tumble_target_ = angle_x_ + ((rand() % 2) == 0 ? PI * 0.5f : -PI * 0.5f); } } } void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const { // Distribuir puntos uniformemente en la superficie del cilindro // Calcular número de anillos (altura) y puntos por anillo (circunferencia) int num_rings = static_cast(sqrtf(static_cast(num_points_) * 0.5f)); if (num_rings < 2) num_rings = 2; int points_per_ring = num_points_ / num_rings; if (points_per_ring < 3) points_per_ring = 3; // Obtener parámetros u (ángulo) y v (altura) del índice int ring = index / points_per_ring; int point_in_ring = index % points_per_ring; // Si nos pasamos del número de anillos, usar el último if (ring >= num_rings) { ring = num_rings - 1; point_in_ring = index - (ring * points_per_ring); if (point_in_ring >= points_per_ring) { point_in_ring = points_per_ring - 1; } } // Parámetro u (ángulo alrededor del cilindro): [0, 2π] float u = (static_cast(point_in_ring) / static_cast(points_per_ring)) * 2.0f * PI; // Parámetro v (altura normalizada): [-1, 1] float v = (static_cast(ring) / static_cast(num_rings - 1)) * 2.0f - 1.0f; if (num_rings == 1) v = 0.0f; // Ecuaciones paramétricas del cilindro // x = radius * cos(u) // y = height * v // z = radius * sin(u) float x_base = radius_ * cosf(u); float y_base = (height_ * 0.5f) * v; // Centrar verticalmente float z_base = radius_ * sinf(u); // Aplicar rotación en eje Y (principal, siempre activa) float cos_y = cosf(angle_y_); float sin_y = sinf(angle_y_); float x_rot_y = x_base * cos_y - z_base * sin_y; float z_rot_y = x_base * sin_y + z_base * cos_y; // Aplicar rotación en eje X (tumbling ocasional) float cos_x = cosf(angle_x_); float sin_x = sinf(angle_x_); float y_rot = y_base * cos_x - z_rot_y * sin_x; float z_rot = y_base * sin_x + z_rot_y * cos_x; // Retornar coordenadas finales con ambas rotaciones x = x_rot_y; y = y_rot; z = z_rot; } float CylinderShape::getScaleFactor(float screen_height) const { // Factor de escala para física: proporcional a la dimensión mayor (altura) // Altura base = 120px (0.5 * 240px en resolución 320x240) const float BASE_HEIGHT = 120.0f; float current_height = screen_height * CYLINDER_HEIGHT_FACTOR; return current_height / BASE_HEIGHT; }