0% encontró este documento útil (0 votos)
902 vistas34 páginas

Tutorial Snake

Este documento presenta el código para crear una versión simple del videojuego Snake usando C++ y la librería gráfica SDL. Explica cómo implementar los movimientos de la serpiente, comprobar colisiones con los bordes y su cola, y actualizar la puntuación cuando come la manzana generada aleatoriamente. El código consta de 280 líneas que dibujan la serpiente y manzana en cada iteración del bucle principal, reiniciando cuando haya una colisión.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
902 vistas34 páginas

Tutorial Snake

Este documento presenta el código para crear una versión simple del videojuego Snake usando C++ y la librería gráfica SDL. Explica cómo implementar los movimientos de la serpiente, comprobar colisiones con los bordes y su cola, y actualizar la puntuación cuando come la manzana generada aleatoriamente. El código consta de 280 líneas que dibujan la serpiente y manzana en cada iteración del bucle principal, reiniciando cuando haya una colisión.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

SNAKE

EN C++/SDL

Hola a todos
He creado este manual, por peticin de Dato000 miembro del grupo de desarrollo de
videojuegos al que pertenezco, en el voy a realizar una versin simple del videojuego
Snake(o serpiente), usando C++ y la librera grfica SDL, veris que con apenas 280 lineas
de cdigo, contando espacios y comentarios se puede hacer el videojuego Snake(o
serpiente) y que no es tan difcil 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 cdigo completo, para despus ir explicndolo linea a linea, doy
por sentado que el lector de este manual tiene una mnima base de programacin en C o C+
+.
Cdigo
1. //Juego Snake realizado por kaltorak para el manual Snake en SDL/C++
2.
3. #include <cstdlib>
4. #include <vector>
5. #include <time.h>
6. #include <SDL/SDL.h>
7.
8. //Prototipo de la funcion Colision.
9. int Colision(SDL_Rect,SDL_Rect);
10.
11. //Prototipo de la funcion Iniciar.
12. void Iniciar(void);
13.

14. /*definimos la direcciones que pude tomas la seriente con esto


conseguimos que el codigo sea mucho mas
15.

mas comprensible*/

16. #define Arriba 1


17. #define Derecha 2
18. #define Abajo 3
19. #define Izquierda 4
20.
21. /*Declaramos e inicializamos como constantes el ancho, el alto y la
profundidad de color
22.

de la ventana principal.*/

23. const int ResolucionX = 640;


24. const int ResolucionY = 480;
25. const int PColor = 32;
26.
27. const int DELAY = 85;
28.
29. //Declaramos e inicializamos la varible LongitudSerpiente la cual
contendra el tamao de la serpiente.
30. int LongitudSerpiente = 0;
31.
32. /*Declaramos e inicializamos la variable Direccion que contendra la
direccion en la que se esta
33.

moviendo la Serpiente.*/

34. int Direccion = 0;


35.

36. //Declaramos e inicializamos la variable control para controlar que la


manzana no coincida con al cola.
37. int Control = 0;
38.
39. /*Declaramos la variable memoria del tipoc SDL_Rect donde almacenaremos
la posion anterior anterior
40.

de la cabeza de la serpiente para poder mover la cola*/

41. SDL_Rect Ultimo;


42.
43. //Declaramos e inicializamos la variable Puntos que contendra los puntos
del juego.
44. int Puntos = 0;
45.
46. //Delcaramos e inicializamos la variable Titulo que contendra el titulo
de la ventana y la puntuacion.
47. char Titulo[255];
48.
49. using namespace std;
50.
51. /*Declaramos la estructura Cuadro que sera la encargada de almacenar la
posicion
52.

y el tamao de cada una de las partes que formaran el cuerpo de la


Serpiente*/

53. struct Cuadro


54. {
55.

SDL_Rect Posicion;

56.

Cuadro(){Posicion.x = 0;Posicion.y = 0;Posicion.w = 20;Posicion.h =


20;}

57. }Manzana;
58.
59. //Declaramos el Vector Serpiente del tipo Cuadro.
60. vector <Cuadro> Serpiente;
61.
62. int main ( int argc, char** argv )
63. {
64.
65.

srand(time(NULL));

66.
67.

//Inicializamos el modo de video de las SDL y comprobamos que se


inicialize bien.

68.

if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )

69.

70.

printf( "Imposible iniciar la libreria SDL: %s\n", SDL_GetError()


);

71.
72.

return 1;
}

73.
74.

//Itroducimos SDL_Quit en atexit para que se inice al finalizar el


programa.

75.

atexit(SDL_Quit);

76.
77.

/*Creamos la Surface principal del juego, la que se va a mostrar en


pantalla.

78.

y comprobamos que se inicie correctamente.*/

79.

SDL_Surface* PantallaV = SDL_SetVideoMode(ResolucionX, ResolucionY,


PColor,SDL_HWSURFACE|SDL_DOUBLEBUF);

80.

if ( !PantallaV )

81.

82.

printf("Imposible crear la ventana Principal: %s\n",


SDL_GetError());

83.
84.

return 1;
}

85.
86.

//Llamamos a la funcion Iniciar par poner todos los valores a cero.

87.

Iniciar();

88.
89.

// program main loop

90.

bool done = false;

91.

while (!done)

92.

93.

// message processing loop

94.

SDL_Event event;

95.

while (SDL_PollEvent(&event))

96.

97.

// check for messages

98.

switch (event.type)

99.

100.
101.
102.

// exit if the window is closed


case SDL_QUIT:
done = true;

103.

break;

104.
105.
106.
107.

// check for keypresses


case SDL_KEYDOWN:
{

108.

// exit if ESCAPE is pressed

109.

if (event.key.keysym.sym == SDLK_ESCAPE)

110.

111.

done = true;

112.

break;

113.
114.

}
if(event.key.keysym.sym == SDLK_UP && Direccion !=

Abajo)
115.

116.

Direccion = Arriba;

117.

break;

118.
119.

}
if(event.key.keysym.sym == SDLK_DOWN && Direccion

!= Arriba)
120.

121.

Direccion = Abajo;

122.

break;

123.
124.

}
if(event.key.keysym.sym == SDLK_LEFT && Direccion

!= Derecha)
125.

126.

Direccion = Izquierda;

127.

break;

128.

129.

if(event.key.keysym.sym == SDLK_RIGHT && Direccion

!= Izquierda)
130.

131.

Direccion = Derecha;

132.

break;

133.

134.

135.
136.

} // end switch
} // end of message processing

137.
138.

// DRAWING STARTS HERE

139.
140.
141.
142.

if(Direccion != 0)
{
//Almacenamos la posicion del ultimo de los elementos que

forman la cola en la variable Ultimo.


143.

Ultimo.x = Serpiente[LongitudSerpiente].Posicion.x;

144.

Ultimo.y = Serpiente[LongitudSerpiente].Posicion.y;

145.
146.

//Movemos la cola de la serpiente.

147.

for(int I = LongitudSerpiente; I >= 1; I--)

148.
149.

{
Serpiente[I].Posicion.x = Serpiente[I-1].Posicion.x;

150.

Serpiente[I].Posicion.y = Serpiente[I-1].Posicion.y;

151.
152.

}
}

153.
154.
155.

if(Direccion == Arriba)
{

156.
157.
158.
159.

Serpiente[0].Posicion.y -= Serpiente[0].Posicion.h;
}
else if(Direccion == Abajo)
{

160.
161.
162.
163.

Serpiente[0].Posicion.y += Serpiente[0].Posicion.h;
}
else if(Direccion == Derecha)
{

164.
165.
166.
167.

Serpiente[0].Posicion.x += Serpiente[0].Posicion.w;
}
else if(Direccion == Izquierda)
{

168.
169.

Serpiente[0].Posicion.x -= Serpiente[0].Posicion.w;
}

170.
171.

//Comprobamos la colision de la serpiente con el borde.

172.

if(((Serpiente[0].Posicion.x + Serpiente[0].Posicion.w)

ResolucionX)
173.

|| (Serpiente[0].Posicion.x < 0)

>

174.

|| ((Serpiente[0].Posicion.y + Serpiente[0].Posicion.h)
> ResolucionY)

175.
176.

|| (Serpiente[0].Posicion.y < 0))


{

177.
178.

Iniciar();
}

179.
180.

//Comprobamos la colision de la serpiente con la cola.

181.

for(int I = 1; I <= LongitudSerpiente; I++)

182.

183.

if(Colision(Serpiente[0].Posicion,Serpiente[I].Posicion))

184.

185.

Iniciar();

186.
187.

}
}

188.
189.

//Comprobamos la colision de la serpiente con la Manzana.

190.

if(Colision(Serpiente[0].Posicion,Manzana.Posicion))

191.

192.

LongitudSerpiente++;

193.

Puntos += 10;

194.

Serpiente.push_back(Cuadro());

195.

Serpiente[LongitudSerpiente].Posicion.x = Ultimo.x;

196.

Serpiente[LongitudSerpiente].Posicion.y = Ultimo.y;

197.

198.

//Metemos en la varible Titulo el titulo de la ventana

seguido de la puntuacion del juego.


199.

sprintf(Titulo,"Snake -- Puntos: %d",Puntos);

200.
201.

/*Posicionamos denuevo la manazana en pantalla y comprobamos

que la nueva ubicacion


202.

no este ocupada por la cola de la Serpiente.*/

203.

do

204.

205.

Manzana.Posicion.x = ((rand() % ((ResolucionX-

Manzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);
206.

Manzana.Posicion.y = ((rand() % ((ResolucionY-

Manzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);
207.

Control = 0;

208.

for(int I = 1; I <= LongitudSerpiente; I++)

209.

210.

if(Colision(Manzana.Posicion,Serpiente[I].Posicion))

211.

212.

Control = 1;

213.

I = LongitudSerpiente;

214.

215.

216.

217.
218.
219.

while(Control == 1);
}

220.

//Borramos la surface principal

221.

SDL_FillRect(PantallaV, 0, SDL_MapRGB(PantallaV->format, 0, 0,

0));
222.
223.

//Pintamos la serpiente en la Surface principal

224.

for(int I = 0; I <= LongitudSerpiente; I++)

225.

226.
SDL_FillRect(PantallaV,&Serpiente[I].Posicion,SDL_MapRGB(PantallaV>format, 255, 255, 255));
227.

228.
229.

//Pintamos la manzana en la Surface principal

230.

SDL_FillRect(PantallaV,&Manzana.Posicion,SDL_MapRGB(PantallaV-

>format, 0, 255, 0));


231.
232.

//Cambiamos el titulo de la ventana por Snake.

233.

SDL_WM_SetCaption (Titulo, NULL);

234.
235.

//Mostramos la Surface principal en pantalla.

236.

SDL_Flip(PantallaV);

237.

SDL_Delay(DELAY);

238.

} // end main loop

239.
240.
241.

return 0;

242. }
243.
244. //Funcion que compruba las colisiones entre los elementos de juego.
245. int Colision(SDL_Rect H,SDL_Rect M)
246. {
247.

if (((H.x + H.w) > M.x) && ((H.y + H.h) > M.y) &&

248.

((M.x + M.w) > H.x) && ((M.y + M.h) > H.y))

249.

250.

return 1;

251.

252.

else

253.

254.

return 0;

255.

256. }
257.
258. //Funcion que reinicia el juego cuando la serpiente colisiona con ella
misma o el borde.
259. void Iniciar(void)
260.
261.

{
/*Ponemos el valor de la variable longitudSerpiente a 0 para que la

serpiente solo este formada por


262.
263.
264.

la cabeza.*/
LongitudSerpiente = 0;
//Ponemos el valor de la variable Direccion a 0 para que la

serpiente aparezca parada al comenzar el juego.

265.

Direccion = 0;

266.

//Ponemos el valor de la variable Puntos a 0 para reiniciar el

marcador de puntos.
267.

Puntos = 0;

268.

//Metemos en la varible Titulo el titulo de la ventana seguido de la

puntuacion del juego.


269.

sprintf(Titulo,"Snake -- Puntos: %d",Puntos);

270.

//Borramos todos los miembros que forman el vector Serpiente

271.

Serpiente.clear();

272.

//Aadimos un miembro en el vector serpiente que contendra la cabeza

de la serpiente.
273.

Serpiente.push_back(Cuadro());

274.

//Posicionamos aleatoriamente la manzana en la pantalla.

275.

Manzana.Posicion.x = ((rand() % ((ResolucionX-

Manzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);
276.
277.

Manzana.Posicion.y = ((rand() % ((ResolucionY-

Manzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);
278.

//Posicionamos la cabeza de la serpiente en el centro de la

pantalla.
279.

Serpiente[0].Posicion.x =

(((ResolucionX/Serpiente[0].Posicion.w)/2)*Serpiente[0].Posicion.w);
280.

Serpiente[0].Posicion.y =

(((ResolucionY/Serpiente[0].Posicion.h)/2)*Serpiente[0].Posicion.h);
281.

282.

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, convirtindose en un
clsico tras su salida en 1998 en todos los dispositivos mviles 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 direccin, para que se coma las manzanas y evite chocar.
Comencemos a analizar el cdigo.
Comenzamos incluyendo las libreras que vamos a necesitar para el buen funcionamiento del
cdigo.
La librera estndar "cstdlib "
Cdigo
1. #include <cstdlib>

La librera vector para la creacin de una lista de vectores, que controlen el tamao de
serpiente.
Cdigo
1. #include <vector>

La librera time.h para generar aleatoriamente la posicin en la que va a aparecer la


manzana en el juego, cada vez que esta sea devorada por la serpiente.
Cdigo
1. #include <time.h>

Y por ultimo la librera SDL.h la cual vamos usar para manejar el entorno grfico y las
pulsaciones del teclado.
Cdigo
1. #include <SDL/SDL.h>

Las siguiente lineas de cdigo son los prototipos de las funciones Colision y Iniciar, de
las cuales explicare su funcionamiento mas adelante.
Cdigo
1. int Colision(SDL_Rect,SDL_Rect);
2.
3. void Iniciar(void);

4.

Ahora vamos a usar la directiva #define para crear unas macros, las cuales nos ayudaran
a entender mejor el cdigo.
Lo que estas macros hacen es que trabajemos con las direcciones reales en las que se
mueve la serpiente y no nmeros pues tras un tiempo sin usar el cdigo no sabramos que
significaba cada numero.
Mirar a la direccin Arriba le adjudicamos el numero 1, lo que hace esta macro es que en el
cdigo podemos poner Arriba y sabremos que significa 1, despus el preprocesador
cambiara las palabra Arriba por un 1 antes de compilar el cdigo, como bien he dicho esto
es solo por limpieza y para mejorar la compresin del cdigo para futuras modificaciones o
para que sea comprensible para otra persona que no sea el programador del mismo.
Cdigo
1. #define Arriba 1
2. #define Derecha 2
3. #define Abajo 3
4. #define Izquierda 4

Tras estas lineas vamos a definir el ancho y alto de la pantalla principal as como la
profundidad de color de la misma.
Cdigo
1. const int ResolucionX = 640;
2. const int ResolucionY = 480;
3. const int PColor = 32;

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 rpidas
Cdigo
1. const int DELAY = 85;

Declaramos e inicializamos la variable LongitudSerpiente la cual contendr el tamao de la


serpiente, la iniciamos con valor 0 para que en un principio solo contenga la cabeza de la
serpiente.
Cdigo
1. int LongitudSerpiente = 0;

Declaramos e inicializamos la variable Direccin, que contendr la direccin 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.
Cdigo
1. int Direccion = 0;

Declaramos e inicializamos la variable control para controlar la permaneca o la salida del


bucle que controla el chequeo de la manzana al ser creada, para que no coincida en una
posicin de la pantalla en la cual se encuentre la serpiente.
Cdigo
1. int Control = 0;

Declaramos la variable Ultimo del tipo SDL_Rect donde almacenaremos la posicin del
ultimo cuadro que forma la cola de la serpiente, para cuando tengamos que aadir un nuevo
cuadro a la cola tras la ingesta de una manzana, sepamos donde posicionarlo con respecto al
resto de la serpiente.
Cdigo
1. SDL_Rect Ultimo;

Declaramos e inicializamos la variable Puntos que contendr los puntos del juego.
Cdigo
1. int Puntos = 0;

Declaramos la variable Titulo que contendr el titulo de la ventana y la puntuacin.


Cdigo
1. char Titulo[255];

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 estndar de C++
Cdigo
1. using namespace std;

Declaramos la estructura Cuadro que sera la encargada de almacenar la posicin y el


tamao, de cada una de las partes que formaran el cuerpo de la Serpiente y la Manzana.

Si os fijis tambin 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 tamao de 20 pxeles.
Cdigo
1. struct Cuadro
2. {
3.

SDL_Rect Posicion;

4.

Cuadro(){Posicion.x = 0;Posicion.y = 0;Posicion.w = 20;Posicion.h =


20;}

5. }Manzana;

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 algn miembro que no no interese,
como no sabremos que tamao 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 tamao de un cuadro y multiplicar los resultados, despus le
restamos 1 para poder posicionar la manzana y tendremos el tamao total que podr tener
nuestra serpiente.
Por ejemplo si la pantalla midiera 640x480 y cada cuadro que forma la serpiente
midiera 20 pxeles, la forma de saber el tamao mximo que podr alcanzar nuestra
serpiente sera as:
640/20 = 32
480/20 = 24
32 * 24 = 768
768 1 = 767
Nuestra serpiente podra tener un tamao mximo de 767 cuadros y podramos generar un
array de 767 elementos y evitar usar vectores, pero de esta manera estaramos
desperdiciando mucha memoria que mas de un 90% de las veces no sera usada, por este
motivo y como es una buena practica de programacin ahorrar memoria vamos a usar
vectores.
Cdigo
1. vector <Cuadro> Serpiente;

la funcin main no necesita presentacin


Cdigo
1. int main ( int argc, char** argv )
2. {

Usaremos la funcin srand con time como semilla para la generacin de numeros aleatorios
para posicionar la manzana en pantalla.
Cdigo
1. srand(time(NULL));

Inicializamos el modo de vdeo de las SDL y comprobamos que se inicialice bien.


Cdigo
1. if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
2.

3.

printf( "Imposible iniciar la libreria SDL: %s\n", SDL_GetError() );

4.

return 1;

5.

Introducimos SDL_Quit en atexit para que se inicie al finalizar el programa, saliendo as de


la librera SDL siempre que el programa finalice.
Cdigo
1. atexit(SDL_Quit);

Creamos la Surface principal del juego, la que se va a mostrar en pantalla y comprobamos


que se inicie correctamente.
Cdigo
1. SDL_Surface* PantallaV = SDL_SetVideoMode(ResolucionX,
ResolucionY,PColor,SDL_HWSURFACE|SDL_DOUBLEBUF);
2.
3.
4.

if ( !PantallaV )
{
printf("Imposible crear la ventana Principal: %s\n",
SDL_GetError());

5.
6.

return 1;
}

Llamamos a la funcin Iniciar para poner todos los valores a cero.


Cdigo
1. Iniciar();

A continuacin voy a pasar a explicar la funcin Iniciar y despus regresare al cdigo en la


linea siguiente a Iniciar();.
La funcin 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.
Cdigo
1. void Iniciar(void)
2. {
3.

/*Ponemos el valor de la variable longitudSerpiente a 0 para que la


serpiente solo este formada por

4.

la cabeza.*/

5.

LongitudSerpiente = 0;

6.

/*Ponemos el valor de la variable Direccion a 0 para que la serpiente


aparezca parada al comenzar

7.
8.

el juego.*/

Direccion = 0;
//Ponemos el valor de la variable Puntos a 0 para reiniciar el marcador
de puntos.

9.

Puntos = 0;

10. //Metemos en la variable Titulo el titulo de la ventana seguido de la


puntuacin del juego.
11. sprintf(Titulo,"Snake -- Puntos: %d",Puntos);
12. //Borramos todos los miembros que forman el vector Serpiente
13. Serpiente.clear();
14. //Aadimos un miembro en el vector serpiente que contendr la cabeza de
la serpiente.
15. Serpiente.push_back(Cuadro());

16. //Posicionamos aleatoriamente la manzana en la pantalla.


17. Manzana.Posicion.x = ((rand() % ((ResolucionXManzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);
18. Manzana.Posicion.y = ((rand() % ((ResolucionYManzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);
19. //Posicionamos la cabeza de la serpiente en el centro de la pantalla.
20. Serpiente[0].Posicion.x =
(((ResolucionX/Serpiente[0].Posicion.w)/2)*Serpiente[0].Posicion.w);
21. Serpiente[0].Posicion.y =
(((ResolucionY/Serpiente[0].Posicion.h)/2)*Serpiente[0].Posicion.h);
22. }
23.

Analicemos mas profundamente la manera de posicionar la manzana aleatoriamente en la


pantalla
Cdigo
1.

Manzana.Posicion.x = ((rand() % ((ResolucionXManzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);

2.

Manzana.Posicion.y = ((rand() % ((ResolucionYManzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);

Sabemos que las medidas de la pantalla estn almacenadas dentro de las


variables ResolucionX para el ancho y ResolucionY para el alto, las coordenadas que
definen la posicin de la manzana se posicionan en la esquina superior izquierda de la
misma.

As que si por un casual el ancho aleatorio que nos saliera fuera 640, la manzana se
colocara fuera de la pantalla por el lado derecho de la misma o si el valor para el alto
generado aleatoriamente coincidiera con 480, pasara lo mismo que en el caso anterior pero
esta vez la manzana se dibujara 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 enManzana.Posicion.h.
Cdigo
1. (ResolucionX-Manzana.Posicion.w)
2. (ResolucionY-Manzana.Posicion.h)

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.
Cdigo
1. (ResolucionX-Manzana.Posicion.w)/Manzana.Posicion.w)
2. (ResolucionY-Manzana.Posicion.h)/Manzana.Posicion.h)

Y por ultimo ya solo nos queda multiplicar el resultado de la operacin 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.
Cdigo
1. Manzana.Posicion.x = ((rand() % ((ResolucionXManzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);
2.

Manzana.Posicion.y = ((rand() % ((ResolucionYManzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);

Para posicionar la serpiente en el centro de la pantalla usamos el mismo mtodo que para
posicionar la manzana, pero lgicamente sin usar nmeros 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 posicin de la cabeza y la
manzana correspondern perfectamente.
Cdigo
1. Serpiente[0].Posicion.x =
(((ResolucionX/Serpiente[0].Posicion.w)/2)*Serpiente[0].Posicion.w);
2. Serpiente[0].Posicion.y =
(((ResolucionY/Serpiente[0].Posicion.h)/2)*Serpiente[0].Posicion.h);

Una vez explicada la funcin Iniciar vamos a continuar con el cdigo.


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 declaracin creamos el bucle principal del
juego que se repetir siempre que el valor de la variable done se a false (o 0).
Cdigo
1. bool done = false;
2. while (!done)

3.

Lo primero que vamos a encontrar dentro del bucle principal del juego es el mtodo 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.
Cdigo
1.

SDL_Event event;

2.

while (SDL_PollEvent(&event))

3.

4.

switch (event.type)

5.

6.

case SDL_QUIT:

7.

done = true;

8.

break;

9.
10.

case SDL_KEYDOWN:

11.

12.

if (event.key.keysym.sym == SDLK_ESCAPE)

13.

14.

done = true;

15.

break;

16.

17.

if(event.key.keysym.sym == SDLK_UP && Direccion !=


Abajo)

18.

19.

Direccion = Arriba;

20.

break;

21.

22.

if(event.key.keysym.sym == SDLK_DOWN && Direccion !=


Arriba)

23.

24.

Direccion = Abajo;

25.

break;

26.

27.

if(event.key.keysym.sym == SDLK_LEFT && Direccion !=


Derecha)

28.

29.

Direccion = Izquierda;

30.

break;

31.

32.

if(event.key.keysym.sym == SDLK_RIGHT && Direccion !=


Izquierda)

33.

34.

Direccion = Derecha;

35.

break;

36.

37.

38.
39.

}
}

Declaramos event del tipo SDL_Event, que es donde almacenaremos los mensajes que
recibamos del sistema.
Cdigo
1. SDL_Event event;

Despus crearemos un bucle que se repetir siempre que queden mensajes del sistema por
procesar, al mismo tiempo almacenamos dichos mensajes en la variableevent creada
anteriormente.
Cdigo
1. while (SDL_PollEvent(&event))
2.

Tras lo cual procederemos a leer el mensaje del sistema almacenado en la variable event
Cdigo
1. switch (event.type)
2.

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.
Cdigo
1. case SDL_QUIT:
2.

done = true;

3.

break;

Otro de los mensajes del sistema que vamos a monitorizar, sera si una tecla a sido pulsada
para ello usaremos
Cdigo
1. case SDL_KEYDOWN:
2.

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.
Cdigo
1. if (event.key.keysym.sym == SDLK_ESCAPE)
2.

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.
Cdigo
1. done = true;
2. break;
3. }

Despus realizaremos la comprobacin con las teclas de direccin, empezando por la tecla de
direccin Arriba o lo que es lo mismo SDLK_UP, pero adems de comprobar que la tecla
haya sido pulsada podremos ver en el cdigo que se realiza otra comprobacin,Esta
comprobacin es que la variable Direccin no contenga el valor Abajo, esto lo hacemos por
que la serpiente no puede andar hacia atrs y si la variable Direccin contiene el
valor Abajo, la serpiente esta yendo hacia abajo en la pantalla, por lo tanto la tecla de
direccin 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 Direccin por Arriba y de este modo le decimos a la
serpiente la direccin que debe tomar a partir de ahora.
Cdigo
1. if(event.key.keysym.sym == SDLK_UP && Direccion != Abajo)
2.

3.

Direccion = Arriba;

4.

break;

5.

Explicado esto el resto de las comprobaciones que se realizan a las teclas de direccin son
iguales a la comprobacin de la tecla de direccin Arriba, pero obviamente cambiando la
direccin del movimiento de la serpiente.
Cdigo
1.

if(event.key.keysym.sym == SDLK_DOWN && Direccion !=


Arriba)

2.

3.

Direccion = Abajo;

4.

break;

5.

6.

if(event.key.keysym.sym == SDLK_LEFT && Direccion !=


Derecha)

7.

8.

Direccion = Izquierda;

9.

break;

10.

11.

if(event.key.keysym.sym == SDLK_RIGHT && Direccion !=


Izquierda)

12.

13.

Direccion = Derecha;

14.

break;

15.

16.

17.
18.

}
}

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 Direccin 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 posicin del
ultimo cuadro que forma la cola de la serpiente antes de que este sea movido de su posicin
actual esto lo hacemos para saber la posicin en la que tendremos que colocar un nuevo
cuadro si la serpiente se come la manzana
Cdigo
1. if(Direccion != 0)
2. {
3.

Ultimo.x = Serpiente[LongitudSerpiente].Posicion.x;

4.

Ultimo.y = Serpiente[LongitudSerpiente].Posicion.y;

Despus de almacenar la posicin del ultimo cuadro que forma la cola de la serpiente,
vamos a mover la posicin de los cuadros que forman la cola de la serpiente mediante el
siguiente for, empezando por el ultimo a la posicin del cuadro que se encuentra una
posicin 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 tamao actual de la serpiente y
recorreremos los elementos que forman el vector Serpiente, hasta alcanzar el cuadro mas
prximo 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 posicin o lo que es lo mismo 20 pxeles
por la pantalla.
Cdigo
1.

//Movemos la cola de la serpiente.

2.

for(int I = LongitudSerpiente; I >= 1; I--)

3.

4.

Serpiente[I].Posicion.x = Serpiente[I-1].Posicion.x;

5.

Serpiente[I].Posicion.y = Serpiente[I-1].Posicion.y;

6.
7.

}
}

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 posicin 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 direccin
que le digamos usando el teclado por ese motivo la movemos con los siguientes if,
Cdigo
1.
2.

if(Direccion == Arriba)
{

3.
4.
5.

Serpiente[0].Posicion.y -= Serpiente[0].Posicion.h;
}
else if(Direccion == Abajo)

6.

7.

Serpiente[0].Posicion.y += Serpiente[0].Posicion.h;

8.
9.
10.

}
else if(Direccion == Derecha)
{

11.
12.
13.
14.

Serpiente[0].Posicion.x += Serpiente[0].Posicion.w;
}
else if(Direccion == Izquierda)
{

15.
16.

Serpiente[0].Posicion.x -= Serpiente[0].Posicion.w;
}

Si la variable Direccin contiene Arriba eso significa por lo que vimos antes que hemos
usado la tecla de direccin Arriba entonces debemos mover la serpiente por la pantalla hacia
arriba esto lo hacemos modificando la variable que contiene la direccin 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.
Cdigo
1.
2.

if(Direccion == Arriba)
{

3.
4.

Serpiente[0].Posicion.y -= Serpiente[0].Posicion.h;
}

El resto de los else if son exactamente iguales pero lgicamente alterando la los variables en
concordancia en la direccin en que deba ser movida la serpiente
Cdigo
1.
2.

else if(Direccion == Abajo)


{

3.
4.
5.

Serpiente[0].Posicion.y += Serpiente[0].Posicion.h;
}
else if(Direccion == Derecha)

6.

7.
8.
9.
10.

Serpiente[0].Posicion.x += Serpiente[0].Posicion.w;
}
else if(Direccion == Izquierda)
{

11.
12.

Serpiente[0].Posicion.x -= Serpiente[0].Posicion.w;
}

Ahora vamos a comprobar la colisin de la cabeza de la serpiente con el borde, para ello
tenemos que comprobar que la posicin x e y de la serpiente se encuentre dentro de los
limites de la pantalla, fijaros bien pues pasa lo mismo que cuando queramos colocar la
manzana dentro de los limites de la pantalla, como los puntos de posicin del cuadro que
forma la cabeza de la serpiente estn en la esquina superior izquierda del cuadro, para
comprobar que la colisin 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 colisin reiniciaremos el
juego llamando a la funcin Iniciar la cual os explique su funcionamiento anteriormente.
Cdigo
1.

if(((Serpiente[0].Posicion.x + Serpiente[0].Posicion.w)

>

ResolucionX)
2.

|| (Serpiente[0].Posicion.x < 0)

3.

|| ((Serpiente[0].Posicion.y + Serpiente[0].Posicion.h)

>

ResolucionY)
4.
5.

|| (Serpiente[0].Posicion.y < 0))


{

6.
7.

Iniciar();
}

8.

Una vez hemos realizado la comprobacin de la colisin con el borde de la pantalla, vamos a
realizar la comprobacin de la colisin de la cabeza de la serpiente con la cola, para ello
vamos a usar la funcin Colision la cual os explicare a continuacin y despus seguiremos
viendo el cdigo
Como podis ver la funcin Colision es muy simple lo que hace es comprobar si el cuadro
que le pasamos como primer miembro de la funcin se encuentra dentro o en contacto con el

cuadro que le pasamos como segundo miembro de la funcin, si estn en contacto


devuelve 1 y en caso contrario devuelve 0.
Cdigo
1. int Colision(SDL_Rect H,SDL_Rect M)
2. {
3.

if (((H.x + H.w) > M.x) && ((H.y + H.h) > M.y) &&

4.
5.

((M.x + M.w) > H.x) && ((M.y + M.h) > H.y))


{

6.

return 1;

7.

8.

else

9.

10.
11.

return 0;
}

12. }

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 lgicamente 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 saltndonos la cabeza de la serpiente y comprobaremos mediante la
funcin Colision si existe colisin con la cabeza de la serpiente que es el elemento 0 del
vector, en caso de que la funcin Colisiondevuelva 1 quiere decir como vimos antes que la
colisin se a producido y entramos dentro del bloque del if donde mediante la
funcin Iniciar reiniciamos el juego .
Cdigo
1.

//Comprobamos la colision de la serpiente con la cola.

2.

for(int I = 1; I <= LongitudSerpiente; I++)

3.
4.
5.

{
if(Colision(Serpiente[0].Posicion,Serpiente[I].Posicion))
{

6.

Iniciar();

7.
8.

}
}

Ya solo nos queda comprobar si la serpiente se a comido la manzana lo cual haremos


nuevamente con la funcin Colision y un if, esta vez comprobaremos la cabeza de la
serpiente y la manzana como podemos ver , en caso de que la colisin se produzca
entraremos en el bloque del if.
Cdigo
1.
2.

if(Colision(Serpiente[0].Posicion,Manzana.Posicion))
{

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.
Cdigo
1. LongitudSerpiente++;

Tambin 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.
Cdigo
1. Puntos += 10;

Al aumentar el tamao de la serpiente, debemos incluir un nuevo elemento en el


vector Serpiente y lo haremos con la siguiente linea.
Cdigo
1. Serpiente.push_back(Cuadro());

Una vez hemos creado el nuevo elemento en el vector Serpiente, debemos darle una
posicin en la pantalla y para eso usaremos la posicin del ultimo elemento de la cola de la
serpiente, que si recordis habamos almacenado en la variable Ultimo.
Cdigo
1. Serpiente[LongitudSerpiente].Posicion.x = Ultimo.x;
2. Serpiente[LongitudSerpiente].Posicion.y = Ultimo.y;

Como hemos modificado el valor de la variable Puntos debemos actualizar el titulo de


ventana para que nos muestre la nueva puntuacin.
Cdigo
1. sprintf(Titulo,"Snake -- Puntos: %d",Puntos);

Y finalmente ya solo nos queda posicionar la manzana nuevamente en una posicin 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 funcin Colision, y en caso de que la colisin se
produzca introduciremos 1 como valor de la Variable Control para que el bucle se vuelva a
realizar y se genere otra posicin aleatoria para la manzana.
Cdigo
1. do {
2.

Manzana.Posicion.x = ((rand() %

((ResolucionX-

Manzana.Posicion.w)/Manzana.Posicion.w))*Manzana.Posicion.w);
3.

Manzana.Posicion.y = ((rand() %

((ResolucionY-

Manzana.Posicion.h)/Manzana.Posicion.h))*Manzana.Posicion.h);
4.

Control = 0;

5.

for(int I = 1; I <= LongitudSerpiente; I++)

6.

7.

if(Colision(Manzana.Posicion,Serpiente[I].Posicion))

8.

9.

Control = 1;

10.

I = LongitudSerpiente;

11.

12.
13.
14.
15. }
16.

}
}
while(Control == 1);

Ya casi hemos terminado solo nos queda el tema grfico y lo primero que vamos a hacer es
limpiar la surface PantallaV pintndola del color del fondo en este caso negro.
Cdigo
1. SDL_FillRect(PantallaV, 0, SDL_MapRGB(PantallaV->format, 0, 0, 0));

Despus posicionamos el dibujo de cada uno de los elementos que forman la serpiente en la
surface PantallaV.
Cdigo
1. for(int I = 0; I <= LongitudSerpiente; I++)
2.

3.

SDL_FillRect(PantallaV,&Serpiente[I].Posicion,SDL_MapRGB(PantallaV>format, 255, 255,

4.

255));

Posicionamos el dibujo de la manzana en la surface PantallaV.


Cdigo
1. SDL_FillRect(PantallaV,&Manzana.Posicion,SDL_MapRGB(PantallaV->format,
0, 255, 0));

Refrescamos el titulo de la ventana, por si la puntuacin a sido modificada.


Cdigo
1. SDL_WM_SetCaption (Titulo, NULL);

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 rpidas.
Cdigo
1.

SDL_Flip(PantallaV);

2.

SDL_Delay(DELAY);

3. }
4.

Y por ultimo cuando el programa finalice devolvemos 0, esto hoy en da casi no se usa pero
es una buena practica de programacin y nos puede ayudar a mantener la compatibilidad del
cdigo con otros sistemas.
Cdigo
1.

return 0;

2. }

Bueno con esto terminamos el manual espero que os haya gustado y os sirva.
Para cualquier duda os podis poner en contacto conmigo en el foro o en mi email.
[email protected]
La versin en pdf del manual la tenis en el siguiente enlace, junto con el archivo compilado
para windows y linux, as como el cdigo fuente:
http://ultrashare.net/hosting/fl/6a05538c64
Un saludo
Kaltorak.

También podría gustarte