Creamos la base jugable de A4B1 con movimiento, disparos, enemigo, paredes, colisiones y rebotes

This commit is contained in:
Clinv committed 2026-09-26 17:03:22 -03:00
1 parent dd1284fca0
commit d3c1495b7c
2 files changed
+513 -339

No files matched your search

+513 -222
View File
@@ -1,293 +1,584 @@
#include "raylib.h" #include "raylib.h"
#include <cmath> #include <cmath>
#include <vector>
#include <algorithm>
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<Pared>& 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() int main()
{ {
const int pantallaAncho = 800; SetConfigFlags(
const int pantallaAlto = 600; FLAG_WINDOW_RESIZABLE |
FLAG_VSYNC_HINT
InitWindow(
pantallaAncho,
pantallaAlto,
"Attacks for Bombs 1"
); );
SetTargetFPS(60); InitWindow(
1100,
750,
"A4B1"
);
// ========================= SetTargetFPS(120);
// JUGADOR
// =========================
float x = 400.0f; Entidad jugador = {
float y = 300.0f; {220.0f, 325.0f},
{0.0f, 0.0f},
RADIO_JUGADOR
};
float tamaño = 50.0f; Entidad enemigo = {
float velocidad = 300.0f; {780.0f, 325.0f},
{210.0f, 145.0f},
RADIO_ENEMIGO
};
// ========================= std::vector<Bala> balas;
// DIRECCIÓN DEL JUGADOR
// =========================
float direccionX = 1.0f; std::vector<Pared> paredes = {
float direccionY = 0.0f; {{280.0f, 150.0f, 180.0f, 14.0f}},
{{540.0f, 150.0f, 180.0f, 14.0f}},
// ========================= {{280.0f, 486.0f, 180.0f, 14.0f}},
// PROYECTIL {{540.0f, 486.0f, 180.0f, 14.0f}},
// ========================= {{240.0f, 230.0f, 14.0f, 150.0f}},
{{746.0f, 230.0f, 14.0f, 150.0f}},
float proyectilX = 0.0f; {{450.0f, 245.0f, 100.0f, 14.0f}},
float proyectilY = 0.0f; {{450.0f, 391.0f, 100.0f, 14.0f}}
};
float proyectilAncho = 20.0f;
float proyectilAlto = 8.0f;
float proyectilVelocidad = 600.0f;
bool proyectilActivo = false;
// Dirección congelada del proyectil
float proyectilDireccionX = 0.0f;
float proyectilDireccionY = 0.0f;
// =========================
// ENEMIGO
// =========================
float enemigoX = 600.0f;
float enemigoY = 300.0f;
float enemigoTamaño = 50.0f;
// =========================
// CONTADOR
// =========================
int impactos = 0; int impactos = 0;
float tiempoDisparo = 0.0f;
// =========================
// BUCLE PRINCIPAL
// =========================
while (!WindowShouldClose()) while (!WindowShouldClose())
{ {
float deltaTime = GetFrameTime(); float dt = GetFrameTime();
// ========================= if (IsKeyPressed(KEY_F11))
// MOUSE ToggleFullscreen();
// =========================
int anchoPantalla = GetScreenWidth();
int altoPantalla = GetScreenHeight();
float escalaX = anchoPantalla / MUNDO_ANCHO;
float escalaY = altoPantalla / MUNDO_ALTO;
Vector2 mouse = GetMousePosition(); Vector2 mouse = GetMousePosition();
// Dirección del jugador hacia el mouse Vector2 mouseMundo = {
float angulo = mouse.x / escalaX,
atan2(mouse.y - y, mouse.x - x); mouse.y / escalaY
};
direccionX = cos(angulo); Vector2 direccionMira = Normalizar({
direccionY = sin(angulo); mouseMundo.x - jugador.posicion.x,
mouseMundo.y - jugador.posicion.y
});
// ========================= Vector2 movimiento = {
// MOVIMIENTO 0.0f,
// ========================= 0.0f
};
if (IsKeyDown(KEY_W)) if (IsKeyDown(KEY_W))
{ movimiento.y -= 1.0f;
x += direccionX * velocidad * deltaTime;
y += direccionY * velocidad * deltaTime;
}
if (IsKeyDown(KEY_S)) if (IsKeyDown(KEY_S))
{ movimiento.y += 1.0f;
x -= direccionX * velocidad * deltaTime;
y -= direccionY * velocidad * deltaTime;
}
if (IsKeyDown(KEY_A)) if (IsKeyDown(KEY_A))
{ movimiento.x -= 1.0f;
x += direccionY * velocidad * deltaTime;
y -= direccionX * velocidad * deltaTime;
}
if (IsKeyDown(KEY_D)) 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)
{ {
x -= direccionY * velocidad * deltaTime; if (direccionMira.x != 0.0f ||
y += direccionX * velocidad * deltaTime; 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 +=
// LÍMITES DEL JUGADOR enemigo.velocidad.x * dt;
// =========================
float mitad = tamaño / 2.0f; enemigo.posicion.y +=
enemigo.velocidad.y * dt;
if (x < mitad) RebotarBorde(enemigo);
x = mitad; RebotarPared(enemigo, paredes);
if (x > pantallaAncho - mitad) for (Bala& bala : balas)
x = pantallaAncho - mitad;
if (y < mitad)
y = mitad;
if (y > pantallaAlto - mitad)
y = pantallaAlto - mitad;
// =========================
// DISPARAR
// =========================
if (IsKeyPressed(KEY_SPACE) && !proyectilActivo)
{ {
proyectilActivo = true; if (!bala.activa)
continue;
// El proyectil aparece en el jugador bala.posicion.x +=
proyectilX = x; bala.direccion.x *
proyectilY = y; bala.velocidad *
dt;
// Guardamos la dirección EXACTA bala.posicion.y +=
// que tenía el jugador al disparar bala.direccion.y *
proyectilDireccionX = direccionX; bala.velocidad *
proyectilDireccionY = direccionY; dt;
}
// ========================= if (bala.posicion.x < BORDE ||
// MOVIMIENTO DEL PROYECTIL bala.posicion.x > MUNDO_ANCHO - BORDE ||
// ========================= bala.posicion.y < BORDE ||
bala.posicion.y > MUNDO_ALTO - BORDE)
if (proyectilActivo)
{
proyectilX +=
proyectilDireccionX *
proyectilVelocidad *
deltaTime;
proyectilY +=
proyectilDireccionY *
proyectilVelocidad *
deltaTime;
// =========================
// COLISIÓN CON ENEMIGO
// =========================
Rectangle proyectilRect =
{ {
proyectilX - proyectilAncho / 2.0f, bala.activa = false;
proyectilY - proyectilAlto / 2.0f, continue;
proyectilAncho, }
proyectilAlto
};
Rectangle enemigoRect = for (const Pared& pared : paredes)
{ {
enemigoX - enemigoTamaño / 2.0f, if (CheckCollisionPointRec(
enemigoY - enemigoTamaño / 2.0f, bala.posicion,
enemigoTamaño, pared.rectangulo))
enemigoTamaño {
}; bala.activa = false;
break;
}
}
if (CheckCollisionRecs( if (!bala.activa)
proyectilRect, continue;
enemigoRect))
if (Distancia(
bala.posicion,
enemigo.posicion)
< enemigo.radio + 6.0f)
{ {
impactos++; impactos++;
proyectilActivo = false; enemigo.velocidad.x +=
} bala.direccion.x * 300.0f;
// ========================= enemigo.velocidad.y +=
// SALIR DE LA PANTALLA bala.direccion.y * 300.0f;
// =========================
if ( float velocidad = sqrtf(
proyectilX < 0 || enemigo.velocidad.x *
proyectilX > pantallaAncho || enemigo.velocidad.x +
proyectilY < 0 || enemigo.velocidad.y *
proyectilY > pantallaAlto enemigo.velocidad.y
) );
{
proyectilActivo = false; 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(
// DIBUJAR std::remove_if(
// ========================= balas.begin(),
balas.end(),
[](const Bala& bala)
{
return !bala.activa;
}
),
balas.end()
);
BeginDrawing(); BeginDrawing();
ClearBackground(WHITE); ClearBackground({
18,
18,
22,
255
});
// ========================= for (const Pared& pared : paredes)
// CONTADOR
// =========================
DrawText(
TextFormat("Impactos: %d", impactos),
10,
10,
25,
BLACK
);
// =========================
// ENEMIGO
// =========================
DrawRectangle(
enemigoX - enemigoTamaño / 2.0f,
enemigoY - enemigoTamaño / 2.0f,
enemigoTamaño,
enemigoTamaño,
BLUE
);
// =========================
// PROYECTIL
// =========================
if (proyectilActivo)
{ {
float anguloProyectil = Rectangle r = {
atan2( pared.rectangulo.x * escalaX,
proyectilDireccionY, pared.rectangulo.y * escalaY,
proyectilDireccionX pared.rectangulo.width * escalaX,
) * RAD2DEG; pared.rectangulo.height * escalaY
};
DrawRectanglePro( DrawRectangleRounded(
r,
0.3f,
8,
{ {
proyectilX, 45,
proyectilY, 45,
proyectilAncho, 52,
proyectilAlto 255
}, }
);
DrawRectangleRoundedLines(
r,
0.3f,
8,
{ {
proyectilAncho / 2.0f, 120,
proyectilAlto / 2.0f 120,
}, 130,
anguloProyectil, 255
BLACK }
); );
} }
// ========================= DibujarBorde(
// JUGADOR escalaX,
// ========================= escalaY
);
DrawRectanglePro( Vector2 jugadorPantalla = {
{ jugador.posicion.x * escalaX,
x, jugador.posicion.y * escalaY
y, };
tamaño,
tamaño Vector2 enemigoPantalla = {
}, enemigo.posicion.x * escalaX,
{ enemigo.posicion.y * escalaY
mitad, };
mitad
}, float escalaRadio =
angulo * RAD2DEG, std::min(escalaX, escalaY);
DrawCircleV(
jugadorPantalla,
jugador.radio * escalaRadio,
RED 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(); EndDrawing();
} }
-117
View File
@@ -1,117 +0,0 @@
#include "raylib.h"
#include <cmath>
int main()
{
// Tamaño de la ventana
const int pantallaAncho = 800;
const int pantallaAlto = 600;
// Crear ventana
InitWindow(
pantallaAncho,
pantallaAlto,
"Attacks for Bombs 1"
);
// Limitar a 60 FPS
SetTargetFPS(60);
// Posición del jugador
float x = 400.0f;
float y = 300.0f;
// Tamaño del jugador
float tamaño = 50.0f;
// Velocidad del jugador
float velocidad = 300.0f;
while (!WindowShouldClose())
{
// Tiempo que pasó desde el frame anterior
float deltaTime = GetFrameTime();
// Posición del mouse
Vector2 mouse = GetMousePosition();
// Dirección hacia el mouse
float angulo =
atan2(mouse.y - y, mouse.x - x);
float direccionX = cos(angulo);
float direccionY = sin(angulo);
// Movimiento hacia adelante
if (IsKeyDown(KEY_W))
{
x += direccionX * velocidad * deltaTime;
y += direccionY * velocidad * deltaTime;
}
// Movimiento hacia atrás
if (IsKeyDown(KEY_S))
{
x -= direccionX * velocidad * deltaTime;
y -= direccionY * velocidad * deltaTime;
}
// Movimiento hacia la izquierda
if (IsKeyDown(KEY_A))
{
x += direccionY * velocidad * deltaTime;
y -= direccionX * velocidad * deltaTime;
}
// Movimiento hacia la derecha
if (IsKeyDown(KEY_D))
{
x -= direccionY * velocidad * deltaTime;
y += direccionX * velocidad * deltaTime;
}
// Límites de la pantalla
float mitad = tamaño / 2.0f;
if (x < mitad)
x = mitad;
if (x > pantallaAncho - mitad)
x = pantallaAncho - mitad;
if (y < mitad)
y = mitad;
if (y > pantallaAlto - mitad)
y = pantallaAlto - mitad;
// Dibujar
BeginDrawing();
// Fondo blanco
ClearBackground(WHITE);
// Dibujar jugador
DrawRectanglePro(
{
x,
y,
tamaño,
tamaño
},
{
mitad,
mitad
},
angulo * RAD2DEG,
RED
);
EndDrawing();
}
// Cerrar ventana
CloseWindow();
return 0;
}