Los dos formularios no tienen los botones de control del formulario los cuales son: cerrar, minimizar y maximizar.
Para el cierre del formulario Cliente se colo un botón cerrar para que cierre este formulario y el formulario del servidor.
En el formulario del Cliente tiene otros tres botones los cuales son:
Generar: Permite cambiar la posición de los barcos en el picturebox, activa el botón jugar
Conectar: Realiza la conexión con el Servidor especificando la Ip de este, permite activar el botón generar y se bloquea a el mismo.
Jugar: Permite comenzar el juego, y bloqueando los botones activos
En el servidor solo existe el botón generar el cual permitirá cambiar la posición de los barcos, este botón se bloqueará cuando se comience el juego.
Cada formulario tiene dos picturebox el uno es el radar el cual es el que esta ubicado a la izquierda y el de la posición de los barcos es el de la derecha, en el radar se ubicará si se golpeo o no el disparo.
BATTLE SHIP EN C# PROYECTO 01 APLICACIONES DISTRIBUÍDAS
El famoso juego de Battle Ship en C# utilizando los conocimientos de conexiones Cliente-Servidor para hacer de este divertido juego, que pueda ser una aplicación distribuida en la red...!!!
domingo, 22 de septiembre de 2013
sábado, 21 de septiembre de 2013
¿Cómo realizamos el envío de datos de Cliente-Servidor?
El envío y la recepción de datos se la realizó mediante la lectura y escritura de flujos binarios. Ya que de esta manera no nos preocupamos de como se empaqueten los datos.
Lo único que debemos preocuparnos es de que tal como se envían los datos se deben recibir en este mismo orden, ya que es un flujo binario de datos.
Para ello se ocupó las funciones Comunicaciones y Enviar.
En el servidor:
public void Comunicaciones()
{
//string Ip = ConfigurationManager.AppSettings["ip"].ToString();
//Obtenemos el numero de puerto del archivo de configuracion
string puerto = ConfigurationManager.AppSettings["puerto"].ToString();
//Inicializamos el TcpListener
escuchar = new TcpListener(IPAddress.Any, Convert.ToInt32(puerto));
//Comenzamos a escuchar por conexiones
escuchar.Start();
//Aceptamos una una conexion
cliente = escuchar.AcceptTcpClient();
//Comprobamos que este conectado
if (cliente.Connected)
{
MessageBox.Show("Cliente conectado", "Mensaje", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos una funcion para desbloquear el boton generar
Invoke(new Desbloquea(DesbloquearControles));
}
//creamos un string para recibir el tipo de informacion
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
}
//Esta funcion permite comprobar si el disparo golpeo un barco
public bool Disparo(int x, int y)
{
//creamos un tipo punto
Point p = new Point(picPosicion.Location.X + (x * 30), picPosicion.Location.Y + (y * 30));
//hacemos un foreach para buscar entre los barcos
foreach (Barco barco in barcos)
{
//Cargamos la propiedad Puntos, para hacer la comprobacion
Point[] valor = barco.Puntos;
//hacemos un foreach dentro del arreglo anteriormente obtenido
foreach (Point p2 in valor)
{
//Comprobamos si los puntos son iguales
if (p2 == p)
{
//Esto comprobamos que no sea en el mismo punto el golpe
int i = 0;
foreach (Point punto in barco.PuntosGolpe)
{
if (punto == p)
{
i++;
}
}
//Si no se ha dado anteriormente un golpe se disminuye los puntos de vida
if (i == 0)
{
MessageBox.Show("Te Golpearon", "Peligro", MessageBoxButtons.OK, MessageBoxIcon.Hand);
barco.PuntosVida--;
barco.PuntosGolpe.Add(p);
}
return true;
}
}
}
return false;
}
//Esta funcion nos permite enviar mensajes al servidor
public void Enviar(string mensaje, int x, int y)
{
//Creamos un binaryWriter para enviar datos
BinaryWriter datos = new BinaryWriter(new BufferedStream(cliente.GetStream()));
//Enviamos los datos de acuerdo al siguiente orden
datos.Write(mensaje);
datos.Write(x);
datos.Write(y);
datos.Flush();
}
En el cliente:
//Esta funcion nos permite enviar mensajes al servidor
public void Enviar(string mensaje, int x, int y)
{
//Creamos un binaryWriter para enviar datos
BinaryWriter datos = new BinaryWriter(new BufferedStream(cliente.GetStream()));
//Enviamos los datos de acuerdo al siguiente orden
datos.Write(mensaje);
datos.Write(x);
datos.Write(y);
datos.Flush();
}
Lo único que debemos preocuparnos es de que tal como se envían los datos se deben recibir en este mismo orden, ya que es un flujo binario de datos.
Para ello se ocupó las funciones Comunicaciones y Enviar.
En el servidor:
public void Comunicaciones()
{
//string Ip = ConfigurationManager.AppSettings["ip"].ToString();
//Obtenemos el numero de puerto del archivo de configuracion
string puerto = ConfigurationManager.AppSettings["puerto"].ToString();
//Inicializamos el TcpListener
escuchar = new TcpListener(IPAddress.Any, Convert.ToInt32(puerto));
//Comenzamos a escuchar por conexiones
escuchar.Start();
//Aceptamos una una conexion
cliente = escuchar.AcceptTcpClient();
//Comprobamos que este conectado
if (cliente.Connected)
{
MessageBox.Show("Cliente conectado", "Mensaje", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos una funcion para desbloquear el boton generar
Invoke(new Desbloquea(DesbloquearControles));
}
//creamos un string para recibir el tipo de informacion
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
}
//Esta funcion permite comprobar si el disparo golpeo un barco
public bool Disparo(int x, int y)
{
//creamos un tipo punto
Point p = new Point(picPosicion.Location.X + (x * 30), picPosicion.Location.Y + (y * 30));
//hacemos un foreach para buscar entre los barcos
foreach (Barco barco in barcos)
{
//Cargamos la propiedad Puntos, para hacer la comprobacion
Point[] valor = barco.Puntos;
//hacemos un foreach dentro del arreglo anteriormente obtenido
foreach (Point p2 in valor)
{
//Comprobamos si los puntos son iguales
if (p2 == p)
{
//Esto comprobamos que no sea en el mismo punto el golpe
int i = 0;
foreach (Point punto in barco.PuntosGolpe)
{
if (punto == p)
{
i++;
}
}
//Si no se ha dado anteriormente un golpe se disminuye los puntos de vida
if (i == 0)
{
MessageBox.Show("Te Golpearon", "Peligro", MessageBoxButtons.OK, MessageBoxIcon.Hand);
barco.PuntosVida--;
barco.PuntosGolpe.Add(p);
}
return true;
}
}
}
return false;
}
//Esta funcion nos permite enviar mensajes al servidor
public void Enviar(string mensaje, int x, int y)
{
//Creamos un binaryWriter para enviar datos
BinaryWriter datos = new BinaryWriter(new BufferedStream(cliente.GetStream()));
//Enviamos los datos de acuerdo al siguiente orden
datos.Write(mensaje);
datos.Write(x);
datos.Write(y);
datos.Flush();
}
En el cliente:
//Esta funcion nos permite enviar mensajes al servidor
public void Enviar(string mensaje, int x, int y)
{
//Creamos un binaryWriter para enviar datos
BinaryWriter datos = new BinaryWriter(new BufferedStream(cliente.GetStream()));
//Enviamos los datos de acuerdo al siguiente orden
datos.Write(mensaje);
datos.Write(x);
datos.Write(y);
datos.Flush();
}
Actualizar los datos de nuestra aplicación en caso de una nueva batalla.
Lo que nosotros como programadores pensamos es que una vez acabada la batalla de barcos, el cliente puede decidir si desea otra partida o no, en caso de desear otra partida los controles deben borrarse para poder comenzar de nuevo la partida, en el otro caso que el cliente no quiera participar de otra batalla la aplicación debe cerrarse. Para esto ocupamos la clase control de los distintos controles ocupados, restablecemos los puntos de vida de los barcos y creo de nuevo los puntos de vida de los mismos.
Aquí ocurrieron pequeños detalles de como reiniciar los valores fue de gran ayuda la idea de hacer como "reset" de todos los controles y otro aspecto fundamental fue que a los barcos les debíamos poner o setear de nuevo sus puntos de vida.
La función que nos permitirá hacer esto es la función es NuevoJuego.
//Esta funcion nos permite jugar de nuevo
public void NuevoJuego()
{
//Removemos los picturebox creados
foreach (PictureBox obj in objetos)
this.Controls.Remove(obj);
//Reestablecemos los puntos de vida de los barcos
for (int i = 0; i < barcos.Length; i++)
{
// Creo los barcos con los puntos de vida
barcos[i] = new Barco(i + 1);
}
//habilitamos el boton generar
btnGenerar.Enabled = true;
//Ponemos el turno en false
turno = false;
}
Problemas para Finalizar la Comunicación
Tenemos un problema para finalizar la comunicación entre el servidor y el cliente, para ello se hizo lo siguiente:
Se tuvo problemas con la forma de leer los datos para terminar la comunicacion para lo siguiente se cambio el while por un do-while
-Con el do while nos permite hacer el fin de la comunicacion en el cliente y en el servidor es:
string mensaje1 = "";
//Este lazo se ejecuta mientras no llegue un mensaje de Terminar
do
{
//creamos un flujo
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del servidor
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del servidor
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Ganar":
//Informamos que se gano la partida
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Preguntamos si quiere seguir jugando
DialogResult resultado = MessageBox.Show("Quieres Jugar un Nuevo Juego", "Informacion", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (resultado == DialogResult.Yes)
//Si selecciona si Invoacamos una funcion para juego nuevo
Invoke(new Nuevo(NuevoJuego));
else
{
//Enviamos terminar al servidor
Enviar("Terminar", 0, 0);
MessageBox.Show("La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
break;
default:
break;
}
} while (mensaje1 != "Terminar");
//Cerramos el flujo
datos.Close();
//Cerramos el cliente
cliente.Close();
//Cerramos el formulario
this.Close();
-Con el do while nos permite hacer el fin de la comunicacion el servidor, verificando si esta conectado y el mensaje recibido por el servidor
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
Para la solución, se obtuvo la idea de: http://www.dreamincode.net/forums/topic/180149-c%23-servermulti-client/
Se tuvo problemas con la forma de leer los datos para terminar la comunicacion para lo siguiente se cambio el while por un do-while
-Con el do while nos permite hacer el fin de la comunicacion en el cliente y en el servidor es:
string mensaje1 = "";
//Este lazo se ejecuta mientras no llegue un mensaje de Terminar
do
{
//creamos un flujo
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del servidor
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del servidor
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Ganar":
//Informamos que se gano la partida
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Preguntamos si quiere seguir jugando
DialogResult resultado = MessageBox.Show("Quieres Jugar un Nuevo Juego", "Informacion", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (resultado == DialogResult.Yes)
//Si selecciona si Invoacamos una funcion para juego nuevo
Invoke(new Nuevo(NuevoJuego));
else
{
//Enviamos terminar al servidor
Enviar("Terminar", 0, 0);
MessageBox.Show("La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
break;
default:
break;
}
} while (mensaje1 != "Terminar");
//Cerramos el flujo
datos.Close();
//Cerramos el cliente
cliente.Close();
//Cerramos el formulario
this.Close();
-Con el do while nos permite hacer el fin de la comunicacion el servidor, verificando si esta conectado y el mensaje recibido por el servidor
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
Para la solución, se obtuvo la idea de: http://www.dreamincode.net/forums/topic/180149-c%23-servermulti-client/
martes, 17 de septiembre de 2013
¿Cómo descontar los puntos de vida en un ataque acertado?
Otro problema se nos presentó cuando al momento que el servidor o el cliente atacaba y me acertaba en la localización del barco el descuento de puntos para saber cuando ganó y cuando perdió. A la vez igual si por una u otra razón el cliente presionaba donde ya acertó los puntos no deberían ser disminuidos solo en el primer acierto se debieron bajar los puntos.
Esto se logró mediante una función booleana la cual nos permitirá chequear si el barco atacado fue o no fue herido, así como también si ya acerté en el barco y presiono en la misma posición los barcos no pierdan más puntos de vida.
Esta función del tipo booleana se la llamó Disparo.
//Esta funcion permite comprobar si el disparo golpeo un barco
public bool Disparo(int x, int y)
{
//creamos un tipo punto
Point p = new Point(picPosicion.Location.X + (x * 30), picPosicion.Location.Y + (y * 30));
//hacemos un foreach para buscar entre los barcos
foreach (Barco barco in barcos)
{
//Cargamos la propiedad Puntos, para hacer la comprobacion
Point[] valor = barco.Puntos;
//hacemos un foreach dentro del arreglo anteriormente obtenido
foreach (Point p2 in valor)
{
//Comprobamos si los puntos son iguales
if (p2 == p)
{
//Esto comprobamos que no sea en el mismo punto el golpe
int i = 0;
foreach (Point punto in barco.PuntosGolpe)
{
if (punto == p)
{
i++;
}
}
//Si no se ha dado anteriormente un golpe se disminuye los puntos de vida
if (i == 0)
{
MessageBox.Show("Te Golpearon", "Peligro", MessageBoxButtons.OK, MessageBoxIcon.Hand);
barco.PuntosVida--;
barco.PuntosGolpe.Add(p);
}
return true;
}
}
}
return false;
}
sábado, 14 de septiembre de 2013
Elección del tipo de conexión para nuestra aplicación. ¿TCP ó UDP?
Un gran problema que tuvimos que enfrentarlo fue lo de la conexión de nuestra aplicación si usábamos conexión TCP ó UDP.
Con UDP tuvimos un gran inconveniente que al momento de enviar los datos la aplicación no recibía de la mejor manera los datos y no los procesaba como queríamos.
Por este motivo decidimos hacer la conexión mediante TCP mediante el TCPClient y con la utilización de hilos para la escucha de clientes que pueden acceder a nuestra aplicación.
Para esto estamos leyendo de un archivo de configuración el puerto y a la vez estamos escuchando que IP se pude conectar con la aplicación. Con la elección de la conexión TCP obtuvimos que nuestros datos se envíen como deseábamos.
A continuación la parte importante de nuestras comunicaciones y lo explicado anteriormente mediante código.
public void Comunicaciones()
{
//string Ip = ConfigurationManager.AppSettings["ip"].ToString();
//Obtenemos el numero de puerto del archivo de configuracion
string puerto = ConfigurationManager.AppSettings["puerto"].ToString();
//Inicializamos el TcpListener
escuchar = new TcpListener(IPAddress.Any, Convert.ToInt32(puerto));
//Comenzamos a escuchar por conexiones
escuchar.Start();
//Aceptamos una una conexion
cliente = escuchar.AcceptTcpClient();
//Comprobamos que este conectado
if (cliente.Connected)
{
MessageBox.Show("Cliente conectado", "Mensaje", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos una funcion para desbloquear el boton generar
Invoke(new Desbloquea(DesbloquearControles));
}
//creamos un string para recibir el tipo de informacion
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
}
Con UDP tuvimos un gran inconveniente que al momento de enviar los datos la aplicación no recibía de la mejor manera los datos y no los procesaba como queríamos.
Por este motivo decidimos hacer la conexión mediante TCP mediante el TCPClient y con la utilización de hilos para la escucha de clientes que pueden acceder a nuestra aplicación.
Para esto estamos leyendo de un archivo de configuración el puerto y a la vez estamos escuchando que IP se pude conectar con la aplicación. Con la elección de la conexión TCP obtuvimos que nuestros datos se envíen como deseábamos.
A continuación la parte importante de nuestras comunicaciones y lo explicado anteriormente mediante código.
public void Comunicaciones()
{
//string Ip = ConfigurationManager.AppSettings["ip"].ToString();
//Obtenemos el numero de puerto del archivo de configuracion
string puerto = ConfigurationManager.AppSettings["puerto"].ToString();
//Inicializamos el TcpListener
escuchar = new TcpListener(IPAddress.Any, Convert.ToInt32(puerto));
//Comenzamos a escuchar por conexiones
escuchar.Start();
//Aceptamos una una conexion
cliente = escuchar.AcceptTcpClient();
//Comprobamos que este conectado
if (cliente.Connected)
{
MessageBox.Show("Cliente conectado", "Mensaje", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos una funcion para desbloquear el boton generar
Invoke(new Desbloquea(DesbloquearControles));
}
//creamos un string para recibir el tipo de informacion
string mensaje1 = "";
//Hacemos un lazo do while, el cual se ejecutara hasta que no llegue terminar y el cliente este conectado
do
{
//Creamos un network stream
datos = cliente.GetStream();
//Leemos los datos enviados de acuerdo al orden con lo que enviamos los datos
BinaryReader datosRx = new BinaryReader(datos);
mensaje1 = datosRx.ReadString();
int x = datosRx.ReadInt32();
int y = datosRx.ReadInt32();
//Observams que tipo de mensaje recibimos
switch (mensaje1)
{
case "True":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, true });
break;
case "False":
//pintamos en radar de acuerdo a la respuesta del cliente
Invoke(new Pinto(Pintar), new object[] { x, y, false });
break;
case "punto":
//Enviamos si nos llego un golpe o no
Enviar(Disparo(x, y).ToString(), x, y);
//verificamos la vida
Invoke(new Vida(VerificarVida));
//Cambiamos el estado de la variable turno
Invoke(new Desbloquea(Desbloquear));
break;
case "Jugar":
//Recibimo el mensaje para el comienzo de la batalla
MessageBox.Show("Listo Para Comenzar La Batalla", "Pregunta", MessageBoxButtons.OK, MessageBoxIcon.Question);
//Invocamos a la funcion bloquear
Invoke(new Bloqueo(Bloquear));
break;
case "Ganar":
//Recibimos el mensaje de que ganamos desde el cliente
MessageBox.Show("Ganaste", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
break;
case "Nuevo":
//Recibimos el mensaje de juego nuevo
MessageBox.Show("Juego Nuevo", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
//Invocamos a la funcionde juego nuevo
Invoke(new Nuevo(NuevoJuego));
break;
default:
break;
}
} while (mensaje1 != "Terminar" && cliente.Connected);
//Enviamos el mensaje terminar al cliente
Enviar("Terminar", 0, 0);
//Cerramos el flujo
datos.Close();
//Cerramo el cliente
cliente.Close();
//Dejamos de escuchar
escuchar.Stop();
MessageBox.Show("Ya no se jugara: La aplicacion se cerrara", "Informe", MessageBoxButtons.OK, MessageBoxIcon.Information);
//Invocamos a la funcion cerrar
Invoke(new Terminar(Cerrar));
}
domingo, 8 de septiembre de 2013
¿Como colocar los barcos en la grilla?
Un gran problema se nos presentó al momento de colocar los barcos dentro de la grilla, ya que como conocemos los barcos pueden ocupar 1, 2, 3, 4 y 5 grillas tanto sea horizontalmente como verticalmente. Por lo que esto conllevó a controlar todas las posibilidades y circunstancias que podían ocurrir. Una de ellas fue controlar que el barco no se ubique fuera del "Picture Box" para lo cual utilizamos la propiedad location del Picture Box y así poder controlar este evento.
Dentro de esto también se encontraba que como los barcos deben ser ubicados verticalmente y horizontalmente, se debía controlar que los barcos no se salgan del Picture Box que los contiene y controlar el movimiento randómico de los barcos hasta que el jugador le parezca la mejor opción.
Otra gran dificultad fue como ubicar y colocar los barcos que ocupan más de una grilla, para esta operación se procedió a la imagen de los barcos dividirlas en puntos, para así con estos puntos poder extender, ensanchar o achicar al barco, con esto conseguimos la colocación y ubicación de los barcos que ocupan más de una grilla.
A continuación se les presenta el código y las 3 funciones que fueron creadas para estos propósitos antes mencionados que son:
- Función Ubicación
- Función PonerBarco
- Función Verificar
// Función ubicación que me servirá para la ubicación de los picturebox de los barcos
private void Ubicacion(Random valor)
{
// Creo un entero posición y lo inicializo en para definir la posición del barco dentro del
// arreglo anteriormente creado
int posicion = 0;
// Lazo for each para los barocs
foreach (Barco obj in barcos)
{
// Lazo infinito para verificar que no se sobrelapen los barcos
while (true)
{
// Generamos un randómico en X que va de 0 a 10
int x = valor.Next(0, 10);
// Generamos un randómico en Y que va de 0 a 10
int y = valor.Next(0, 10);
// Con esta condición definimo que no se salga el tamaño en ancho del picturebox
if ((x + obj.PuntosVida) < 10)
{
// Condición para que no se sobrelapen los picturebox de los barcos
if (Verificar(posicion, x, y, obj.PuntosVida, 1))
{
// Creo un punto para la posición del picturebox dentro del formularios para
// que se ubique correctaente el barco
Point punto = new Point((x * 30) + picPosicion.Location.X, (y * 30) +
picPosicion.Location.Y);
// Agrego en el barco la posición
obj.Posicion = punto;
// Definimos el ancho del barco y lo asociamos con los puntos de vida
obj.Ancho = obj.PuntosVida * 30;
// Definimos el largo del barco
obj.Largo = 30;
// LLamamos a la función actualizar de la clase Barco
obj.Actualizar();
// Llamamos a la función poner barco
PonerBarco(x, y, obj.PuntosVida, 1, obj.PuntosVida);
// Rompo el lazo infinito con cualquier condición que cumpla
break;
}
}
// Caso contrario si no es en lo horizontal ahora condición para la colocación
// vertical
else if ((y + obj.PuntosVida) < 10)
{
// // Condición para que no se sobrelapen los picturebox de los barcos
if (Verificar(posicion, x, y, 1, obj.PuntosVida))
{
// Creo un punto para la posición del picturebox dentro del formularios para
// que se ubique correctaente el barco
Point punto = new Point((x * 30) + picPosicion.Location.X, (y * 30) + picPosicion.Location.Y);
// Agrego en el barco la posición
obj.Posicion = punto;
// Defino el ancho del barco
obj.Ancho = 30;
// Definimos el largo del barco con los puntos de vida
obj.Largo = obj.PuntosVida * 30;
// LLamamos a la función actualizar de la clase Barco
obj.Actualizar();
// Llamamos a la función poner barco
PonerBarco(x, y, 1, obj.PuntosVida, obj.PuntosVida);
// Rompo el lazo infinito con cualquier condición que cumpla
break;
}
}
}
// Aumentamos la posición en 1 para verificar que no se sobrelapen los barcos
posicion++;
}
}
// Función PonerBarco para colocar el barco dentro del picturebox
private void PonerBarco(int x, int y, int ancho, int largo, int tipo)
{
// Creamos el punto de posición del barco
Point punto = new Point(picPosicion.Location.X + (x * 30), picPosicion.Location.Y + (y * 30));
// Con el swtich definimos que tipo de barco vamos a colocar en el picturebox
switch (tipo)
{
// Caso 1 Definen los datos (propiedades) del picture box esto es para todos los casos
case 1:
picBarco1.Location = punto;
picBarco1.Width = ancho * 30;
picBarco1.Height = largo * 30;
picBarco1.BorderStyle = BorderStyle.FixedSingle;
picBarco1.Visible = true;
picBarco1.BackColor = Color.Blue;
break;
case 2:
picBarco2.Location = punto;
picBarco2.Width = ancho * 30;
picBarco2.Height = largo * 30;
picBarco2.BorderStyle = BorderStyle.FixedSingle;
picBarco2.Visible = true;
picBarco2.BackColor = Color.Purple;
break;
case 3:
picBarco3.Location = punto;
picBarco3.Width = ancho * 30;
picBarco3.Height = largo * 30;
picBarco3.BorderStyle = BorderStyle.FixedSingle;
picBarco3.Visible = true;
picBarco3.BackColor = Color.Green;
break;
case 4:
picBarco4.Location = punto;
picBarco4.Width = ancho * 30;
picBarco4.Height = largo * 30;
picBarco4.BorderStyle = BorderStyle.FixedSingle;
picBarco4.Visible = true;
picBarco4.BackColor = Color.Yellow;
break;
case 5:
picBarco5.Location = punto;
picBarco5.Width = ancho * 30;
picBarco5.Height = largo * 30;
picBarco5.BorderStyle = BorderStyle.FixedSingle;
picBarco5.Visible = true;
picBarco5.BackColor = Color.Brown;
break;
}
}
// Función que nos permitirá veriicar que no se sobrelapen los barcos
private bool Verificar(int posicion, int x, int y, int ancho, int largo)
{
// Si la posición del barco dentro del arreglo es 0 se colocará en el picturebox
if (posicion == 0)
return true;
// Caso contrario
else
{
// Creo un lazo for para ir obteniendo la propiedad puntos de los barcos ya posicionados
for (int i = 0; i < posicion; i++)
{
// Creo un arreglo de puntos con la propiedad Puntos de los barcos
Point[] valor = barcos[i].Puntos;
// Verificamos si el ancho es diferente de 1 (el barco estará horizontalmente)
if (ancho != 1)
{
// Hacemos un for each del arreglo de puntos obtenido
foreach (Point punto in valor)
{
// Otro lazo for para hacer la comparación del ancho del barco y los puntos
// del barco anteriormente posicionado
for (int j = 0; j < ancho; j++)
{
// Hacemos la verificación si encontramos una coincidencia del punto retornará
// la función un false ya que se sobrelapan
if (punto == new Point(picPosicion.Location.X + (j * 30) + (x * 30),
picPosicion.Location.Y + (y * 30)))
return false;
}
}
}
// Verificamos si el largo es diferente de 1 (el barco estará verticalmente)
else if (largo != 1)
{
// Hacemos un for each del arreglo de puntos obtenido
foreach (Point punto in valor)
{
// Otro lazo for para hacer la comparación del largo del barco y los puntos
// del barco anteriormente posicionado
for (int j = 0; j < largo; j++)
{
// Hacemos la verificación si encontramos una coincidencia del punto retornará
// la función un false ya que se sobrelapan
if (punto == new Point(picPosicion.Location.X + (x * 30), picPosicion.Location.Y + (y * 30) + (j * 30)))
return false;
}
}
}
}
// Retorna verdadero si no hay ninguna coincidencia
return true;
}
}
Suscribirse a:
Entradas (Atom)