#include "raylib.h" #include #include #include struct Bala { Vector2 posicion; Vector2 direccion; float velocidad; bool activa; }; struct Entidad { Vector2 posicion; Vector2 velocidad; float radio; }; struct Pared { Rectangle rectangulo; }; const float MUNDO_ANCHO = 1000.0f; const float MUNDO_ALTO = 650.0f; const float BORDE = 35.0f; const float RADIO_JUGADOR = 18.0f; const float RADIO_ENEMIGO = 20.0f; float Limitar(float valor, float minimo, float maximo) { if (valor < minimo) return minimo; if (valor > maximo) return maximo; return valor; } Vector2 Normalizar(Vector2 v) { float largo = sqrtf(v.x * v.x + v.y * v.y); if (largo <= 0.0001f) return {0.0f, 0.0f}; return { v.x / largo, v.y / largo }; } float Distancia(Vector2 a, Vector2 b) { float x = a.x - b.x; float y = a.y - b.y; return sqrtf(x * x + y * y); } bool CirculoRectangulo(Vector2 centro, float radio, Rectangle rect) { float puntoX = Limitar( centro.x, rect.x, rect.x + rect.width ); float puntoY = Limitar( centro.y, rect.y, rect.y + rect.height ); float dx = centro.x - puntoX; float dy = centro.y - puntoY; return dx * dx + dy * dy < radio * radio; } void DibujarBorde(float escalaX, float escalaY) { Rectangle borde = { BORDE * escalaX, BORDE * escalaY, (MUNDO_ANCHO - BORDE * 2.0f) * escalaX, (MUNDO_ALTO - BORDE * 2.0f) * escalaY }; DrawRectangleRoundedLines( borde, 0.08f, 16, WHITE ); } void RebotarBorde(Entidad& entidad) { float izquierda = BORDE + entidad.radio; float derecha = MUNDO_ANCHO - BORDE - entidad.radio; float arriba = BORDE + entidad.radio; float abajo = MUNDO_ALTO - BORDE - entidad.radio; if (entidad.posicion.x < izquierda) { entidad.posicion.x = izquierda; if (entidad.velocidad.x < 0.0f) entidad.velocidad.x *= -1.0f; } if (entidad.posicion.x > derecha) { entidad.posicion.x = derecha; if (entidad.velocidad.x > 0.0f) entidad.velocidad.x *= -1.0f; } if (entidad.posicion.y < arriba) { entidad.posicion.y = arriba; if (entidad.velocidad.y < 0.0f) entidad.velocidad.y *= -1.0f; } if (entidad.posicion.y > abajo) { entidad.posicion.y = abajo; if (entidad.velocidad.y > 0.0f) entidad.velocidad.y *= -1.0f; } } void RebotarPared(Entidad& entidad, const std::vector& paredes) { for (const Pared& pared : paredes) { if (!CirculoRectangulo( entidad.posicion, entidad.radio, pared.rectangulo)) { continue; } float izquierda = pared.rectangulo.x; float derecha = pared.rectangulo.x + pared.rectangulo.width; float arriba = pared.rectangulo.y; float abajo = pared.rectangulo.y + pared.rectangulo.height; float dIzquierda = fabsf(entidad.posicion.x - izquierda); float dDerecha = fabsf(entidad.posicion.x - derecha); float dArriba = fabsf(entidad.posicion.y - arriba); float dAbajo = fabsf(entidad.posicion.y - abajo); float menor = std::min( std::min(dIzquierda, dDerecha), std::min(dArriba, dAbajo) ); if (menor == dIzquierda) { entidad.posicion.x = izquierda - entidad.radio; entidad.velocidad.x = -fabsf(entidad.velocidad.x); } else if (menor == dDerecha) { entidad.posicion.x = derecha + entidad.radio; entidad.velocidad.x = fabsf(entidad.velocidad.x); } else if (menor == dArriba) { entidad.posicion.y = arriba - entidad.radio; entidad.velocidad.y = -fabsf(entidad.velocidad.y); } else { entidad.posicion.y = abajo + entidad.radio; entidad.velocidad.y = fabsf(entidad.velocidad.y); } } } int main() { SetConfigFlags( FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT ); InitWindow( 1100, 750, "A4B1" ); SetTargetFPS(120); Entidad jugador = { {220.0f, 325.0f}, {0.0f, 0.0f}, RADIO_JUGADOR }; Entidad enemigo = { {780.0f, 325.0f}, {210.0f, 145.0f}, RADIO_ENEMIGO }; std::vector balas; std::vector paredes = { {{280.0f, 150.0f, 180.0f, 14.0f}}, {{540.0f, 150.0f, 180.0f, 14.0f}}, {{280.0f, 486.0f, 180.0f, 14.0f}}, {{540.0f, 486.0f, 180.0f, 14.0f}}, {{240.0f, 230.0f, 14.0f, 150.0f}}, {{746.0f, 230.0f, 14.0f, 150.0f}}, {{450.0f, 245.0f, 100.0f, 14.0f}}, {{450.0f, 391.0f, 100.0f, 14.0f}} }; int impactos = 0; float tiempoDisparo = 0.0f; while (!WindowShouldClose()) { float dt = GetFrameTime(); if (IsKeyPressed(KEY_F11)) ToggleFullscreen(); int anchoPantalla = GetScreenWidth(); int altoPantalla = GetScreenHeight(); float escalaX = anchoPantalla / MUNDO_ANCHO; float escalaY = altoPantalla / MUNDO_ALTO; Vector2 mouse = GetMousePosition(); Vector2 mouseMundo = { mouse.x / escalaX, mouse.y / escalaY }; Vector2 direccionMira = Normalizar({ mouseMundo.x - jugador.posicion.x, mouseMundo.y - jugador.posicion.y }); Vector2 movimiento = { 0.0f, 0.0f }; if (IsKeyDown(KEY_W)) movimiento.y -= 1.0f; if (IsKeyDown(KEY_S)) movimiento.y += 1.0f; if (IsKeyDown(KEY_A)) movimiento.x -= 1.0f; if (IsKeyDown(KEY_D)) movimiento.x += 1.0f; movimiento = Normalizar(movimiento); Vector2 derecha = { -direccionMira.y, direccionMira.x }; Vector2 movimientoRelativo = { derecha.x * movimiento.x + direccionMira.x * (-movimiento.y), derecha.y * movimiento.x + direccionMira.y * (-movimiento.y) }; jugador.velocidad = { movimientoRelativo.x * 300.0f, movimientoRelativo.y * 300.0f }; jugador.posicion.x += jugador.velocidad.x * dt; jugador.posicion.y += jugador.velocidad.y * dt; RebotarBorde(jugador); RebotarPared(jugador, paredes); tiempoDisparo -= dt; if (IsKeyDown(KEY_SPACE) && tiempoDisparo <= 0.0f) { if (direccionMira.x != 0.0f || direccionMira.y != 0.0f) { Bala bala; bala.posicion = { jugador.posicion.x + direccionMira.x * 27.0f, jugador.posicion.y + direccionMira.y * 27.0f }; bala.direccion = direccionMira; bala.velocidad = 850.0f; bala.activa = true; balas.push_back(bala); tiempoDisparo = 0.11f; } } enemigo.posicion.x += enemigo.velocidad.x * dt; enemigo.posicion.y += enemigo.velocidad.y * dt; RebotarBorde(enemigo); RebotarPared(enemigo, paredes); for (Bala& bala : balas) { if (!bala.activa) continue; bala.posicion.x += bala.direccion.x * bala.velocidad * dt; bala.posicion.y += bala.direccion.y * bala.velocidad * dt; if (bala.posicion.x < BORDE || bala.posicion.x > MUNDO_ANCHO - BORDE || bala.posicion.y < BORDE || bala.posicion.y > MUNDO_ALTO - BORDE) { bala.activa = false; continue; } for (const Pared& pared : paredes) { if (CheckCollisionPointRec( bala.posicion, pared.rectangulo)) { bala.activa = false; break; } } if (!bala.activa) continue; if (Distancia( bala.posicion, enemigo.posicion) < enemigo.radio + 6.0f) { impactos++; enemigo.velocidad.x += bala.direccion.x * 300.0f; enemigo.velocidad.y += bala.direccion.y * 300.0f; float velocidad = sqrtf( enemigo.velocidad.x * enemigo.velocidad.x + enemigo.velocidad.y * enemigo.velocidad.y ); if (velocidad > 600.0f) { enemigo.velocidad.x = enemigo.velocidad.x / velocidad * 600.0f; enemigo.velocidad.y = enemigo.velocidad.y / velocidad * 600.0f; } bala.activa = false; } } balas.erase( std::remove_if( balas.begin(), balas.end(), [](const Bala& bala) { return !bala.activa; } ), balas.end() ); BeginDrawing(); ClearBackground({ 18, 18, 22, 255 }); for (const Pared& pared : paredes) { Rectangle r = { pared.rectangulo.x * escalaX, pared.rectangulo.y * escalaY, pared.rectangulo.width * escalaX, pared.rectangulo.height * escalaY }; DrawRectangleRounded( r, 0.3f, 8, { 45, 45, 52, 255 } ); DrawRectangleRoundedLines( r, 0.3f, 8, { 120, 120, 130, 255 } ); } DibujarBorde( escalaX, escalaY ); Vector2 jugadorPantalla = { jugador.posicion.x * escalaX, jugador.posicion.y * escalaY }; Vector2 enemigoPantalla = { enemigo.posicion.x * escalaX, enemigo.posicion.y * escalaY }; float escalaRadio = std::min(escalaX, escalaY); DrawCircleV( jugadorPantalla, jugador.radio * escalaRadio, RED ); DrawCircleV( enemigoPantalla, enemigo.radio * escalaRadio, BLUE ); Vector2 mira = { jugadorPantalla.x + direccionMira.x * 38.0f * escalaX, jugadorPantalla.y + direccionMira.y * 38.0f * escalaY }; DrawLineEx( jugadorPantalla, mira, 4.0f, WHITE ); for (const Bala& bala : balas) { Vector2 posicion = { bala.posicion.x * escalaX, bala.posicion.y * escalaY }; DrawCircleV( posicion, 5.0f * escalaRadio, YELLOW ); } DrawRectangle( 15, 15, 230, 110, Fade(BLACK, 0.75f) ); DrawText( TextFormat( "IMPACTOS: %d", impactos ), 28, 27, 22, WHITE ); DrawText( TextFormat( "FPS: %d", GetFPS() ), 28, 57, 20, GREEN ); DrawText( "WASD MOVER", 28, 87, 16, LIGHTGRAY ); DrawText( "ESPACIO DISPARAR", 28, 106, 16, LIGHTGRAY ); EndDrawing(); } CloseWindow(); return 0; }