Título: [Tutorial] Snake en C++/SDL Publicado por: kaltorak en 13 Agosto 2013, 04:49 am SNAKE EN C++/SDL (http://imageshack.us/a/img268/7075/jyc0.png) Hola a todos He creado este manual, por petición de Dato000 miembro del grupo de desarrollo de videojuegos al que pertenezco, en el voy a realizar una versión simple del videojuego Snake(o serpiente), usando C++ y la librería gráfica SDL, veréis que con apenas 280 lineas de código, contando espacios y comentarios se puede hacer el videojuego Snake(o serpiente) y que no es tan difícil como parece. Espero que este manual le sea de ayuda a la gente que se apunto al reto y no pudo resolverlo, o para todo aquel que alguna vez a querido realizar el videojuego Snake(o serpiente) y no ha sido capaz. Voy a empezar poniendo el código completo, para después ir explicándolo linea a linea, doy por sentado que el lector de este manual tiene una mínima base de programación en C o C++. Código
Para el que no lo conozca el videojuego Snake (o serpiente) comentaros que fue lanzado a mediados de los 70 y ha mantenido su popularidad desde entonces, convirtiéndose en un clásico tras su salida en 1998 en todos los dispositivos móviles de Nokia. Su argumento es muy sencillo pero enormemente adictivo, el jugador controla una larga y delgada criatura semejante a una serpiente, de hay el nombre del videojuego, que vaga por un plano delimitado por paredes, donde debe evitar a toda costa chocar contra las paredes o consigo misma mientras come manzanas las cuales la hacen crecer, lo cual complica el juego a medida que la serpiente va creciendo debido a la ingesta de las mencionadas manzanas, si esto no fuera suficiente la serpiente una vez que comienza a moverse no puede ser para por el jugador, este se tiene que limitar a cambiar el sentido de la marcha de la suso dicha serpiente mediante las flechas de dirección, para que se coma las manzanas y evite chocar. Comencemos a analizar el código. Comenzamos incluyendo las librerías que vamos a necesitar para el buen funcionamiento del código. La librería estándar "cstdlib " Código
La librería “vector” para la creación de una lista de vectores, que controlen el tamaño de serpiente. Código
La librería “time.h” para generar aleatoriamente la posición en la que va a aparecer la manzana en el juego, cada vez que esta sea devorada por la serpiente. Código
Y por ultimo la librería “SDL.h” la cual vamos usar para manejar el entorno gráfico y las pulsaciones del teclado. Código
Las siguiente lineas de código son los prototipos de las funciones “Colision” y “Iniciar”, de las cuales explicare su funcionamiento mas adelante. Código
Ahora vamos a usar la directiva “#define” para crear unas macros, las cuales nos ayudaran a entender mejor el código. Lo que estas macros hacen es que trabajemos con las direcciones reales en las que se mueve la serpiente y no números pues tras un tiempo sin usar el código no sabríamos que significaba cada numero. Mirar a la dirección Arriba le adjudicamos el numero 1, lo que hace esta macro es que en el código podemos poner Arriba y sabremos que significa 1, después el preprocesador cambiara las palabra Arriba por un 1 antes de compilar el código, como bien he dicho esto es solo por limpieza y para mejorar la compresión del código para futuras modificaciones o para que sea comprensible para otra persona que no sea el programador del mismo. Código
Tras estas lineas vamos a definir el ancho y alto de la pantalla principal así como la profundidad de color de la misma. Código
Ahora vamos a definir el retardo en milisegundos que usaremos para que el programa funcione mas o menos igual en todas las maquinas aunque sean las rápidas Código
Declaramos e inicializamos la variable LongitudSerpiente la cual contendrá el tamaño de la serpiente, la iniciamos con valor 0 para que en un principio solo contenga la cabeza de la serpiente. Código
Declaramos e inicializamos la variable Dirección, que contendrá la dirección en la que se esta moviendo la Serpiente en cada momento, principalmente la inicializamos a 0 para que la serpiente aparezca parada al comenzar el juego. Código
Declaramos e inicializamos la variable control para controlar la permanecía o la salida del bucle que controla el chequeo de la manzana al ser creada, para que no coincida en una posición de la pantalla en la cual se encuentre la serpiente. Código
Declaramos la variable Ultimo del tipo SDL_Rect donde almacenaremos la posición del ultimo cuadro que forma la cola de la serpiente, para cuando tengamos que añadir un nuevo cuadro a la cola tras la ingesta de una manzana, sepamos donde posicionarlo con respecto al resto de la serpiente. Código
Declaramos e inicializamos la variable Puntos que contendrá los puntos del juego. Código
Declaramos la variable Titulo que contendrá el titulo de la ventana y la puntuación. Código
la siguiente linea es la encargada de usar el ámbito std como namespace, esto se traduce en que no tendremos que usar std:: delante de las funciones estándar de C++ Código
Declaramos la estructura Cuadro que sera la encargada de almacenar la posición y el tamaño, de cada una de las partes que formaran el cuerpo de la Serpiente y la Manzana. Si os fijáis también he creado un constructor para que la primera vez que creemos uno de los cuadros que formaran la serpiente o la manzana, se inicialicen con un tamaño de 20 píxeles. Código
Declaramos el vector Serpiente del tipo Cuadro, un vector es muy similar a un array o lista, lo único que tendremos control total cobre los miembros que forman el vector, podremos incluir miembros nuevos cuando queramos o eliminar algún miembro que no no interese, como no sabremos que tamaño va a alcanzar nuestra serpiente en cada momento, la mejor forma de manejarlo es usando vector pues como os he comentado nos genera una array o lista, que podemos modificar libremente, otra manera de hacerlo seria dividir el ancho y el alto de la pantalla por el tamaño de un cuadro y multiplicar los resultados, después le restamos 1 para poder posicionar la manzana y tendremos el tamaño total que podrá tener nuestra serpiente. Por ejemplo si la pantalla midiera 640x480 y cada cuadro que forma la serpiente midiera 20 píxeles, la forma de saber el tamaño máximo que podrá alcanzar nuestra serpiente sera así: 640/20 = 32 480/20 = 24 32 * 24 = 768 768 – 1 = 767 Nuestra serpiente podría tener un tamaño máximo de 767 cuadros y podríamos generar un array de 767 elementos y evitar usar vectores, pero de esta manera estaríamos desperdiciando mucha memoria que mas de un 90% de las veces no sera usada, por este motivo y como es una buena practica de programación ahorrar memoria vamos a usar vectores. Código
la función main no necesita presentación ;) Código
Usaremos la función srand con time como semilla para la generación de numeros aleatorios para posicionar la manzana en pantalla. Código
Inicializamos el modo de vídeo de las SDL y comprobamos que se inicialice bien. Código
Introducimos SDL_Quit en atexit para que se inicie al finalizar el programa, saliendo así de la librería SDL siempre que el programa finalice. Código
Creamos la Surface principal del juego, la que se va a mostrar en pantalla y comprobamos que se inicie correctamente. Código
Llamamos a la función Iniciar para poner todos los valores a cero. Código
A continuación voy a pasar a explicar la función Iniciar y después regresare al código en la linea siguiente a Iniciar();. La función Iniciar es la encargada de poner todas las variables con los valores originales del juego para de esta manera poder reiniciarlo cuando colisionemos y la serpiente muera. Código
Analicemos mas profundamente la manera de posicionar la manzana aleatoriamente en la pantalla Código
Sabemos que las medidas de la pantalla están almacenadas dentro de las variables ResolucionX para el ancho y ResolucionY para el alto, las coordenadas que definen la posición de la manzana se posicionan en la esquina superior izquierda de la misma. (http://imageshack.us/a/img855/4343/60to.png) Así que si por un casual el ancho aleatorio que nos saliera fuera 640, la manzana se colocaría fuera de la pantalla por el lado derecho de la misma o si el valor para el alto generado aleatoriamente coincidiera con 480, pasaría lo mismo que en el caso anterior pero esta vez la manzana se dibujaría fuera de la pantalla por el lado inferior de la misma, para solucionar este problema debemos restarle el ancho y el alto de la manzana a las dimensiones de la pantalla para asegurarnos de que dicha manzana cuando sea dibujada no se muestre fuera de los limites de la pantalla, el ancho de la manzana se encuentran en Manzana.Posicion.w y el alto en Manzana.Posicion.h. Código
Para asegurarnos que el numero aleatorio que va a ser generado para colocar la manzana esta centrado con respecto a la pantalla y al movimiento de la serpiente, debemos dividir el resultado nuevamente por el ancho o el alto de la manzana de esta manera la manzana solo se podrá colocar en posiciones multiplicas de 20 que es el ancho y al alto de la manzana, quedando siempre centrada con el movimiento de la serpiente. Código
Y por ultimo ya solo nos queda multiplicar el resultado de la operación aleatoria por el ancho y el alto de la manzana para sacar las coordenadas reales de la pantalla en que va a ser dibujada la manzana. Código
Para posicionar la serpiente en el centro de la pantalla usamos el mismo método que para posicionar la manzana, pero lógicamente sin usar números aleatorios, así nos aseguramos que tanto la manzana como la serpiente se encuentren centradas una con respecto a la otra, de esta manera cuando la serpiente se coma la manzana la posición de la cabeza y la manzana corresponderán perfectamente. Código
Una vez explicada la función Iniciar vamos a continuar con el código. Ahora Declaramos e inicializamos la variable done del tipo bool la cual usaremos como bandera de control para abandonar el bucle principal del juego una vez que pulsemos la tecla Escape o la X que cierra la ventana, tras la declaración creamos el bucle principal del juego que se repetirá siempre que el valor de la variable done se a false (o 0). Código
Lo primero que vamos a encontrar dentro del bucle principal del juego es el método para leer los mensajes que el programa recibe del exterior, como pueden ser las teclas que han sido pulsadas o los mensajes recibidos de la ventana. Código
Declaramos event del tipo SDL_Event, que es donde almacenaremos los mensajes que recibamos del sistema. Código
Después crearemos un bucle que se repetirá siempre que queden mensajes del sistema por procesar, al mismo tiempo almacenamos dichos mensajes en la variable event creada anteriormente. Código
Tras lo cual procederemos a leer el mensaje del sistema almacenado en la variable event Código
Si el mensaje almacenado en la variable event es SDL_QUIT, esto nos informa de que la X de la ventana a sido pulsado y por tanto el programa debe finalizar, así que ponemos el valor de la variable done a true(o 1) para salir del bucle principal de programa y de este modo finalizar el mismo. Código
Otro de los mensajes del sistema que vamos a monitorizar, sera si una tecla a sido pulsada para ello usaremos Código
Y tras saber que una tecla a sido pulsada debemos ver cual y si nos interesa para que el programa reaccione en concordancia a la tecla pulsada, la primera tecla que vamos a comprobar si ha sido pulsada es Escape y lo haremos mediante. Código
En caso de que el resultado sea 1 o mayor de 1 eso quiere decir que la tecla Escape a sido pulsada y se procederá a realizar lo que hay en el interior del bloque que no es otra cosa que poner el valor de la variable done a true (o 1) para salir del bucle principal de programa y de este modo finalizar el mismo. Código
Después realizaremos la comprobación con las teclas de dirección, empezando por la tecla de dirección Arriba o lo que es lo mismo SDLK_UP, pero además de comprobar que la tecla haya sido pulsada podremos ver en el código que se realiza otra comprobación,Esta comprobación es que la variable Dirección no contenga el valor Abajo, esto lo hacemos por que la serpiente no puede andar hacia atrás y si la variable Dirección contiene el valor Abajo, la serpiente esta yendo hacia abajo en la pantalla, por lo tanto la tecla de dirección Arriba no tiene que tener efecto; Para que entremos en el bloque del if ambas comprobaciones deben ser correctas, en caso de que las dos comprobaciones sean correctas cambiamos el valor de la variable Dirección por Arriba y de este modo le decimos a la serpiente la dirección que debe tomar a partir de ahora. Código
Explicado esto el resto de las comprobaciones que se realizan a las teclas de dirección son iguales a la comprobación de la tecla de dirección Arriba, pero obviamente cambiando la dirección del movimiento de la serpiente. Código
Una vez hemos comprobado todos los mensajes del sistema y realizados las acciones que mejor se ajustan a dichos mensajes, salimos del bucle que procesa los mensajes y continuamos. Si la serpiente esta en movimiento quiere decir que la variable Dirección no vale 0 por tanto tenemos que empezar a mover dicha serpiente por la pantalla y para hacer esto lo primero que vamos a hacer es almacenar en la variable Ultimo del tipo SDL_Rect la posición del ultimo cuadro que forma la cola de la serpiente antes de que este sea movido de su posición actual esto lo hacemos para saber la posición en la que tendremos que colocar un nuevo cuadro si la serpiente se come la manzana Código
Después de almacenar la posición del ultimo cuadro que forma la cola de la serpiente, vamos a mover la posición de los cuadros que forman la cola de la serpiente mediante el siguiente for, empezando por el ultimo a la posición del cuadro que se encuentra una posición mas arriba en la lista de elementos del vector Serpiente, como podemos ver Declaramos la variable I la cual vamos a usar como contador y la Inicializamos con el valor de la variable LongitudSerpiente que contiene el tamaño actual de la serpiente y recorreremos los elementos que forman el vector Serpiente, hasta alcanzar el cuadro mas próximo a la cabeza de la serpiente que no es otro que el elemento del vector 1, pues como vimos antes la cabeza de la serpiente se encuentra en el elemento del vector 0.con esto conseguimos que la cola de la serpiente avance una posición o lo que es lo mismo 20 píxeles por la pantalla. Código
Una vez llegados a este punto nos tiene que surgir una duda, bien si movemos todos los cuadros que forman la cola de la serpiente a la posición inmediata siguiente que pasa con la cabeza de la serpiente? Pues vamos a resolver esta duda ahora mismo, como la cabeza de la serpiente es la que dirige al resto de la serpiente es la que tiene que moverse en concordancia con la dirección que le digamos usando el teclado por ese motivo la movemos con los siguientes if, Código
Si la variable Dirección contiene Arriba eso significa por lo que vimos antes que hemos usado la tecla de dirección Arriba entonces debemos mover la serpiente por la pantalla hacia arriba esto lo hacemos modificando la variable que contiene la dirección y de la cabeza de la serpiente que no es otra que Serpiente[0].Posicion.y y para ello le restamos el alto del cuadro que forma la cabeza de la serpiente que se encuentra en la variable Serpiente[0].Posicion.h, que son 20 pixeles. Código
El resto de los else if son exactamente iguales pero lógicamente alterando la los variables en concordancia en la dirección en que deba ser movida la serpiente Código
Ahora vamos a comprobar la colisión de la cabeza de la serpiente con el borde, para ello tenemos que comprobar que la posición x e y de la serpiente se encuentre dentro de los limites de la pantalla, fijaros bien pues pasa lo mismo que cuando queríamos colocar la manzana dentro de los limites de la pantalla, como los puntos de posición del cuadro que forma la cabeza de la serpiente están en la esquina superior izquierda del cuadro, para comprobar que la colisión se realiza correctamente con la parte inferior y la parte derecha de la pantalla, tenemos que sumar el ancho y el alto del cuadro que forma la cabeza de la serpiente, a la variable respectiva, en caso de que se produzca la colisión reiniciaremos el juego llamando a la función Iniciar la cual os explique su funcionamiento anteriormente. Código
Una vez hemos realizado la comprobación de la colisión con el borde de la pantalla, vamos a realizar la comprobación de la colisión de la cabeza de la serpiente con la cola, para ello vamos a usar la función Colision la cual os explicare a continuación y después seguiremos viendo el código Como podéis ver la función Colision es muy simple lo que hace es comprobar si el cuadro que le pasamos como primer miembro de la función se encuentra dentro o en contacto con el cuadro que le pasamos como segundo miembro de la función, si están en contacto devuelve 1 y en caso contrario devuelve 0. Código
Vamos a recorrer los elementos que forman el vector Serpiente usando un for, empezaremos por el elemento 1 del vector Serpiente, de este modo nos saltamos la cabeza de la serpiente pues esta es la que colisiona con la cola, y lógicamente no puede colisionar consigo misma, cuando Declaramos la variable I que vamos a usar como contador, la Inicializamos con el valor 1, de este modo recorreremos todos los elementos que forman el vector Serpiente saltándonos la cabeza de la serpiente y comprobaremos mediante la función Colision si existe colisión con la cabeza de la serpiente que es el elemento 0 del vector, en caso de que la función Colision devuelva 1 quiere decir como vimos antes que la colisión se a producido y entramos dentro del bloque del if donde mediante la función Iniciar reiniciamos el juego . Código
Ya solo nos queda comprobar si la serpiente se a comido la manzana lo cual haremos nuevamente con la función Colision y un if, esta vez comprobaremos la cabeza de la serpiente y la manzana como podemos ver , en caso de que la colisión se produzca entraremos en el bloque del if. Código
Como sabemos que cuando la serpiente se come un manzana su cola crece un cuadro debemos incrementar en uno el valor de la variable LongitudSerpiente y lo haremos así. Código
También sabemos que cuando nos comemos una manzana debemos aumentar los puntos, yo en este caso he decidido que cada manzana valga 10 puntos, así que aumento en 10 el valor de la variable Puntos. Código
Al aumentar el tamaño de la serpiente, debemos incluir un nuevo elemento en el vector Serpiente y lo haremos con la siguiente linea. Código
Una vez hemos creado el nuevo elemento en el vector Serpiente, debemos darle una posición en la pantalla y para eso usaremos la posición del ultimo elemento de la cola de la serpiente, que si recordáis habíamos almacenado en la variable Ultimo. Código
Como hemos modificado el valor de la variable Puntos debemos actualizar el titulo de ventana para que nos muestre la nueva puntuación. Código
Y finalmente ya solo nos queda posicionar la manzana nuevamente en una posición aleatoria de la pantalla, como podemos ver aparte de colocar la manzana, debemos comprobar que no la ponemos sobre ninguno de los elementos que forman la serpiente, lo cual comprobaremos nuevamente con la función Colision, y en caso de que la colisión se produzca introduciremos 1 como valor de la Variable Control para que el bucle se vuelva a realizar y se genere otra posición aleatoria para la manzana. Código
Ya casi hemos terminado solo nos queda el tema gráfico y lo primero que vamos a hacer es limpiar la surface PantallaV pintándola del color del fondo en este caso negro. Código
Después posicionamos el dibujo de cada uno de los elementos que forman la serpiente en la surface PantallaV. Código
Posicionamos el dibujo de la manzana en la surface PantallaV. Código
Refrescamos el titulo de la ventana, por si la puntuación a sido modificada. Código
Ahora mostramos la surface PantallaV en la pantalla y esperamos los milisegundos necesarios para que el programa funcione mas o menos igual en todas las maquinas aunque sean mas rápidas. Código
Y por ultimo cuando el programa finalice devolvemos 0, esto hoy en día casi no se usa pero es una buena practica de programación y nos puede ayudar a mantener la compatibilidad del código con otros sistemas. Código
Bueno con esto terminamos el manual espero que os haya gustado y os sirva. Para cualquier duda os podéis poner en contacto conmigo en el foro o en mi email. kaltorak_@hotmail.com La versión en pdf del manual la tenis en el siguiente enlace, junto con el archivo compilado para windows y linux, así como el código fuente: http://ultrashare.net/hosting/fl/6a05538c64 (http://ultrashare.net/hosting/fl/6a05538c64) Un saludo Kaltorak. Título: Re: [Tutorial] Snake en C++/SDL Publicado por: dato000 en 13 Agosto 2013, 21:43 pm TOP 10 es un regalo de kaltorak para el mundo, si quieren hacer buenos juegos, ya saben a quien acudir, amchacon y kaltorak son unas eminencias en allegro y SDL, sean parte de nuestro grupo de diseño y programación de juegos.
EI: SIN SPAM Esperamos que la comunidad del hacker.net nos apoye, somos un grupo de emprendedores que gusta de la programación (bueno, yo al menos lo intento) y dejenme decirles, este post es sin lugar a dudas, de los mejores que pueden encontrar en toda la red, en cualquier idioma, es aún mejor que un videotutorial (y eso que soy fan incondicionable de mi sensei paueky) ya que encuentran absolutamente todo el material disponible para la causa, be water my friends!!! Título: Re: [Tutorial] Snake en C++/SDL Publicado por: crksergio en 14 Agosto 2013, 19:03 pm No sé cómo hay tan pocos (por no decir nada) comentarios en este tema. Felicitaciones por este tremendo tutorial, está buenísimo.
Título: Re: [Tutorial] Snake en C++/SDL Publicado por: kaltorak en 15 Agosto 2013, 08:18 am Me alegra mucho saber que les a gustado ;-)
Muchas gracias por el apoyo. Un saludo Kaltorak. Título: Re: [Tutorial] Snake en C++/SDL Publicado por: noalg en 15 Agosto 2013, 13:19 pm No sé cómo hay tan pocos (por no decir nada) comentarios en este tema. Felicitaciones por este tremendo tutorial, está buenísimo. +1 Yo creo que simplemente el tutorial habla por si solo, excelente. Título: Re: [Tutorial] Snake en C++/SDL Publicado por: Danyfirex en 15 Agosto 2013, 18:05 pm Gracias kaltorak muy interesante y útil.
saludos Título: Re: [Tutorial] Snake en C++/SDL Publicado por: vangodp en 16 Agosto 2013, 15:32 pm Joder muy bueno sii!! Gracias :o
Quiere ser mi amigo??? jajajaj ;-) :-* Título: Re: [Tutorial] Snake en C++/SDL Publicado por: kaltorak en 17 Agosto 2013, 18:41 pm Gracias chicos
Me gusta saber que os esta sirviendo ;) vangodp claro que si que podemos ser amigos, es mas todo el que quiera hacer algún desarrollo conmigo que me lo diga. Busco a alguien con un buen juego en mente para hacer, que tenga una buena historia y una buena mecánica y a alguien para hacer los gráficos de ese juego. todo el que quiera que se ponga en contacto conmigo por aquí ;) Un saludo kaltorak. Título: Re: [Tutorial] Snake en C++/SDL Publicado por: vangodp en 18 Agosto 2013, 16:07 pm Hombre juego en mente.... :rolleyes: as veces se me va explotar la cabeza y as veces po me quedo en blanco jajaj.
Tengo pensado hacer algo como Lord of Ultima, pero con algo mas de emoción jajaj. Aun que no se que hacer y soy novato extremo y me queda un camino largo.XD Me gusta los 2D ya que el 3D se necesita un batallón de programadores jeje. Algo pequeño seria mas guapo creo, algo que se puede hacer a nivel entre compaeros y no tán profissional. ::) Título: Re: [Tutorial] Snake en C++/SDL Publicado por: kaltorak en 19 Agosto 2013, 05:21 am Si la idea seria hacer algo no muy complicado, pero que tenga estilo propio que no se haya echo ya, la programación en 3d no seria un problema no se me da mal programar en opengl y siempre podemos usar un motor gráfico gratuito para aliviar la carga de programación, lo que necesito es una historia buena y una mecánica de juego fresca que no este muy trillada y si ya consigo a alguien que se encargue del apartado gráfico mejor que mejor :-\ , se que pido casi un imposible pues la gente normalmente no quiere hacer nada quieren que se lo demos todo echo, pero bueno soñar no cuesta nada.
Título: Re: [Tutorial] Snake en C++/SDL Publicado por: vangodp en 19 Agosto 2013, 06:59 am Hola soy yo jajaj
Sabes que salio la SDL 2.0?? Si sabes donde hay algunos tutoriales??... :D Título: Re: [Tutorial] Snake en C++/SDL Publicado por: kaltorak en 19 Agosto 2013, 10:03 am Hola vangodp
Mira este es el mejor manual que hay sobre SDL en español http://ultrashare.net/hosting/fl/c10d969b3b Son 670 paginas y trata todos los aspecto de la programación en SDL, incluyendo sus librerías mas famosas como son SDL_Image,SDL_Mixer,SDL_ttf,ETC.. Título: Re: [Tutorial] Snake en C++/SDL Publicado por: maxim_o en 20 Agosto 2013, 14:38 pm Aqui, hay varios libros sobre programación de videojuegos, no se si de un master o titulo propio de la UCLM, han liberado el material.
esi.uclm.es/videojuegos Seguro que a más de uno le interesa... Saludos |