Anteriormente, había escrito una entrada muy básica sobre la creación de un juego tipo Ping Pong con Windows Forms en C# y Visual Basic, en esta ocasión, escribo una versión completamente funcional en Windows Forms.

Creando y configurando el proyecto

Lo primero que haremos, será crear el proyecto, éste lo crearemos en el apartado Visual C# -> Windows Classic Desktop -> Windows Forms App (.NET Framework), de la siguiente forma:

Creando un proyecto Windows Forms
Creando un proyecto Windows Forms

Configurando el formulario

Colocaremos los elementos principales en nuestro formulario.

Le ponemos un fondo negro al formulario a través de la propiedad BackColor.

Colocamos 4 PictureBox y les asignamos lo siguiente:

Name Size
pbPlayer1 65, 160
pbPlayer2 65, 160
pbTitleScreen N/A
pbBall 35, 35

 

Colocamos 2 elementos Label, y les hacemos los siguientes ajustes:

Name Text
lblScore1 0
lblScore2 0
N/A

 

Al final, debemos tener algo así:

Interfaz Gráfica del Ping Pong
Interfaz Gráfica del Ping Pong

No te preocupes mucho en estos momentos por las posiciones, eso lo haremos bajo código.

Definiendo el tamaño del contenedor

Definiremos 2 constantes como parte de la clase, una llamada ScreenWidth, y otra llamada ScreenHeight, de la siguiente forma:

Dentro del constructor, definiremos el nuevo tamaño de nuestra ventana, a través de la propiedad ClientSize, a la cual le pasaremos los parámetros definidos previamente.

Con esto, si ejecutamos la aplicación, tendremos una ventana definida en base a los vales asignados a las variables ScreenWidth y ScreenHeight.

Cargando los Sprites

Nos interesa ahora, mostrar las imágenes en los PictureBox correspondientes. Para esto, crearemos una nueva clase llamada “GameItem”, la cual será la encargada de gestionar la velocidad, la posición y la imagen de un elemento “jugable” en la pantalla, y la codificaremos de la siguiente forma:

De igual forma, creamos otra clase llamada BallItem, la cual heredará de nuestra clase base “GameItem”, y la cual tendrá un método específico para actualizar la posición de nuestra pelota.

Regresando a la clase del formulario, creamos 3 variables, 2 del tipo GameItem, y 1 del tipo BallItem.

Dentro del constructor, nos suscribimos al evento Load del formulario y también llamamos a un método que se llamará “Initialize”. Como parte del evento Load, llamaremos a un método llamado “LoadGraphicsContent”, el cual definimos de la siguiente forma:

Antes de ejecutar el proyecto, debemos descargar los sprites. Dichos sprites, hay que descomprimirlos, y deben quedar en la carpeta de Debug.

Colocando los sprites
Colocando los sprites

Con esto, ya tendremos nuestros sprites cargados en el formulario.

Sprites cargados
Sprites cargados

Detectar mouse y dibujar el Jugador 1

Antes de continuar, crearemos 5 regiones:

  • GamePlay Methods
  • Events
  • Engine Methods
  • Mechanics
  • Collisions

Colocaremos el código del evento de carga del formulario en la región de eventos, Initalize y LoadGraphicsContent dentro de Engine Methods.

Agregamos 2 timers como parte de la interfaz principal, y les asignamos lo siguiente:

Name Enabled Interval
UpdateTimer True 16
DrawTimer True 16

 

Tenemos que crearles su respectivo manejador de eventos para el evento Tick, los cuales llevaremos a la región de eventos para tener el código ordenado. Dentro del manejador de eventos del evento click del control UpdateTimer, hay que llamar un método no definido aún llamado UpdateScene, el cual contendrá la lógica para llevar a cabo la actualización de la interfaz gráfica. UpdateScene debe ir en la región EngineMethods.

Definiremos el método UpdateScene dentro de la región Engine Methods, y desde ahí llamaremos un nuevo método no definido llamado UpdatePlayer.

Dentro de la región Mechanics, definiremos el nuevo método UpdatePlayer, en donde definiremos el código, en primer lugar para controlar al jugador 1. Comenzamos por definir la posición en X constante que tendrá nuestro sprite en el escenario, esto es, debido a que un paddle sólo puede moverse de arriba hacia abajo, por lo tanto, la posición en X siempre será la misma. Por otro lado, tomaremos el valor en Y, de acuerdo a la posición del puntero del mouse. Posteriormente, crearemos una nueva posición de acuerdo a los valores obtenidos. Finalmente, hacemos comprobaciones para que nuestro paddle no se salga de los límites del escenario.

Por último, debemos de redibujar el control en su nueva posición, por lo que tenemos que codificar dentro del manejador de eventos de DrawTimer_Tick, un nuevo método llamado DrawScene.

DrawScene estará definido dentro de Engine Methods, y contendrá una llamada al método Draw del sprite correspondiente.

Si ejecutamos, tendremos el paddle del jugador 1 en acción.

Detectar teclado y dibujar el Jugador 2

Llevar a cabo la detección de las teclas en Windows Forms, es más fácil en estos días. Para hacer esto, hay que utilizar 2 bibliotecas que no son agregadas por defecto: “PresentationCore” y “WindowsBase”. Con esto, podremos implementar la lógica en el método UpdatePlayer, para detectar si una tecla de nuestra preferencia ha sido tecleada, en nuestro caso, utilizaremos las teclas ‘S’ y ‘W’, posteriormente, validamos si el paddle del jugador 2 se encuentra dentro del escenario. También debemos definir una variable a nivel de clase llamada “_currentY”, del tipo int.

El código para realizar la comprobación, es el siguiente:

Por último, no debemos olvidar actualizar el dibujado del paddle, en el método DrawScene.

Moviendo la pelota

Para mover la pelota, debemos definir 3 nuevos métodos dentro de la región “Mechanics”, los cuales serán: “ResetBall”, “GenerateBallX” y “GenerateBallY”.

Para que no marque errores con las variables, agregaremos las que faltan como parte de la clase.

Finalmente, hay que actualizar la posición de la pelota, y dibujarla a través de los métodos correspondientes.

Validando el choque de la pelota contra los paddles y las paredes

Validando el choque contra los paddles

Para realizar estas validaciones, hay que agregar 4 puntos a los sprites, con el objetivo de verificar si la pelota ha chocado contra algún paddle. Para esto, modificaremos la clase GameItem, de la siguiente forma.

Y agregaremos el método CheckPaddleCollisions a la clase del formulario.

Finalmente, mandamos a llamar el nuevo método a través de UpdateScene:

Validando el choque contra las paredes superior e inferior

Para esta validación, crearemos un nuevo método llamado “CheckWallCollision”, el cual debe quedar de la siguiente forma:

De nuevo, hay que agregar la variable “BaseBallSpeed” como parte de las variables de la clase.

Y de nuevo, llamamos la comprobación desde el método UpdateScene.

Validando si la pelota ha salido de la escena

Para esto, hay que validar dónde se encuentra la posición de la pelota a través del siguiente código.

Hay que agregar las variables que almacenarán el puntaje de los jugadores.

Finalmente, llamamos el método desde UpdateScene.

Código en Github

Con esto llegamos al final de la entrada, el código es todavía bastante mejorable, simplemente he querido actualizar esta entrada, porque ví que había mucha gente interesada en el tema. Dejo el código en Github con una pieza de código que no he mostrado aquí.

¡Saludos!

¡Califica la publicación!
[Total: 1 Promedio: 5]

DEJA UNA RESPUESTA

Please enter your comment!
Please enter your name here