fix: els globos verds s'inicialitzaven amb vy = 0 per gastar abs en lloc de fabs fix: corregit un bug milenari que de sempre havia creat els balloons verds al popar al pare amb la meitat de velocitat en y. Lo que jo no se es com anava res. Supose que ara el joc serà un poc mes xungo. Quan rebotaven en el piso ja se'ls posava la velocitat bona (crec)
274 lines
7.8 KiB
C++
274 lines
7.8 KiB
C++
#include "utils.h"
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <algorithm> // for min, clamp, find_if_not, transform
|
|
#include <cctype> // for tolower, isspace
|
|
#include <cmath> // for cos, pow, M_PI
|
|
#include <compare> // for operator<
|
|
struct JA_Music_t; // lines 7-7
|
|
struct JA_Sound_t; // lines 8-8
|
|
|
|
// Colores
|
|
const Color bg_color = {0x27, 0x27, 0x36};
|
|
const Color no_color = {0xFF, 0xFF, 0xFF};
|
|
const Color shdw_txt_color = {0x43, 0x43, 0x4F};
|
|
const Color separator_color = {0x0D, 0x1A, 0x2B};
|
|
const Color scoreboard_color = {0x2E, 0x3F, 0x47};
|
|
const Color difficulty_easy_color = {0x4B, 0x69, 0x2F};
|
|
const Color difficulty_normal_color = {0xFF, 0x7A, 0x00};
|
|
const Color difficulty_hard_color = {0x76, 0x42, 0x8A};
|
|
const Color flash_color = {0xFF, 0xFF, 0xFF};
|
|
const Color fade_color = {0x27, 0x27, 0x36};
|
|
const Color orange_color = {0xFF, 0x7A, 0x00};
|
|
|
|
// Calcula el cuadrado de la distancia entre dos puntos
|
|
double distanceSquared(int x1, int y1, int x2, int y2)
|
|
{
|
|
const int delta_x = x2 - x1;
|
|
const int delta_y = y2 - y1;
|
|
return delta_x * delta_x + delta_y * delta_y;
|
|
}
|
|
|
|
// Detector de colisiones entre dos circulos
|
|
bool checkCollision(const Circle &a, const Circle &b)
|
|
{
|
|
// Calcula el radio total al cuadrado
|
|
int total_radius_squared = (a.r + b.r) * (a.r + b.r);
|
|
|
|
// Comprueba si la distancia entre los centros de los círculos es inferior a la suma de sus radios
|
|
return distanceSquared(a.x, a.y, b.x, b.y) < total_radius_squared;
|
|
}
|
|
|
|
// Detector de colisiones entre un circulo y un rectangulo
|
|
bool checkCollision(const Circle &a, const SDL_Rect &b)
|
|
{
|
|
// Encuentra el punto más cercano en el rectángulo
|
|
int cX = std::clamp(a.x, b.x, b.x + b.w);
|
|
int cY = std::clamp(a.y, b.y, b.y + b.h);
|
|
|
|
// Si el punto más cercano está dentro del círculo
|
|
return distanceSquared(a.x, a.y, cX, cY) < a.r * a.r;
|
|
}
|
|
|
|
// Detector de colisiones entre dos rectangulos
|
|
bool checkCollision(const SDL_Rect &a, const SDL_Rect &b)
|
|
{
|
|
const int leftA = a.x, rightA = a.x + a.w, topA = a.y, bottomA = a.y + a.h;
|
|
const int leftB = b.x, rightB = b.x + b.w, topB = b.y, bottomB = b.y + b.h;
|
|
|
|
if (bottomA <= topB)
|
|
return false;
|
|
if (topA >= bottomB)
|
|
return false;
|
|
if (rightA <= leftB)
|
|
return false;
|
|
if (leftA >= rightB)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Detector de colisiones entre un punto y un rectangulo
|
|
bool checkCollision(const SDL_Point &p, const SDL_Rect &r)
|
|
{
|
|
if (p.x < r.x || p.x > r.x + r.w)
|
|
return false;
|
|
if (p.y < r.y || p.y > r.y + r.h)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Convierte una cadena en un valor booleano
|
|
bool stringToBool(const std::string &str)
|
|
{
|
|
return str == "true";
|
|
}
|
|
|
|
// Convierte un valor booleano en una cadena
|
|
std::string boolToString(bool value)
|
|
{
|
|
return value ? "true" : "false";
|
|
}
|
|
|
|
// Convierte un valor booleano en una cadena "on" o "off"
|
|
std::string boolToOnOff(bool value)
|
|
{
|
|
return value ? "on" : "off";
|
|
}
|
|
|
|
// Convierte una cadena a minusculas
|
|
std::string toLower(const std::string &str)
|
|
{
|
|
std::string result = str;
|
|
std::transform(result.begin(), result.end(), result.begin(),
|
|
[](unsigned char c)
|
|
{ return std::tolower(c); });
|
|
return result;
|
|
}
|
|
|
|
// Dibuja un circulo
|
|
void DrawCircle(SDL_Renderer *renderer, int32_t centerX, int32_t centerY, int32_t radius)
|
|
{
|
|
const int32_t diameter = (radius * 2);
|
|
|
|
int32_t x = (radius - 1);
|
|
int32_t y = 0;
|
|
int32_t tx = 1;
|
|
int32_t ty = 1;
|
|
int32_t error = (tx - diameter);
|
|
|
|
while (x >= y)
|
|
{
|
|
// Each of the following renders an octant of the circle
|
|
SDL_RenderDrawPoint(renderer, centerX + x, centerY - y);
|
|
SDL_RenderDrawPoint(renderer, centerX + x, centerY + y);
|
|
SDL_RenderDrawPoint(renderer, centerX - x, centerY - y);
|
|
SDL_RenderDrawPoint(renderer, centerX - x, centerY + y);
|
|
SDL_RenderDrawPoint(renderer, centerX + y, centerY - x);
|
|
SDL_RenderDrawPoint(renderer, centerX + y, centerY + x);
|
|
SDL_RenderDrawPoint(renderer, centerX - y, centerY - x);
|
|
SDL_RenderDrawPoint(renderer, centerX - y, centerY + x);
|
|
|
|
if (error <= 0)
|
|
{
|
|
++y;
|
|
error += ty;
|
|
ty += 2;
|
|
}
|
|
|
|
if (error > 0)
|
|
{
|
|
--x;
|
|
tx += 2;
|
|
error += (tx - diameter);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Aclara el color
|
|
Color lightenColor(const Color &color, int amount)
|
|
{
|
|
Color newColor;
|
|
newColor.r = std::min(255, color.r + amount);
|
|
newColor.g = std::min(255, color.g + amount);
|
|
newColor.b = std::min(255, color.b + amount);
|
|
return newColor;
|
|
}
|
|
|
|
// Oscurece el color
|
|
Color DarkenColor(const Color &color, int amount)
|
|
{
|
|
Color newColor;
|
|
newColor.r = std::min(255, color.r - +amount);
|
|
newColor.g = std::min(255, color.g - +amount);
|
|
newColor.b = std::min(255, color.b - +amount);
|
|
return newColor;
|
|
}
|
|
|
|
// Quita los espacioes en un string
|
|
std::string trim(const std::string &str)
|
|
{
|
|
auto start = std::find_if_not(str.begin(), str.end(), ::isspace);
|
|
auto end = std::find_if_not(str.rbegin(), str.rend(), ::isspace).base();
|
|
return (start < end ? std::string(start, end) : std::string());
|
|
}
|
|
|
|
// Función de suavizado
|
|
double easeOutQuint(double t)
|
|
{
|
|
return 1 - std::pow(1 - t, 5);
|
|
}
|
|
|
|
// Función de suavizado
|
|
double easeInOutSine(double t)
|
|
{
|
|
return -0.5 * (std::cos(M_PI * t) - 1);
|
|
}
|
|
|
|
// Comprueba si una vector contiene una cadena
|
|
bool stringInVector(const std::vector<std::string> &vec, const std::string &str)
|
|
{
|
|
return std::find(vec.begin(), vec.end(), str) != vec.end();
|
|
}
|
|
|
|
// Imprime por pantalla una linea de texto de tamaño fijo rellena con puntos
|
|
void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3)
|
|
{
|
|
std::cout.setf(std::ios::left, std::ios::adjustfield);
|
|
std::cout << text1;
|
|
|
|
std::cout.width(50 - text1.length() - text3.length());
|
|
std::cout.fill('.');
|
|
std::cout << text2;
|
|
|
|
std::cout << text3 << std::endl;
|
|
}
|
|
|
|
// Carga el fichero de datos para la demo
|
|
DemoData loadDemoDataFromFile(const std::string &file_path)
|
|
{
|
|
DemoData dd;
|
|
|
|
// Indicador de éxito en la carga
|
|
auto file = SDL_RWFromFile(file_path.c_str(), "r+b");
|
|
if (!file)
|
|
{
|
|
std::cerr << "Error: Fichero no encontrado " << file_path << std::endl;
|
|
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
|
}
|
|
else
|
|
{
|
|
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
|
|
printWithDots("DemoData : ", file_name, "[ LOADED ]");
|
|
|
|
// Lee todos los datos del fichero y los deja en el destino
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
DemoKeys dk = DemoKeys();
|
|
SDL_RWread(file, &dk, sizeof(DemoKeys), 1);
|
|
dd.push_back(dk);
|
|
}
|
|
|
|
// Cierra el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
|
|
return dd;
|
|
}
|
|
|
|
#ifdef RECORDING
|
|
// Guarda el fichero de datos para la demo
|
|
bool saveDemoFile(const std::string &file_path, const DemoData &dd)
|
|
{
|
|
auto success = true;
|
|
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
|
|
auto file = SDL_RWFromFile(file_path.c_str(), "w+b");
|
|
|
|
if (file)
|
|
{
|
|
// Guarda los datos
|
|
for (const auto &data : dd)
|
|
{
|
|
if (SDL_RWwrite(file, &data, sizeof(DemoKeys), 1) != 1)
|
|
{
|
|
std::cerr << "Error al escribir el fichero " << file_name << std::endl;
|
|
success = false;
|
|
break;
|
|
}
|
|
}
|
|
if (success)
|
|
{
|
|
std::cout << "Writing file " << file_name.c_str() << std::endl;
|
|
}
|
|
// Cierra el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Error: Unable to save " << file_name.c_str() << " file! " << SDL_GetError() << std::endl;
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
#endif // RECORDING
|