Anteriormente parte 1
VIENDO EL ARCHIVO MAIN.JS
Recordemos que nuestro principal objetivo es tener una aplicación donde exista una grilla de cuadrados los cuales pueden ser pintados desde un menú de colores haciendo click en un color y luego click en el cuadrado que se desea pintar, esto debe ser comunicado a los demás clientes que se hayan conectado a nuestra aplicación, además cualquier cliente puede nuevamente pintar el mismo cuadrado; recordemos que una condición es que esta grilla se pueda renderizar de forma adecuada sin importar el dispositivo, la dimensión y el aspecto está totalmente controlado por P5Js; sin embargo, P5Js hace uso de valores absolutos en pixeles tal que si definimos que un cuadrado tenga 120×120 pixeles en un computador de mesa podría verse bien dada las dimensiones del mismo, pero eso no ocurriría en un teléfono móvil; para ello debemos hacer uso de ciertos artilugios que permitan la renderización .
MANOS AL CÓDIGO
Lo primero entonces es declarar una serie de variables globales las cuáles serán accesibles en todo la aplicación por lo mismo que son globales, entonces:
var socket=io();
var dx=5*window.innerWidth/6; //variable general del ancho
var dy=5*window.innerHeight/6; //variable general del alto
Cuando se realizó la comunicación desde el servidor con socket.io() este puso a disposición un socket que nos permitirá emitir y escuchar eventos, luego de ello debemos de trabajar en función de proporciones, window.innerWidth y window.innerHeight nos da la dimensión en ancho y alto de la ventana de la ventana del dispositivo, de ello nuestra aplicación cogerá los 5/6. Si dx y dy son las dimensiones de nuestra aplicación, podemos entonces segmentarla como un grilla, tal que en vertical sean once espacios y en horizontal sean 10 espacios:

var grilla_y=11;
var grilla_x=10;
Podemos obtener la dimensión de cada grilla haciendo:
var w_c=dx/grilla_x; // variable del ancho de un cuadrado
var h_c=dy/grilla_y; //variable del alto de un cuadrado
Como hemos de crear una grilla de cuadrados, lo ideal es almacenarlo en un arreglo, tal que podamos acceder a su posición, así también recordemos que los cuadrados tienen como propiedad un id que tiene la misma estructura de la posición en el arreglo:
var malla_cuadrados=[]; //cuadrícula de cuadrados
var mando_colores=[]; // cuadrícula de botones de asignación de color
Finalmente creamos una variable global relacionada al color sin inicializar, y su función principal es almacenar y comunicar el color que se ha elegido
P5Js tiene dos funciones básicas principales, setup y draw, la primera es llamada cuando el programa inicia y es la encargada de inicializar todas las variables o configuraciones de entorno que nuestra aplicación requiera, la segunda es la encargada de ejecutar infinitamente el código que se inserte en el, lo cual será de mucha utilidad cuando se tenga que repintar un cuadrado ante un cambio de color.
Función Setup
Lo primero que debemos hacer en esta función es crear el canvas, el canvas es el lienzo sobre el cual se ha de dibujar todos nuestros elementos:
let canvas=seteo_canvas(dx,dy);
¿Pero qué hace la función seteo_canvas(), como observamos recibe la dimensión de nuestra aplicación y hace lo siguiente:
function seteo_canvas(){
let canvas=createCanvas(dx,dy);
let posx=(windowWidth-width)/2;
let posy=(windowHeight-height)/2;
canvas.position(posx, posy);
canvas.parent("juego");
return canvas
}
P5Js usa el método createCanvas que recibe las dimensiones del canvas, si lo dejamos tal cual, posicionará el canvas en la esquina superior izquierda creando un nuevo tag canvas, pero queremos controlar ello, esto lo hacemos indicando la posición tanto en X e Y usando las variables que nos proporciona P5Js que son windowWidth que nos da el ancho de la ventana y width que nos proporciona el ancho de nuestra aplicación, similar a lo que hicimos para hallar dx, solo que en términos de P5Js y que con el método position le daríamos una posición, finalmente lo asociamos al tag main de nuestro index.html a través del método parent que recibe un id y devolvemos un canvas ya configurado.
Luego de crear el canvas debemos de crear la grilla de cuadrados, al ser una grilla posicionarlo se hará a través de un bucle for anidado tal que en cada iteración del bucle anidado se genere una instancia de la clase cuadrados y se guarde en malla_cuadrados:
for(fila=0;fila<grilla_y-1;fila++){
for(columna=0;columna<grilla_x;columna++){
let c=new Cuadrados(w_c/2+w_c*columna,h_c/2+h_c*fila,w_c,h_c,fila,columna);
malla_cuadrados.push(c);
}
}
Observemos 1 cuadrado:
let c=new Cuadrados(w_c/2+w_c*columna,h_c/2+h_c*fila,w_c,h_c,fila,columna);
Cada w_c es un segmento de la grilla, como el cuadrado está centrado le damos como primera posición la mitad de un segmento de grilla, y el cual aumenta en un segmento en cada iteración de columna, de forma similar con la posición Y solo que con la fila. Observamos además que la grilla es de 10×10, ya que el último nivel lo reservamos para el menú de colores.
Función menu_colores
Vamos a crear una línea divisoria haciendo uso de la función line(), le asignamos la posición inferior un grosor de línea de 4 (strokeWeight) y un color con stroke(), también una lista de colores en formato RGB haciendo uso de color, y finalmente tan igual que la creación de cuadrados, los creamos a través del uso de bucle for.
function menu_colores(){
//Línea divisoria
stroke(155,56,89);//color de línea
strokeWeight(4);
line(0, (grilla_y-1)*h_c-2,grilla_x*w_c,(grilla_y-1)*h_c-2);
//Fin de línea divisoria
//cuadrados de mando
strokeWeight(1);
noStroke();
lista_colores=[color(19,22,76),color(19,76,40),color(196,47,11),color(242,245,2),color(255)]
for (let i = 0; i < 5; i++) {
fill(lista_colores[i]);
rectMode(CENTER);
let rectangulo=rect(w_c/2+(w_c)*i, (grilla_y-1)*h_c+h_c/2, w_c, h_c);
mando_colores.push(rectangulo);
}
}
Función Draw
Recordemos que draw es la función que va iterar infinitamente, por ende es la encargada de la actualización de estado de nuestros cuadrados los cuáles cambiarán de color, para ello debemos de dibujar los cuadrados, para dibujar los cuadrados tenemos el método de la clase que es dibujar cuadrado, luego de ello dibujamos el menú de colores:
function draw(){
malla_cuadrados.forEach(cuadrado=>{
cuadrado.dibujarCuadrado();
});
menu_colores();
}
Hemos utilizado el bucle forEach el cual recorrerá por cada elemento (que es un cuadrado) y llamará al método dibujar cuadrado, luego se ejecutará la función de los colores. Hasta este punto solo tendremos la grilla de cuadrados y el menú de de colores puestos en la escena, Ahora debemos de estar a la escucha de los eventos, para ello P5Js puede registrar una serie de eventos relacionados al ratón, ¿Cuál de esos eventos necesitamos?, pues el evento que sucede cuando el botón del ratón ha sido presionado y suelto el cual se registra en la función mouseClicked().
Función mouseClicked
Al no ser un botón, no se puede asignar un “listener“, y mouseClicked registrará cualquier evento que implique un presionar y soltar del ratón en toda la pantalla, debemos de ser un poco más creativos para determinar cuando se presionó un cuadrado específico o si fue el cuadro de colores, para ello ante el evento debemos de rastrear toda la grilla, tanto de cuadrados como de colores y determinar la posición del ratón en X e Y de donde se generó el evento:
function mouseClicked(){
//Grid de cuadrados
for(let fila=0;fila<(dy/h_c)-1;fila++){
for(let columna=0;columna<dx/w_c;columna++){
if((w_c*columna<mouseX && mouseX<w_c*(columna+1)) &&(h_c*fila<mouseY && mouseY<h_c*(fila+1))){
//console.log(" fila: ", fila+1," columna: ",columna+1 );
let pos_aux=columna+(grilla_y-1)*fila;
let aux_x=malla_cuadrados[pos_aux].x;
let aux_y=malla_cuadrados[pos_aux].y;
let aux_cuadrado=new Cuadrados(aux_x,aux_y,w_c,h_c,fila,columna,color_actual);
aux_cuadrado.dibujarCuadrado();
malla_cuadrados[pos_aux]=aux_cuadrado;
//el socekt emite
socket.emit("dibujar",{id:pos_aux,mi_color:malla_cuadrados[pos_aux].mi_color}) ;
//console.log(malla_cuadrados[pos_aux].id);
}
}
}
//Grid de mandos
colores=[{r:19,g:22,b:76},{r:19,g:76,b:40},{r:196,g:47,b:11},{r:242,g:245,b:2},{r:255,g:255,b:255}];
if(mouseY>(grilla_y-1)*h_c && mouseY<grilla_y*h_c){
for(let columna=0;columna<dx/w_c;columna++){
if(w_c*columna<mouseX && mouseX<w_c*(columna+1)){
color_actual=colores[columna];
//console.log(color_actual); revisamos si el color actual está cambiando
}
}
}
}
En la grilla de cuadrados hemos ejecutado el doble bucle for, note el artilugio sobre la condición del límite (dv/h_c)-1, dv: es el área de trabajo, y h_c: es un segmento de la grilla, esta división y resta posterior es 10, ¿Por qué usar esta forma y no 10 a secas?, pues porque tu grilla puede variar, así no tendrías que estar modificando todo el código, de forma similar ocurre con (dx/w_c). Ahora revisemos el condicional, como deseamos saber la posición del ratón, esta la podemos obtener con los eventos mouseX y mouseY de P5Js, pero no solo ello, también si está en un segmento específico de la grilla, es por ello que tenemos w_c*columna y h_c*fila, ¿Por qué en un condicional?, pues porque podemos hacer click fuera del área de trabajo, debemos asegurar que el click se hizo dentro del área de trabajo y en un cuadrado específico, cuando obtenemos ello, almacenamos la posición, la posición la buscamos dentro de malla cuadrados obteniendo la posición X e Y, creamos un nuevo cuadrado en la misma posición, fila y columna, con un detalle, ahora sí agregamos el parámetro del color asignando el valor de la variable color_actual, esto lo hacemos el siguiente fin, recordemos que color_actual tiene como función almacenar un color, por defecto es blanco y solo varía cuando un color del cuadro de colores ha sido seleccionado, esto responde a la siguiente dinámica:
“El usuario selecciona un color modificando el valor de color_actual, el usuario luego de seleccionar un color, selecciona un cuadrado de la grilla para modificar el color, se modifica el color creando una nueva instancia de cuadrado asignando como parámetro de color el valor de la variable color_actual”
Cuando se crea una instancia de cuadrado esta reemplaza al cuadrado anterior en su posición en el arreglo de malla_cuadrados. Vemos ya en acción el registro del evento emit, vamos a emitir “dibujar“ enviando al servidor para que retransmita a todos los clientes el cambio de color en una posición indicada que se almacena en la propiedad id.
En la grilla de mandos o cuadro de colores, la misma dinámica de detección de la posición del ratón; sin embargo, tenemos un arreglo de colores que en función de la posición iremos asignando a la variable global color_actual.
El socket a la Escucha del evento personalizado
Hasta el momento hemos localizado la posición donde se genera un evento, hemos comunicado el evento y sus parámetros a los demás clientes, pero también la siguiente perspectiva en que un mismo clientes está emitiendo y estando a la escucha de los eventos registrados, esto ya lo habíamos revisado en el servidor, toca entonces en el cliente poner a la escucha, sabemos que el evento registrado es “redibujar“
socket.on("redibujar",(datos)=>{
console.log(datos);
malla_cuadrados.forEach(cuadrado=>{
if(cuadrado.id==datos.id){
cuadrado.mi_color=datos.mi_color;
}
})
})
Cuando el evento es comunicado el cliente recibe los datos y recorre el arreglo de malla_cuadrados, buscando a través del id, cuando estos sean iguales, modificaremos la propiedad mi_color del cuadrado asignado.
Esto resuelve de forma completa nuestra aplicación, espero que haya sido de su agrado.