De todo un poco

This commit is contained in:
Marklogo 2024-04-08 02:28:46 +02:00
parent 3444bc59ed
commit 68177c2ffa
15 changed files with 924 additions and 153 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 197 KiB

View File

@ -10,17 +10,24 @@
</head> </head>
<body> <body>
<div id="container"> <div class="parent">
<div id="sub-container"> <div class="div1">
<canvas id="mapa" tabindex="0"></canvas> <div class="logo" style="width: fit-content;">
<h1 style="font-size: 5rem;display: inline;">BattleShip</h1>
<i style="font-size: 2rem;" class="ti ti-medal-2"></i>
<i style="font-size: 2rem;" class="ti ti-medal-2"></i>
</div>
</div> </div>
<div id="sub-container"> <div class="div2"> <canvas id="mapa" tabindex="-1"></canvas></div>
<canvas id="minimapa" tabindex="1"></canvas> <div class="div3"> <canvas id="minimapa" tabindex="-1"></canvas></div>
<textarea id="chat" readonly>Battleship</textarea> <div class="div4" tabindex="-1"> </div>
<input type="text" name="" id=""> <div class="div5" tabindex="-1">
<div id="logchat"> </div>
<input id="chatinput" type="text">
</div> </div>
</div> </div>
</body> </body>
<script src="socket.io/socket.io.js"></script> <script src="socket.io/socket.io.js"></script>
<script type="module" src="./js_game/battleship.js"></script> <script type="module" src="./js_game/battleship.js"></script>
</html> </html>

63
public/js_game/barco.js Normal file
View File

@ -0,0 +1,63 @@
export const BarcoTipo = Object.freeze({
FRAGATA: 1,
DESTRUCTOR: 2,
ACORAZADO: 3,
PORTAAVIONES: 4,
});
class Barco {
constructor(x, y, longitud, orientacion, barcoImg, tipoNave) {
this.barcoImg = barcoImg;
this.tipoNave = tipoNave;
this.xIni = this.x = x;
this.yIni = this.y = y;
this.longitud = longitud;
this.orientacionIni = this.orientacion = orientacion;
this.seleccionado = false;
this.posIncorrecta = true;
}
clickado(clickX, clickY) {
if (this.orientacion === 'VERTICAL') {
return (
clickX === this.x && clickY >= this.y && clickY < this.y + this.longitud
);
} else {
return (
clickY === this.y && clickX >= this.x && clickX < this.x + this.longitud
);
}
}
saveIniPos() {
this.orientacionIni = this.orientacion;
this.xIni = this.x;
this.yIni = this.y;
}
restoreIniPos() {
this.orientacion = this.orientacionIni;
this.x = this.xIni;
this.y = this.yIni;
}
setXY(x, y) {
this.x = x;
this.y = y;
}
giraBarco() {
this.orientacion === 'VERTICAL'
? (this.orientacion = 'HORIZONTAL')
: (this.orientacion = 'VERTICAL');
}
draw(ctx) {
this.orientacion === 'VERTICAL'
? ctx.drawImage(this.barcoImg[0], this.x * 64, this.y * 64)
: ctx.drawImage(this.barcoImg[1], this.x * 64, this.y * 64);
if (this.seleccionado) {
ctx.fillStyle = this.posIncorrecta
? 'rgba(255, 0, 0, 0.2)'
: 'rgba(187, 187, 0, 0.2)';
this.orientacion === 'VERTICAL'
? ctx.fillRect(this.x * 64, this.y * 64, 64, 64 * this.longitud)
: ctx.fillRect(this.x * 64, this.y * 64, 64 * this.longitud, 64);
}
}
}
export default Barco;

View File

@ -1,6 +1,178 @@
const urlParams = new URLSearchParams(window.location.search); import { TableroEditor, TableroVisor } from './tablero.js';
const gameId = urlParams.get('game_id'); const barcosImg = new Image();
const userId = localStorage.getItem('userId'); barcosImg.src = '/assets/barcos.png';
const socket = io('/batalla', { closeOnBeforeunload: true, auth: { userId, gameId } }); barcosImg.onload = function () {
iniciaJuego();
};
function getSprites(spriteSheet) {
const sprites = {
PORTAAVIONES: [
{ x: 0, y: 0, width: 64, height: 256 },
{ x: 64, y: 192, width: 256, height: 64 },
],
ACORAZADO: [
{ x: 64, y: 0, width: 64, height: 192 },
{ x: 128, y: 128, width: 192, height: 64 },
],
DESTRUCTOR: [
{ x: 128, y: 0, width: 64, height: 128 },
{ x: 192, y: 64, width: 128, height: 64 },
],
FRAGATA: [
{ x: 192, y: 0, width: 64, height: 64 },
{ x: 256, y: 0, width: 64, height: 64 },
],
OCEANO: [
{ x: 320, y: 0, width: 32, height: 32 },
{ x: 384, y: 0, width: 32, height: 32 },
{ x: 416, y: 0, width: 32, height: 32 },
{ x: 320, y: 32, width: 32, height: 32 },
{ x: 352, y: 64, width: 32, height: 32 },
{ x: 416, y: 64, width: 32, height: 32 },
{ x: 320, y: 96, width: 32, height: 32 },
{ x: 352, y: 96, width: 32, height: 32 },
{ x: 416, y: 96, width: 32, height: 32 },
{ x: 448, y: 0, width: 32, height: 32 },
{ x: 512, y: 0, width: 32, height: 32 },
{ x: 544, y: 0, width: 32, height: 32 },
{ x: 448, y: 32, width: 32, height: 32 },
{ x: 480, y: 64, width: 32, height: 32 },
{ x: 544, y: 64, width: 32, height: 32 },
{ x: 448, y: 96, width: 32, height: 32 },
{ x: 480, y: 96, width: 32, height: 32 },
{ x: 544, y: 96, width: 32, height: 32 },
{ x: 576, y: 0, width: 32, height: 32 },
{ x: 640, y: 0, width: 32, height: 32 },
{ x: 672, y: 0, width: 32, height: 32 },
{ x: 576, y: 32, width: 32, height: 32 },
{ x: 608, y: 64, width: 32, height: 32 },
{ x: 672, y: 64, width: 32, height: 32 },
{ x: 576, y: 96, width: 32, height: 32 },
{ x: 608, y: 96, width: 32, height: 32 },
{ x: 672, y: 96, width: 32, height: 32 },
],
};
const spritesObj = {};
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
for (const key in sprites) {
if (Object.hasOwnProperty.call(sprites, key)) {
const spriteArray = sprites[key];
spritesObj[key] = spriteArray.map((sprite) => {
canvas.width = sprite.width;
canvas.height = sprite.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
spriteSheet,
sprite.x,
sprite.y,
sprite.width,
sprite.height,
0,
0,
sprite.width,
sprite.height,
);
const spriteImage = new Image();
spriteImage.src = canvas.toDataURL();
return spriteImage;
});
}
}
return spritesObj;
}
function iniciaJuego() {
const canvasMapa = document.getElementById('mapa');
const canvasMiniMapa = document.getElementById('minimapa');
const sprites = getSprites(barcosImg);
const urlParams = new URLSearchParams(window.location.search);
const gameId = urlParams.get('game_id');
const userId = localStorage.getItem('userId');
const socket = io('/batalla', {
closeOnBeforeunload: true,
auth: { userId, gameId },
});
let tablero = null;
const OnChangeState = (snapshotJugador) => {
switch (snapshotJugador.estado) {
case 'ENPREPARACION':
ENPREPARACION(snapshotJugador);
break;
case 'ENCURSO':
ENCURSO(snapshotJugador);
break;
}
};
const handlers = {
connect: () => {
gameLoop();
},
disconnect: () => {
window.close();
},
OnChangeState,
};
Object.entries(handlers).forEach(([event, handler]) => {
socket.on(event, handler);
});
const ENPREPARACION = (snapshotJugador) => {
muestraBoton('Fijar Flota',()=>{
console.log(JSON.stringify(tablero.mapaFlota.barcos));
socket.emit('sendFlota', tablero.mapaFlota.barcos,handlers.OnChangeState);
});
addMsgChat('Situa tu flota en el mapa y pulsa el boton para continuar');
tablero = new TableroEditor(canvasMapa, canvasMiniMapa, sprites, [
snapshotJugador.mapaFlota,
snapshotJugador.mapaDeAtaques,
]);
};
function addMsgChat(msg) {
const divChat = document.querySelector('#logchat');
const pMsg = document.createElement('p');
pMsg.textContent = msg;
divChat.appendChild(pMsg);
divChat.scrollTop = divChat.scrollHeight;
}
function muestraBoton(msg, callback) {
const divContent = document.querySelector('.div4');
divContent.innerHTML = `<button class="button button-orange prepasradoBtn"> --${msg}-- </button>`;
const preparadoBtn = divContent.querySelector('.prepasradoBtn');
preparadoBtn.addEventListener('click', callback);
}
function muestraAviso(msg) {
const divContent = document.querySelector('.div4');
divContent.innerHTML = `<span class="avisoMsg parpadea"> -- ${msg} -- </span>`;
}
function limpiaContenedorAvisos() {
const divContent = document.querySelector('.div4');
divContent.innerHTML = '';
}
function gameLoop() {
if (tablero) tablero.draw();
window.requestAnimationFrame(gameLoop);
}
}

266
public/js_game/mapa.js Normal file
View File

@ -0,0 +1,266 @@
import Barco from './barco.js';
import Oceano from './oceano.js';
class MapaBase {
constructor(canvas, size, scale, sprites) {
this.canvas = canvas;
this.canvas.width = size;
this.canvas.height = size;
this.width = size / scale;
this.height = size / scale;
this.ctx = this.canvas.getContext('2d');
this.scale = scale;
this.ctx.scale(this.scale, this.scale);
this.sprites = sprites;
this.oceano = new Oceano(this.width, this.height, 32, sprites['OCEANO']);
this.casillaSize = 64;
this.numFilas = 10;
this.numColumnas = 10;
}
draw() {
this.ctx.clearRect(0, 0, this.width, this.height);
this.oceano.draw(this.ctx);
}
}
class MapaVisor extends MapaBase {
celdas = [];
barcos = [];
constructor(canvas, size, scale, sprites, barcos, celdas) {
super(canvas, size, scale, sprites);
this.celdas = celdas;
//this.inicializarCeldas();
this.setBarcos(barcos);
}
inicializarCeldas() {
for (let i = 0; i < this.numFilas; i++) {
this.celdas[i] = new Array(this.numColumnas).fill(0);
}
}
setBarcos(barcos) {
const barcosArray = Array.isArray(barcos) ? barcos : [barcos];
for (const barco of barcosArray) {
this.barcos.push(
new Barco(
barco.x,
barco.y,
barco.longitud,
barco.orientacion,
this.sprites[barco.tipoNave],
barco.tipoNave,
),
);
}
}
draw() {
super.draw();
this.barcos.forEach((barco) => {
barco.draw(this.ctx);
});
this.ctx.beginPath();
for (let i = 1; i < this.numFilas; i++) {
const y = i * this.casillaSize;
this.ctx.moveTo(5, y);
this.ctx.lineTo(this.casillaSize * this.numColumnas - 5, y);
}
for (let i = 1; i < this.numColumnas; i++) {
const x = i * this.casillaSize;
this.ctx.moveTo(x, 5);
this.ctx.lineTo(x, this.casillaSize * this.numFilas - 5);
}
this.ctx.strokeStyle = 'rgba(0, 255, 0, 0.6)';
this.ctx.stroke();
this.ctx.fillStyle = 'red';
this.ctx.font = 'bold 24px Arial';
for (let fila = 0; fila < this.numFilas; fila++) {
for (let columna = 0; columna < this.numColumnas; columna++) {
const valor = this.celdas[fila][columna];
const posX = columna * this.casillaSize + this.casillaSize / 2.3;
const posY = fila * this.casillaSize + this.casillaSize / 1.5;
this.ctx.fillText(valor, posX, posY);
}
}
}
}
class MapaAtaque extends MapaVisor {
constructor(canvas, size, scale, sprites, barcos, celdas) {
super(canvas, size, scale, sprites, barcos, celdas);
canvas.addEventListener('click', this.getPosClick);
}
calcularCoordenadas(event) {
const rect = this.canvas.getBoundingClientRect();
const x = Math.floor(
(event.clientX - rect.left) / (this.casillaSize * this.scale),
);
const y = Math.floor(
(event.clientY - rect.top) / (this.casillaSize * this.scale),
);
return { x, y };
}
getPosClick = (event) => {
const { x, y } = this.calcularCoordenadas(event);
console.log(x, y);
};
draw() {
super.draw();
}
}
class MapaEditor extends MapaVisor {
barcoSeleccionado;
constructor(canvas, size, scale, sprites, barcos, celdas) {
super(canvas, size, scale, sprites, barcos, celdas);
canvas.addEventListener('click', this.getPosClick);
canvas.addEventListener('contextmenu', this.giraBarcoSeleccionado);
canvas.addEventListener('mousemove', this.mueveBarcoSeleccionado);
document.addEventListener('keydown', this.handleKeyDown);
}
fijaBarco(barco) {
barco.seleccionado = false;
const incFila = barco.orientacion === 'VERTICAL' ? 1 : 0;
const incColumna = barco.orientacion === 'HORIZONTAL' ? 1 : 0;
for (let i = 0; i < barco.longitud; i++) {
const fila = barco.y + i * incFila;
const columna = barco.x + i * incColumna;
this.celdas[fila][columna] = barco.longitud;
}
this.barcos.push(barco);
}
calcularCoordenadas(event) {
const rect = this.canvas.getBoundingClientRect();
const x = Math.floor(
(event.clientX - rect.left) / (this.casillaSize * this.scale),
);
const y = Math.floor(
(event.clientY - rect.top) / (this.casillaSize * this.scale),
);
return { x, y };
}
//Acuerdate!!!! funcion de flecha en los callBack para no tener problemas con el contexto this
handleKeyDown = (event) => {
const canvasFocused = document.activeElement === this.canvas;
if (canvasFocused && event.key === 'Escape' && this.barcoSeleccionado) {
this.barcoSeleccionado.restoreIniPos();
this.posicionaBarcoSeleccionado();
}
};
//Acuerdate!!!! funcion de flecha en los callBack para no tener problemas con el contexto this
giraBarcoSeleccionado = (event) => {
event.preventDefault();
if (this.barcoSeleccionado) {
if (
this.barcoSeleccionado.x + this.barcoSeleccionado.longitud <=
this.numColumnas &&
this.barcoSeleccionado.y + this.barcoSeleccionado.longitud <=
this.numFilas
) {
this.barcoSeleccionado.giraBarco();
this.barcoSeleccionado.posIncorrecta = this.sePuedeColocar();
}
}
};
//Acuerdate!!!! funcion de flecha en los callBack para no tener problemas con el contexto this
getPosClick = (event) => {
const { x, y } = this.calcularCoordenadas(event);
if (!this.barcoSeleccionado) {
const index = this.barcos.findIndex((barco) => barco.clickado(x, y));
if (index != -1) this.seleccionaBarco(index);
} else {
this.posicionaBarcoSeleccionado();
}
};
seleccionaBarco(index_barco) {
this.barcoSeleccionado = this.barcos[index_barco];
this.barcoSeleccionado.seleccionado = true;
this.barcoSeleccionado.saveIniPos();
this.barcos.splice(index_barco, 1);
const incFila = this.barcoSeleccionado.orientacion === 'VERTICAL' ? 1 : 0;
const incColumna =
this.barcoSeleccionado.orientacion === 'HORIZONTAL' ? 1 : 0;
for (let i = 0; i < this.barcoSeleccionado.longitud; i++) {
const fila = this.barcoSeleccionado.y + i * incFila;
const columna = this.barcoSeleccionado.x + i * incColumna;
this.celdas[fila][columna] = 0;
}
}
//Acuerdate!!!! funcion de flecha en los callBack para no tener problemas con el contexto this
mueveBarcoSeleccionado = (event) => {
if (this.barcoSeleccionado) {
const { x, y } = this.calcularCoordenadas(event);
if (!this.colisionBorde(x, y)) this.barcoSeleccionado.setXY(x, y);
this.barcoSeleccionado.posIncorrecta = this.sePuedeColocar();
}
};
posicionaBarcoSeleccionado() {
if (!this.barcoSeleccionado.posIncorrecta) {
this.fijaBarco(this.barcoSeleccionado);
this.barcoSeleccionado = null;
}
}
colisionBorde(x, y) {
const barco = this.barcoSeleccionado;
const longitud = barco.longitud;
const orientacion = barco.orientacion;
return orientacion === 'VERTICAL'
? x < 0 || x >= this.numColumnas || y < 0 || y + longitud > this.numFilas
: x < 0 || x + longitud > this.numColumnas || y < 0 || y > this.numFilas;
}
sePuedeColocar() {
const x = this.barcoSeleccionado.x;
const y = this.barcoSeleccionado.y;
const longitud = this.barcoSeleccionado.longitud;
const orientacion = this.barcoSeleccionado.orientacion;
let suma = 0;
if (orientacion === 'VERTICAL') {
for (let f = -1; f <= longitud; f++) {
for (let c = -1; c < 2; c++) {
const fila = y + f;
const columna = x + c;
if (
fila >= 0 &&
fila < this.celdas.length &&
columna >= 0 &&
columna < this.celdas[0].length
) {
suma += this.celdas[fila][columna];
}
}
}
} else {
for (let f = -1; f < 2; f++) {
for (let c = -1; c <= longitud; c++) {
const fila = y + f;
const columna = x + c;
if (
fila >= 0 &&
fila < this.celdas.length &&
columna >= 0 &&
columna < this.celdas[0].length
) {
suma += this.celdas[fila][columna];
}
}
}
}
return suma;
}
esFlotaValida() {
return true;
}
draw() {
super.draw();
if (this.barcoSeleccionado) this.barcoSeleccionado.draw(this.ctx);
}
}
export { MapaBase, MapaVisor, MapaAtaque, MapaEditor };

52
public/js_game/oceano.js Normal file
View File

@ -0,0 +1,52 @@
class Oceano {
constructor(width, height, celdaSize, sprites) {
this.sprites = sprites;
this.celdaSize = celdaSize;
this.filas = Math.floor(height / celdaSize);
this.columnas = Math.floor(width / celdaSize);
this.nFramesAnim = 3;
this.animFrame = 0;
this.gameFrame = 0;
this.lastColumnIndex = this.columnas - 1;
this.lastRowIndex = this.filas - 1;
this.lastColumnX = this.lastColumnIndex * this.celdaSize;
this.lastRowY = this.lastRowIndex * this.celdaSize;
}
update() {}
draw(ctx) {
this.animFrame = Math.floor(this.gameFrame / 10) % this.nFramesAnim;
this.gameFrame++;
const frame = this.animFrame * 9;
// Dibujar los bordes superior e inferior
ctx.drawImage(this.sprites[0 + frame], 0, 0);
ctx.drawImage(this.sprites[2 + frame], this.lastColumnX, 0);
ctx.drawImage(this.sprites[6 + frame], 0, this.lastRowY);
ctx.drawImage(this.sprites[8 + frame], this.lastColumnX, this.lastRowY);
// Dibujar los bordes laterales
for (let y = 1; y < this.lastRowIndex; y++) {
ctx.drawImage(this.sprites[3 + frame], 0, y * this.celdaSize);
ctx.drawImage(
this.sprites[5 + frame],
this.lastColumnX,
y * this.celdaSize
);
}
for (let x = 1; x < this.lastColumnIndex; x++) {
ctx.drawImage(this.sprites[1 + frame], x * this.celdaSize, 0);
ctx.drawImage(this.sprites[7 + frame], x * this.celdaSize, this.lastRowY);
}
// Dibujar el contenido interno
for (let y = 1; y < this.lastRowIndex; y++) {
for (let x = 1; x < this.lastColumnIndex; x++) {
ctx.drawImage(this.sprites[4], x * this.celdaSize, y * this.celdaSize);
}
}
}
}
export default Oceano;

53
public/js_game/tablero.js Normal file
View File

@ -0,0 +1,53 @@
import { MapaVisor,MapaEditor, MapaAtaque } from './mapa.js';
class TableroBase {
constructor(canvasMapa, canvasMiniMapa,sprites){
this.canvasMapa = canvasMapa;
this.canvasMiniMapa = canvasMiniMapa;
this.sprites = sprites;
}
}
class TableroEditor extends TableroBase{
constructor(canvasMapa, canvasMiniMapa,sprites, [mapaFlota, mapaAtaques] ){
super(canvasMapa, canvasMiniMapa,sprites)
const { barcos: barcosMapaFlota, celdas: celdasMapaFlota } = mapaFlota;
const { barcos: barcosMapaAtaques, celdas: celdasMapaAtaques } = mapaAtaques;
this.mapaFlota = new MapaEditor(canvasMapa, 640, 1,sprites,barcosMapaFlota,celdasMapaFlota);
this.mapaDeAtaques = new MapaVisor(canvasMiniMapa, 320, 0.5, sprites,barcosMapaAtaques,celdasMapaAtaques);
}
draw() {
this.mapaFlota.draw();
this.mapaDeAtaques.draw();
}
}
class TableroVisor extends TableroBase{
constructor(canvasMapa, canvasMiniMapa,sprites, [mapaFlota, mapaAtaques] ){
super(canvasMapa, canvasMiniMapa,sprites)
const { barcos: barcosMapaFlota, celdas: celdasMapaFlota } = mapaFlota;
const { barcos: barcosMapaAtaques, celdas: celdasMapaAtaques } = mapaAtaques;
this.mapaFlota = new MapaVisor(canvasMiniMapa, 320, 0.5,sprites,barcosMapaFlota,celdasMapaFlota);
this.mapaDeAtaques = new MapaVisor(canvasMapa, 640, 1, sprites,barcosMapaAtaques,celdasMapaAtaques);
}
draw() {
this.mapaFlota.draw();
this.mapaDeAtaques.draw();
}
}
class TableroAtaque extends TableroBase{
constructor(canvasMapa, canvasMiniMapa,sprites, [mapaFlota, mapaAtaques] ){
super(canvasMapa, canvasMiniMapa,sprites)
const { barcos: barcosMapaFlota, celdas: celdasMapaFlota } = mapaFlota;
const { barcos: barcosMapaAtaques, celdas: celdasMapaAtaques } = mapaAtaques;
this.mapaFlota = new MapaVisor(canvasMiniMapa, 320, 0.5,sprites,barcosMapaFlota,celdasMapaFlota);
this.mapaDeAtaques = new MapaAtaque(canvasMapa, 640, 1, sprites,barcosMapaAtaques,celdasMapaAtaques);
}
draw() {
this.mapaFlota.draw();
this.mapaDeAtaques.draw();
}
}
export {TableroBase,TableroEditor,TableroVisor}

View File

@ -4,10 +4,14 @@
} }
* { * {
/* box-sizing: content-box; */
box-sizing: border-box; box-sizing: border-box;
min-width: 0; min-width: 0;
} }
h1,h2,h3,h4 { h1,
h2,
h3,
h4 {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -20,96 +24,165 @@ body {
} }
body { body {
padding: 1rem;
background: linear-gradient(to bottom right, #0f2027, #203a43, #2c5364); background: linear-gradient(to bottom right, #0f2027, #203a43, #2c5364);
color: white;
font-family: 'ITC Machine Std Bold', sans-serif; font-family: 'ITC Machine Std Bold', sans-serif;
text-align: center; color: #bf360c;
}
#container {
height: 100%;
display: flex; display: flex;
flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 0.5rem;
} }
#sub-container { /* Estilo base para los botones */
height: 648px; .button {
display: flex; width: 100%;
flex-direction: column;
border: 4px solid #2c5364;
border-radius: 10px;
overflow: hidden;
}
#input-container {
display: flex;
padding: 1rem;
gap: 0.4rem;
max-width: fit-content;
flex-direction: column;
border: 4px solid #2c5364;
border-radius: 10px;
overflow: hidden;
}
/* Estilo del botón */
#input-container input[type="button"] {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
font-size: 1rem; font-family: 'ITC Machine Std Bold', sans-serif;
font-size: 2rem;
border: none; border: none;
border-radius: 0.4rem; border-radius: 0.4rem;
background-color: #ff5722; /* Color de fondo naranja */ cursor: pointer;
color: white; /* Color del texto blanco */ transition: background-color 0.3s ease;
cursor: pointer; /* Cambia el cursor al pasar sobre el botón */
transition: background-color 0.3s ease; /* Transición suave al cambiar de color */
} }
/* Estilo del botón al pasar el cursor */ /* Estilo para el botón naranja */
#input-container input[type="button"]:hover { .button-orange {
background-color: #e64a19; /* Color de fondo naranja más oscuro al pasar el cursor */ background-color: #ff5722;
} }
/* Estilo del botón al hacer clic */ /* Estilo para el botón naranja claro al pasar el cursor */
#input-container input[type="button"]:active { .button-orange:hover {
background-color: #bf360c; /* Color de fondo naranja más oscuro al hacer clic */ background-color: #e64a19;
} }
/* Estilo para el botón naranja oscuro al hacer clic */
.button-orange:active {
background-color: #bf360c;
}
.avisoMsg {
width: 100%;
text-align: center;
margin: auto;
font-size: 3rem;
}
.parpadea {
animation-name: parpadeo;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
-webkit-animation-name: parpadeo;
-webkit-animation-duration: 2s;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
}
.parent {
height: 744px;
display: grid;
grid-template-columns: min-content min-content;
grid-template-rows: auto 328px 55px auto;
grid-column-gap: 4px;
}
.div1 {
grid-area: 1 / 1 / 2 / 3;
}
.div2 {
grid-area: 2 / 1 / 5 / 2;
width: 648px;
height: 648px;
border: 4px solid #2c5364;
border-radius: 10px;
}
.div3 {
grid-area: 2 / 2 / 3 / 3;
width: 328px;
height: 328px;
border: 4px solid #2c5364;
border-radius: 10px;
}
.div4 {
grid-area: 3 / 2 / 4 / 3;
display: flex;
padding: 0.2rem;
}
.div5 {
grid-area: 4 / 2 / 5 / 3;
border: 4px solid #2c5364;
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 0.4rem;
overflow-y: hidden;
}
#mapa { #mapa {
width: 640px; width: 640px;
height: 640px; height: 640px;
background-color: #2c5364; background-color: #2c5364;
} }
#minimapa { #minimapa {
width: 320px; width: 320px;
height: 320px; height: 320px;
flex-shrink: 0; flex-shrink: 0;
background-color: #2c5364; background-color: #2c5364;
} }
#logchat {
#chat { width: 100%;
font-family: 'ITC Machine Std Bold', sans-serif;
resize: none;
width: 320px;
height: 100%; height: 100%;
padding: 0.1rem;
padding-right: 0.4rem;
font-family: 'roboto', sans-serif;
font-size: small;
font-weight: bold;
border-radius: 0.4rem;
background-color: transparent; background-color: transparent;
color: antiquewhite; overflow-y: auto;
}
#logchat p {
margin: 0;
}
#chatinput {
font-family: 'roboto', sans-serif;
padding: 0.4rem;
font-weight: bold;
border-radius: 0 0 0.4rem 0.4rem;
background-color: transparent;
color: wheat;
outline: none;
} }
.basic-input{ @-moz-keyframes parpadeo {
font-family: 'ITC Machine Std Bold', sans-serif; 0% {
padding: 0.4rem; opacity: 1;
font-size: larger; }
border-radius: 0.4rem; 50% {
background-color: #2c5364; opacity: 0;
color:wheat; }
outline: none; 100% {
opacity: 1;
}
}
} @-webkit-keyframes parpadeo {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes parpadeo {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}

View File

@ -1,19 +1,41 @@
import { OnGatewayConnection, OnGatewayDisconnect, WebSocketGateway } from '@nestjs/websockets'; import {
OnGatewayConnection,
OnGatewayDisconnect,
SubscribeMessage,
WebSocketGateway,
} from '@nestjs/websockets';
import { BatallaService } from './batalla.service'; import { BatallaService } from './batalla.service';
import { Socket } from 'socket.io'; import { Socket } from 'socket.io';
import Barco from 'src/battleship/barco';
@WebSocketGateway({ namespace: 'batalla' }) @WebSocketGateway({ namespace: 'batalla' })
export class BatallaGateway implements OnGatewayConnection, OnGatewayDisconnect { export class BatallaGateway
implements OnGatewayConnection, OnGatewayDisconnect
{
constructor(private readonly batallaService: BatallaService) {} constructor(private readonly batallaService: BatallaService) {}
handleConnection(client: Socket) { handleConnection(client: Socket) {
const {userId,gameId}=client.handshake.auth const { userId, gameId } = client.handshake.auth;
if (this.batallaService.existePartidaUsuario(gameId,userId)){
client.emit('OnChangeState',this.batallaService.getSnapshotJugador(gameId,userId));
}else{
client.disconnect();
}
}
handleDisconnect(client: Socket) {}
@SubscribeMessage('sendFlota')
handleMsg(client: Socket, barcos:Barco[]) {
const { userId, gameId } = client.handshake.auth;
console.log(barcos);
console.log(barcos[0] instanceof Barco);
const snapshotJugador = this.batallaService.getSnapshotJugador(gameId,userId);
snapshotJugador.prepararFlota(barcos);
} }
handleDisconnect(client: Socket) {
}
} }

View File

@ -5,7 +5,18 @@ import { UsuariosService } from 'src/shared/usuarios.service';
@Injectable() @Injectable()
export class BatallaService { export class BatallaService {
constructor( constructor(
private readonly usuariosService: UsuariosService,
private readonly partidasService: PartidasService, private readonly partidasService: PartidasService,
) {} ) {}
existePartidaUsuario(uuidPartida:string,uuidJugador:string){
return this.partidasService.existePartida(uuidPartida,uuidJugador);
}
getSnapshotJugador(uuidPartida:string,uuidJugador:string){
return this.partidasService.getSnapshotJugador(uuidPartida,uuidJugador);
}
} }

View File

@ -13,7 +13,8 @@ export default class Barco {
public longitud: number, public longitud: number,
public orientacion: string, public orientacion: string,
public impactos: number = 0, public impactos: number = 0,
public destruido = false, public destruido: boolean = false,
public tipoNave: string = '',
) {} ) {}
recibirImpacto() { recibirImpacto() {
@ -26,4 +27,14 @@ export default class Barco {
haSidoDestruido(): boolean { haSidoDestruido(): boolean {
return this.destruido; return this.destruido;
} }
toJSON() {
return {
x: this.x,
y: this.y,
longitud: this.longitud,
orientacion: this.orientacion,
tipoNave: this.tipoNave,
};
}
} }

View File

@ -1,55 +1,17 @@
import Barco from './barco';
import Jugador from './jugador'; import Jugador from './jugador';
export default class BattleshipGame { export default class BattleshipGame {
public jugadorA: Jugador | null = null; public jugadorA: Jugador;
public jugadorB: Jugador | null = null; public jugadorB: Jugador;
turnoActual: Jugador | null; turnoActual: Jugador | null;
constructor(public idPartida: string) { constructor() {
this.turnoActual = null; this.turnoActual = null;
this.jugadorA=new Jugador();
this.jugadorB=new Jugador();
this.turnoActual=this.jugadorA;
} }
setJugadorA(jugador: Jugador) {
this.jugadorA = jugador;
}
setJugadorB(jugador: Jugador) {
this.jugadorB = jugador;
}
iniciaPartida() {
this.turnoActual = this.jugadorA;
// Iniciar el primer turno
this.realizarTurno();
}
realizarTurno() {
// Realizar las acciones correspondientes al turno actual
// Por ejemplo, mostrar el mapa del turno actual, solicitar un disparo, etc.
// Implementa esta parte según sea necesario
// Luego, alternar el turno al otro jugador
this.turnoActual =
this.turnoActual === this.jugadorA ? this.jugadorB : this.jugadorA;
// Verificar si se ha alcanzado el final del juego
if (this.haFinalizado()) {
this.finalizaPartida();
} else {
// Si no ha finalizado, continuar con el próximo turno
this.realizarTurno();
}
}
haFinalizado(): boolean {
// Aquí debes implementar la lógica para verificar si el juego ha finalizado
// Por ejemplo, si todos los barcos de uno de los jugadores han sido destruidos
// Devuelve true si el juego ha finalizado, de lo contrario, devuelve false
// Implementa esta parte según sea necesario
return false;
}
finalizaPartida() {
// Aquí debes implementar la lógica para finalizar el juego
// Por ejemplo, mostrar el resultado (quién ganó, etc.)
// Implementa esta parte según sea necesario
}
} }

View File

@ -5,35 +5,72 @@ export default class Jugador {
public mapaFlota: Mapa = new Mapa(); public mapaFlota: Mapa = new Mapa();
public mapaDeAtaques: Mapa = new Mapa(); public mapaDeAtaques: Mapa = new Mapa();
public jugadorPreparado: boolean = false; public estado: string = 'ENPREPARACION';
public barcos: Barco[] = [ public barcos: Barco[] = [
new Barco(1, 0, 0, BarcoTipo.PORTAAVIONES, 'VERTICAL'), new Barco(
new Barco(2, 1, 0, BarcoTipo.ACORAZADO, 'VERTICAL'), 1,
new Barco(3, 2, 0, BarcoTipo.ACORAZADO, 'VERTICAL'), 0,
new Barco(4, 3, 0, BarcoTipo.ACORAZADO, 'VERTICAL'), 0,
new Barco(5, 4, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'), BarcoTipo.PORTAAVIONES,
new Barco(6, 5, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'), 'VERTICAL',
new Barco(7, 6, 0, BarcoTipo.DESTRUCTOR, 'VERTICAL'), 0,
new Barco(8, 7, 0, BarcoTipo.FRAGATA, 'VERTICAL'), false,
new Barco(9, 8, 0, BarcoTipo.FRAGATA, 'VERTICAL'), 'PORTAAVIONES',
),
new Barco(2, 1, 0, BarcoTipo.ACORAZADO, 'VERTICAL', 0, false, 'ACORAZADO'),
new Barco(3, 2, 0, BarcoTipo.ACORAZADO, 'VERTICAL', 0, false, 'ACORAZADO'),
new Barco(4, 3, 0, BarcoTipo.ACORAZADO, 'VERTICAL', 0, false, 'ACORAZADO'),
new Barco(
5,
4,
0,
BarcoTipo.DESTRUCTOR,
'VERTICAL',
0,
false,
'DESTRUCTOR',
),
new Barco(
6,
5,
0,
BarcoTipo.DESTRUCTOR,
'VERTICAL',
0,
false,
'DESTRUCTOR',
),
new Barco(
7,
6,
0,
BarcoTipo.DESTRUCTOR,
'VERTICAL',
0,
false,
'DESTRUCTOR',
),
new Barco(8, 7, 0, BarcoTipo.FRAGATA, 'VERTICAL', 0, false, 'FRAGATA'),
new Barco(9, 8, 0, BarcoTipo.FRAGATA, 'VERTICAL', 0, false, 'FRAGATA'),
]; ];
constructor(public nickname: string) {} constructor() {
this.mapaFlota.setBarcos(this.barcos);
}
prepararFlota(barcos: Barco[]) { prepararFlota(barcos: Barco[]) {
this.barcos = barcos; this.barcos = barcos;
this.mapaFlota.setBarcos(this.barcos); this.mapaFlota.setBarcos(this.barcos);
this.jugadorPreparado = true;
} }
setBarcos(barcos: Barco[]) {
this.mapaFlota.setBarcos(barcos);
}
realizarDisparo(x: number, y: number, rival: Jugador): boolean { realizarDisparo(x: number, y: number, rival: Jugador): boolean {
const acierto = rival.mapaFlota.verificaDisparo(x, y); const acierto = rival.mapaFlota.verificaDisparo(x, y);
this.mapaDeAtaques.marcaDisparo(x,y,acierto ? EstadoCelda.Golpe : EstadoCelda.Agua); this.mapaDeAtaques.marcaDisparo(
x,
y,
acierto ? EstadoCelda.Golpe : EstadoCelda.Agua,
);
return acierto; return acierto;
} }
@ -46,4 +83,11 @@ export default class Jugador {
return true; return true;
} }
toJSON() {
return {
mapaFlota: this.mapaFlota,
mapaDeAtaques: this.mapaDeAtaques,
estado: this.estado,
};
}
} }

View File

@ -5,10 +5,14 @@ export enum EstadoCelda {
Agua = -1, Agua = -1,
Golpe = -2, Golpe = -2,
} }
export default class Mapa { export default class Mapa {
celdas: number[][] = []; celdas: number[][] = [];
barcosMapa: Map<number, Barco> = new Map<number, Barco>(); barcosMapa: Map<number, Barco> = new Map<number, Barco>();
get barcos() {
return Array.from(this.barcosMapa.values());
}
constructor() { constructor() {
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
this.celdas[i] = []; this.celdas[i] = [];
@ -18,6 +22,10 @@ export default class Mapa {
} }
} }
toJSON() {
return { celdas: this.celdas, barcos: this.barcos };
}
setBarcos(barcos: Barco | Barco[]) { setBarcos(barcos: Barco | Barco[]) {
const barcosArray = Array.isArray(barcos) ? barcos : [barcos]; const barcosArray = Array.isArray(barcos) ? barcos : [barcos];
for (const barco of barcosArray) { for (const barco of barcosArray) {
@ -44,8 +52,8 @@ export default class Mapa {
return null; return null;
} }
marcaDisparo(x:number,y:number,valor:number){ marcaDisparo(x: number, y: number, valor: number) {
this.celdas[x][y]=valor; this.celdas[x][y] = valor;
} }
getInformacionBarcos(): Barco[] { getInformacionBarcos(): Barco[] {
@ -54,7 +62,7 @@ export default class Mapa {
verificaDisparo(x: number, y: number): boolean { verificaDisparo(x: number, y: number): boolean {
if (this.celdas[x][y] > 0) { if (this.celdas[x][y] > 0) {
const barco = this.getBarcoEnCelda(x,y); const barco = this.getBarcoEnCelda(x, y);
if (barco) { if (barco) {
barco.recibirImpacto(); barco.recibirImpacto();
this.celdas[x][y] = EstadoCelda.Golpe; this.celdas[x][y] = EstadoCelda.Golpe;

View File

@ -1,16 +1,29 @@
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { UsuariosService } from './usuarios.service'; import { UsuariosService } from './usuarios.service';
import BattleshipGame from 'src/battleship/battleship';
export class Partida { export class Partida {
constructor( constructor(
public uuid: string, public uuid: string,
public uuidJugadorA: string, public uuidJugadorA: string,
public nickJugadorA: string = '', public nickJugadorA: string = null,
public uuidJugadorB: string = null, public uuidJugadorB: string = null,
public nickJugadorB: string = null, public nickJugadorB: string = null,
public abierta: boolean = true, public abierta: boolean = true,
public batalla: BattleshipGame = null,
) {} ) {}
toJson() {
return {
uuid: this.uuid,
uuidJugadorA: this.uuidJugadorA,
nickJugadorA: this.nickJugadorA,
uuidJugadorB: this.uuidJugadorB,
nickJugadorB: this.nickJugadorB,
abierta: this.abierta,
};
}
} }
@Injectable() @Injectable()
@ -18,19 +31,16 @@ export class PartidasService {
private _partidas: Map<string, Partida> = new Map<string, Partida>(); private _partidas: Map<string, Partida> = new Map<string, Partida>();
constructor(private readonly usuariosService: UsuariosService) {} constructor(private readonly usuariosService: UsuariosService) {}
get partidasAbiertas(): Partida[] { get partidasAbiertas(): Partida[] {
return Array.from(this._partidas.values()).filter( return Array.from(this._partidas.values()).filter(
(partida) => partida.abierta, (partida) => partida.abierta,
); );
} }
get partidasCerradadas(): Partida[] { get partidasCerradadas(): Partida[] {
return Array.from(this._partidas.values()).filter( return Array.from(this._partidas.values()).filter(
(partida) => !partida.abierta, (partida) => !partida.abierta,
); );
} }
creaPartida(uuidJugadorA: string) { creaPartida(uuidJugadorA: string) {
const uuid = uuidv4(); const uuid = uuidv4();
const nickJugadorA = const nickJugadorA =
@ -39,16 +49,16 @@ export class PartidasService {
this._partidas.set(uuid, partida); this._partidas.set(uuid, partida);
return partida; return partida;
} }
unirsePartida(uuidJugadorB: string, uuidPartida: string) {
unirsePartida(uuidJugadorB: string, uuidPartida: string){
const partida = this._partidas.get(uuidPartida); const partida = this._partidas.get(uuidPartida);
const nickJugadorB = this.usuariosService.usuarios.get(uuidJugadorB)?.nickname; const nickJugadorB =
this.usuariosService.usuarios.get(uuidJugadorB)?.nickname;
partida.uuidJugadorB = uuidJugadorB; partida.uuidJugadorB = uuidJugadorB;
partida.nickJugadorB = nickJugadorB; partida.nickJugadorB = nickJugadorB;
partida.abierta = false; partida.abierta = false;
partida.batalla = new BattleshipGame();
return partida; return partida;
} }
eliminarPartida(uuidJugador: string, uuidPartida: string) { eliminarPartida(uuidJugador: string, uuidPartida: string) {
if (!this._partidas.has(uuidPartida)) { if (!this._partidas.has(uuidPartida)) {
return null; return null;
@ -63,5 +73,22 @@ export class PartidasService {
this._partidas.delete(uuidPartida); this._partidas.delete(uuidPartida);
return uuidPartida; return uuidPartida;
} }
existePartida(uuidPartida: string, uuidJugador: string): boolean {
if (!this._partidas.has(uuidPartida)) {
return false;
}
const partida = this._partidas.get(uuidPartida);
return (partida.uuidJugadorA === uuidJugador || partida.uuidJugadorB === uuidJugador)
}
getSnapshotJugador(uuidPartida: string, uuidJugador: string){
if (this.existePartida(uuidPartida,uuidJugador)){
const partida=this._partidas.get(uuidPartida);
return partida.uuidJugadorA === uuidJugador ? partida.batalla.jugadorA : partida.batalla.jugadorB;
}
return null;
}
} }