Consejos

Programación de juegos 2D en C Tutorial: Serpiente

Programación de juegos 2D en C Tutorial: Serpiente

El propósito de este tutorial es enseñar programación de juegos 2D y lenguaje C a través de ejemplos. El autor solía programar juegos a mediados de la década de 1980 y fue diseñador de juegos en MicroProse durante un año en los años 90. Aunque gran parte de eso no es relevante para la programación de los grandes juegos 3D de hoy, para pequeños juegos casuales servirá como una introducción útil.

Implementando Serpiente

Los juegos como la serpiente donde los objetos se mueven sobre un campo 2D pueden representar los objetos del juego en una cuadrícula 2D o como una matriz de objetos de una sola dimensión. "Objeto" aquí significa cualquier objeto del juego, no un objeto como se usa en la programación orientada a objetos.

Controles del juego

Las teclas se mueven con W = arriba, A = izquierda, S = abajo, D = derecha. Presione Esc para salir del juego, f para alternar la velocidad de fotogramas (esto no está sincronizado con la pantalla, por lo que puede ser rápido), la tecla de tabulación para alternar la información de depuración yp para pausarla. Cuando está en pausa, el subtítulo cambia y la serpiente parpadea,

En serpiente los principales objetos del juego son

  • La serpiente
  • Trampas y frutas

Para fines de juego, una variedad de entradas contendrá cada objeto del juego (o parte de la serpiente). Esto también puede ayudar al representar los objetos en el búfer de la pantalla. He diseñado los gráficos para el juego de la siguiente manera:

  • Cuerpo de serpiente horizontal - 0
  • Cuerpo de serpiente vertical - 1
  • Cabeza en 4 x rotaciones de 90 grados 2-5
  • Cola en 4 rotaciones de 90 grados 6-9
  • Curvas para cambiar de dirección. 10-13
  • Manzana - 14
  • Fresa - 15
  • Plátano - 16
  • Trampa - 17
  • Ver el archivo de gráficos de serpiente snake.gif

Por lo tanto, tiene sentido usar estos valores en un tipo de cuadrícula definido como blockWIDTH * HEIGHT. Como solo hay 256 ubicaciones en la cuadrícula, he elegido almacenarlo en una matriz de una sola dimensión. Cada coordenada en la cuadrícula de 16 x16 es un entero 0-255. Hemos usado ints para que puedas agrandar la cuadrícula. Todo está definido por #defines con WIDTH y HEIGHT ambos 16. Como los gráficos de serpiente son 48 x 48 píxeles (GRWIDTH y GRHEIGHT #defines), la ventana se define inicialmente como 17 x GRWIDTH y 17 x GRHEIGHT para ser un poco más grande que la cuadrícula .

Esto tiene beneficios en la velocidad del juego, ya que usar dos índices siempre es más lento que uno, pero significa que en lugar de sumar o restar 1 de las coordenadas Y de la serpiente para moverse verticalmente, restas ANCHO. Agrega 1 para moverte a la derecha. Sin embargo, siendo astutos también hemos definido una macro l (x, y) que convierte las coordenadas xey en tiempo de compilación.

¿Qué es una macro?

#definir l (X, Y) (Y * ANCHO) + X

La primera fila es el índice 0-15, la segunda 16-31, etc. Si la serpiente está en la primera columna y se mueve hacia la izquierda, entonces la marca para golpear la pared, antes de moverse hacia la izquierda, debe verificar si la coordenada% WIDTH == 0 y para la coordenada de pared derecha% WIDTH == WIDTH-1. El% es el operador del módulo C (como la aritmética del reloj) y devuelve el resto después de la división. 31 div 16 deja un resto de 15.

Manejando la serpiente

Hay tres bloques (matrices int) utilizados en el juego.

  • serpiente, un anillo de amortiguación
  • shape - Contiene índices gráficos de Snake
  • dir: mantiene la dirección de cada segmento de la serpiente, incluida la cabeza y la cola.

Al comienzo del juego, la serpiente tiene dos segmentos de largo con una cabeza y una cola. Ambos pueden apuntar en 4 direcciones. Para el norte, la cabeza es el índice 3, la cola es 7, para la cabeza este es 4, la cola es 8, para la cabeza sur es 5 y la cola es 9, y para el oeste, la cabeza es 6 y la cola es 10 Mientras que la serpiente tiene dos segmentos de largo, la cabeza y la cola siempre están separadas 180 grados, pero después de que la serpiente crece pueden tener 90 o 270 grados.

El juego comienza con la cabeza hacia el norte en la ubicación 120 y la cola hacia el sur en 136, aproximadamente en el centro. Con un ligero costo de unos 1.600 bytes de almacenamiento, podemos obtener una mejora de velocidad apreciable en el juego manteniendo las ubicaciones de la serpiente en el búfer del anillo de serpiente mencionado anteriormente.

¿Qué es un buffer de anillo?

Un búfer de anillo es un bloque de memoria utilizado para almacenar una cola de tamaño fijo y debe ser lo suficientemente grande como para contener todos los datos. En este caso, es solo para la serpiente. Los datos se envían al frente de la cola y se retiran por la parte posterior. Si el frente de la cola llega al final del bloque, entonces se envuelve. Mientras el bloque sea lo suficientemente grande, el frente de la cola nunca alcanzará a la parte posterior.

Cada ubicación de la serpiente (es decir, la coordenada int única) desde la cola hasta la cabeza (es decir, hacia atrás) se almacena en la memoria intermedia del anillo. Esto brinda beneficios de velocidad porque no importa cuánto tiempo se demore la serpiente, solo la cabeza, la cola y el primer segmento después de la cabeza (si existe) deben cambiarse a medida que se mueve.

Almacenarlo al revés también es beneficioso porque cuando la serpiente obtiene comida, la serpiente crecerá la próxima vez que se mueva. Esto se hace moviendo la ubicación de la cabeza una en el búfer de anillo y cambiando la ubicación de la cabeza antigua para convertirla en un segmento. La serpiente está formada por una cabeza, segmentos 0-n) y luego una cola.

Cuando la serpiente come alimentos, la variable atefood se establece en 1 y se verifica en la función DoSnakeMove ()

Moviendo la serpiente

Utilizamos dos variables de índice, headindex y tailindex para señalar las ubicaciones de cabeza y cola en el búfer de anillo. Estos comienzan en 1 (headindex) y 0. Entonces, la ubicación 1 en el búfer en anillo contiene la ubicación (0-255) de la serpiente en el tablero. La ubicación 0 contiene la ubicación de la cola. Cuando la serpiente mueve una ubicación hacia adelante, tanto el índice de la cola como el índice de la cabeza se incrementan en uno, envolviéndose a 0 cuando alcanzan 256. Entonces, la ubicación donde estaba la cabeza es donde está la cola.

Incluso con una serpiente muy larga que se enrolla y se enreda en unos 200 segmentos. solo el índice de cabecera, el segmento al lado de la cabeza y el índice de cola cambian cada vez que se mueve.

Tenga en cuenta que debido a la forma en que funciona SDL, tenemos que dibujar la serpiente completa en cada cuadro. Cada elemento se dibuja en el búfer de cuadro y luego se voltea para que se muestre. Sin embargo, esto tiene una ventaja, ya que podríamos dibujar la serpiente moviendo suavemente unos pocos píxeles, no una posición de cuadrícula completa.