Sunteți pe pagina 1din 18

3-7-2014

Desarrollo de
Juego Snake
Proyecto Final
Bertin Rogelio Gmez Rendn
UNIVERSIDAD IBEROAMERICANA PUEBLA VERANO 2014
MTI. LOURDES AGUILAR LPEZ
1

DESARROLLO DE JUEGO
SNAKE
(Proyecto Final)
Analisis del problema
Se desea desarrollar aplicando los conocimientos adquiridos a lo largo del curso
Estructura de Datos un programa que evidencie lo aprendido implementando
sentencias y cdigo en lenguaje C/C++.
Con base en lo anterior se opt por desarrollar un juego que aunque antiguo
conjuga en su estructura funciones y sentencias que fueron revisadas en el curso
y que permiten la implementacin del mismo.
El Snake, tambin conocido como el juego de la serpiente, es un video
juego lanzado a mediados de los 70 que aumento su popularidad desde
entonces a la fecha, convirtindose en un clsico. Obtuvo una audiencia masiva
tras convertirse en un juego estndar pre-grabado en los telfonos Nokia de 1998.
Actualmente el Snake es un juego nivel intermedio que puede ser desarrollado
bajo diferentes lenguajes de programacin.
En el caso de la implementacin de este juego en lenguaje C se sabe que exige
conocer variedad de estructuras y conceptos de implementacin como pilas,
colas, matrices, funciones y recursin, incluso para hacer ms vistoso el juego es
posible implementar cdigo en modo grfico.
El Snake clsico como cualquier otro juego tiene ciertas caractersticas que
debern ser tomadas en cuenta por el desarrollador:
Deber existir un campo de juego limitado y preestablecido que ser la
seccin en donde podr moverse la serpiente libremente.
La forma en cmo se represente la serpiente deber tener como
caracterstica principal movimiento como mnimo izquierda, derecha,
2

arriba, abajo, esto permitir al usuario guiar a la serpiente por sobre el
campo de juego.
En el juego se posicionar comida para la serpiente, en cuanto la
serpiente coma dicha comida deber generarse una nueva comida
aleatoriamente por sobre el campo de juego.
En cuanto coma la serpiente deber existir un aumento en el tamao del
cuerpo de la misma lo que aumenta la dificultad a la hora de maniobrar.
Existen 2 formas de perder en el juego, la primera consiste en chocar con
el mismo cuerpo de la serpiente y, la segunda apunta a chocar con
cualquiera de las paredes que limitan el campo de juego.
Para aumentar dificultad pueden incluirse indicadores de puntuacin que
permitan visualizar el nmero de comidas hechas por la serpiente y, en
base a ello dado un nmero especfico de comidas hechas es posible
incrementar la velocidad de desplazamiento de la serpiente haciendo
ms difcil el control del cuerpo en movimiento.

Desarrollo de la solucin
A continuacin se proceder a describir las funciones que sern tomadas en
cuenta para general el cdigo del juego.
Lo primero y esencial como en cualquier programa es el incluir las libreras para
uso de funciones, en este caso se usaron las siguientes.

Llamado de libreras

#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>


Posterior a la declaracin de las libreras se procede a declarar las variables
globales, las cuales sern usadas en las funciones posteriormente incluidas.

DECLARACIN DE VARIABLES GLOBALES
Creacin variable entera array cuerpo
Creacin variable entera de ndices del cuerpo
3

Creacin variable entera de tamao del cuerpo
Creacin variable entera de coordenadas de la serpiente
Creacin variable entera de variable direccin
Creacin variable entera de coordenadas comida
Creacin variable entera de velocidad inicial
Creacin variable entera nivel inicial
Creacin variable entera puntuacin inicial
Creacin variable de tipo carcter que almacena entrada de teclado
Creacin variable entera mayor puntuacin

int cuerpo[200][2];
int n=1; //controla indices del cuerpo
int tam=3; //tamao del cuerpo
int x=10, y=12; //coordenadas de la serpiente
int dir=3; //variable direccion
int xc=30, yc=15; //coordenadas comida
int velocidad=150, h=1; //velocidad inicial y nivel inicial
int puntos=0; //puntuacin inicial
char tecla; //variable tipo tecla que almacena entrada de teclado
int mayorp=0;


Para conseguir movimiento de la serpiente ser necesario que el programa
responda bajo impulsos desde el teclado hechos por el usuario, bajo esa
caracterstica con las siguientes definiciones se consigue asociar las teclas que
regirn la interaccin de movimiento del juego con el usuario, en este caso las
flechas del teclado sern las encargadas de darle direccin al objeto principal
del juego.

ASOCIACIN TECLAS DIRECCIN
Define ARRIBA
Define IZQUIERDA
Define DERECHA
Define ABAJO
Define SALIR

// NMEROS ASOCIADOS A LAS FLECHAS DEL TECLADO
#define ARRIBA 72
#define IZQUIERDA 75
#define DERECHA 77
#define ABAJO 80
#define ESC 27


Para facilitar la codificacin del juego y considerando que es ms fcil el
desarrollo del mismo usando coordenadas se pens en incluir una funcin que
4

permite posicionarse por sobre la pantalla de salida, gotoxy(x,y) permite
posicionar mediante coordenadas impresiones de pantalla

FUNCIN POSICIN X-Y
Declaracin tipo vaco funcin posicin (paso de coordenadas x,y)
Declaracin de variables

Almacena en variable nueva x por paso de parmetros
Almacena en variable nueva y por paso de parmetros

Traduccin de coordenadas a posicin en pantalla.

//Funcion posicion x-y
void gotoxy(int x, int y)
{
HANDLE hCon;
COORD dwPos;

dwPos.X = x;
dwPos.Y = y;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hCon,dwPos);
}


Para generar un campo especifico de juego la funcin pintar() genera un
margen establecido X,Y. Para este caso se decidi limitar a X mxima = 78 y Y
mxima = 24 formando un espacio de juego libre de 78 x 24.

FUNCIN MARGEN DE JUEGO
Declaracin de funcin pintar
Para horizontal de 2 a 77
Incremento en posicin (horizontal,Y) imprime margen ACSII
Horizontal +1

Para vertical de 4 a 22
Incremento en posicin (vertical,Y) imprime margen ACSII
Vertical +1

Para esquinas
Posicin esquina (X,Y) imprime margen ACSII


//Funcion margen de juego
void pintar()
{
// Lneas horizontales
5

for(int h=2; h < 78; h++)
{
gotoxy (h, 3); printf ("%c", 205); // los nmeros hacen referencia al cdigo acsii
gotoxy(h, 23); printf ("%c", 205);
}
//Lneas verticales
for(int v=4; v < 23; v++)
{
gotoxy (2,v); printf ("%c", 186);
gotoxy(77,v); printf ("%c", 186);
}
// Esquinas
gotoxy(2,3); printf ("%c", 201);
gotoxy(2,23); printf ("%c", 200);
gotoxy(77,3); printf ("%c", 187);
gotoxy(77,23); printf ("%c", 188);
}


Ahora ser necesario desarrollar una funcin que permita almacenar las
coordenadas del cuerpo de la serpiente, para lo cual se usara un arreglo, (en
este caso cuerpo[x][y]; esta funcin permitir guardar las coordenadas a la
ejecucin del programa, as determinando posicin del cuerpo de la serpiente.
Dicho arreglo funciona bajo la condicin de tipo pila en donde el primero en
entrar es el ltimo en salir.

Declaracin de funcin almacenar posicin
Llamado variable arreglo igual a coordenada x en [n,0]
Llamado arreglo cuerpo igual a coordenada x [n,1]
n +1

si n es igual a tamao
entonces n=1

void guardar_posicion()
{
cuerpo[n][0]=x; //coordenada x en poscion 0
cuerpo[n][1]=y;//coordenada y en posicion 0
n++; //incremento n+1
if(n==tam) n=1;
}


Sabiendo la posicin en la que se encuentra el cuerpo de la serpiente ahora es
posible imprimirla en pantalla, esto se logra bajo la funcin dibujar_cuerpo(). Se
imprime la serpiente bajo las coordenadas guardadas anteriormente en la
6

funcin guardar_posicion(); del arreglo posicionando el cuerpo de la serpiente
en una coordenada X,Y aumentado conforme recorre cuerpo

Declaracin de funcin imprime cuerpo
Para tamao menor que incremento i
Posiciona en [incremento i,0][incremento i,1]imprime cuerpo serpiente carcter ACSII
i +1

void dibujar_cuerpo()
{
for(int i=1;i<tam;i++)
{
gotoxy(cuerpo[i][0],cuerpo[i][1]); //desplazamiento de cuerpo
printf("%c",127); //impresin de cuerpo
}
}


No basta solo con imprimir el cuerpo de la serpiente, tambin es necesario que
esta se mueva, esto se puede conseguir si se borra el ltimo eslabn de la
cadena de caracteres impreso, as la funcin borrar_cuerpo() permite simular el
desplazamiento de la serpiente de acuerdo a la direccin asignada, se puede
decir que esta funcin es un arreglo que resuelve el problema de simular
movimiento de la serpiente, por cada posicin que recorra la funcin
dibujar_cuerpo() antes expresada se imprimir un espacio en la primer posicin
encontrada en el arreglo guardar_cuerpo().

Declaracin de funcin borrar cuerpo
Posiciona en [ndice del cuerpo, 0][ndice del cuerpo, 1] imprime un espacio

void borrar_cuerpo()
{
gotoxy(cuerpo[n][0],cuerpo[n][1]);
printf(" "); //imprime espacio en primer coordenada
}


Dado que la direccin se asigna de acuerdo a la tecla que presione el usuario
(en este caso previa asignacin de flechas de teclado) se requiere que el
programa traduzca la direccin para lo que precisamente esta funcin permite
indicar la direccin a la que el usuario desea mover la serpiente. Se procede a
declarar la funcin teclear() para posteriormente detectar la asignacin de
direccin desde el teclado y almacenndola en la variable tecla la cual pasa a
un men switch case() el cual de acuerdo a la tecla presionada permite darle la
direccin correcta a la serpiente.

7

Declaracin vaca funcin teclear
Si se presiona una tecla entonces
Detecta que tecla en cdigo ASCII

Declaracin sentencia swich de tipo tecla detectada
Caso ARRIBA
Si direccin no es abajo entonces direccin es 1
Caso ABAJO
Si direccin no es arriba entonces direccin es 2
Caso DERECHA
Si direccin no es izquierda entonces direccin es 3
Caso IZQUIERDA
Si direccin no es derecha entonces direccin es 4

void teclear() //declaracion funcin teclear
{
if(kbhit()) //habilita entrada de teclado
{
tecla=getch(); //obtencion de tecla
switch(tecla) //registro tecla a menu
{
case ARRIBA:
if(dir !=2) //si dir no es abajo
dir=1;
break;
case ABAJO:
if(dir!=1) //si dir no es arriba
dir=2;
break;
case DERECHA:
if(dir!=4) //si dir no es izquierda
dir=3;
break;
case IZQUIERDA:
if(dir!=3) // si dir no es derecha
dir=4;
break;
}
}
}


Ahora se necesitara crear una funcin que imprima la comida de la serpiente. A
continuacin se declara la funcin comida () que posiciona un carcter
aleatoriamente en el espacio de juego preestablecido por la funcin pintar() de
78 x 24. Si el ltimo arreglo de la funcin guardar_cuerpo() es igual a las
8

coordenadas de comida() entonces aumento el tamao del cuerpo de la
serpiente y posteriormente gener un nuevo carcter (comida) aleatoriamente
dentro del espacio de juego preestablecido.


Declaracin funcin comida de tipo vaca
Si posicin x es igual a posicin x comida y si posicin y es igual a posicin y comida
entonces
Genera nueva posicin aleatoria x para comida menor a 78
Genera nueva posicin aleatoria y para comida menor a 24
Incrementa tamao en 1
Incremento puntos en 10
Posicin (x comida,y comida) imprime carcter comida ASCII

void comida() //declaracin funcin comida
{
if(x==xc && y==yc)
{
xc=(rand()%73)+4; //numero aleatorio menor que 78 asignado a xc
yc=(rand()%19)+4; //numero aleatorio menor que 24 asignado a yc
tam++; //incremento variable tam+1
puntos+=10; //incremento variable puntos+10
gotoxy(xc,yc);printf("%c",2); //impresin de comida en posicion xc,xc
}
}


Hasta ahora se ha completado prcticamente el funcionamiento bsico del
juego pero, como plus se decidi imprimir el nmero de comidas hechas por la
serpiente y adems, aumentar la dificultad del juego aumentando la velocidad
de recorrido de la serpiente cada determinado nmero de comidas hechas, por
tal se cre la funcin posicion() la cual hace posible la visualizacin en pantalla
de la puntuacin (nmero de comidas hechas) y del nivel del juego al momento.

Declaracin vaca funcin puntuacin
Posicin (3,1) imprime PUNTUACION de variable puntos
Posicin (3,1) imprime NIVEL de variable h

//implesion de puntuacion y nivel
void puntuacion()
{
gotoxy(3,1); printf("PUNTUACION %d", puntos); //imprime puntos en 3,1
gotoxy(70,1); printf("NIVEL %d", h); //imprime nivel en 70,1
}

9

La funcin crditos() permite sellar el programa con los datos del desarrollador
del programa.

Declaracin vaca funcin crditos
Limpia pantalla
Llamado de funcion pintar
Llamado de funcion puntuacin
Posicin (mitad total x,mitad total y) imprime GAME OVER
Posicin (x,y) imprime datos adicionales
Para sistema -> termina programa

void creditos()
{
system("CLS"); //limpieza de pantalla
pintar(); //llamado funcin pintar
puntuacion(); //llamado funcin puntuacion
gotoxy(70/2,23/2);printf("GAME OVER\n");
printf("\n\n\n\n\n\n\n\n\n\n");
gotoxy(20,14);printf("***UNIVERSIDAD IBEROAMERICANA PUEBLA***\n");
gotoxy(18,15);printf("DESARROLLO: \tBertin Rogelio Gomez Rendon\n");
gotoxy(18,16);printf("MAESTRA: \tMaria de Lourdes Aguilar Lopez\n");
gotoxy(36,17);printf("Verano 2014\n");
system("pause>null");
}


Esta funcin de tipo booleana (devuelve true/false) permite establecer los
parmetros para terminar el juego (perder una partida) en este caso como se
explic, en el modo clsico del juego existen 2 forma de perder en el clsico
Snake, la primera consiste en que la serpiente choque con las paredes y la
segunda consiste en chocar con el mismo cuerpo de la serpiente, para lo cual
se desarroll la funcin gameover() como se muestra a continuacin que
devuelve valores falsos o verdaderas de acuerdo a lo establecido parando o
continuando el juego

Declaracin de funcin de tipo booleana gameover
Si y es igual a lmites de campo de juego entonces
Llama funcin crditos
Devuelve falso
Si no
Para variable = tamao-1 mayor que 0
Si arreglo cuerpo es igual a coordenadas campo entonces
Llamado funcin crditos
Devuelve falso
Para cualquier otro caso devuelve verdadero


10

bool gameover()
{
if(y==3 || y==23 || x==2 || x==77) //si cualquiera de estas condiciones se cumple
{
creditos(); //va a funcin
return false; // y regresa un valor falso
}
Else //si no
{
for (int j=tam-1;j>0;j--)
{
if(cuerpo[j][0]==x && cuerpo[j][1]==y) //si pos. cuerpo es igual a X y Y
{
creditos(); //va a funcion
return false; //y regresa un valor falso
}
}
}
return true; //mientras sea todo lo contrario la funcin gameover() se omite
}


Tambin se mencion que para aumentar la dificultad del juego se poda
aumentar la velocidad de recorrido de la serpiente cada que se coma cierta
cantidad de caracteres comida, para lo cual se desarroll la funcin
mvelocidad()

Declaracin funcin ms velocidad de tipo vaca
Si los puntos son iguales a variable h por tope de nivel entonces
Variable velocidad incrementa
Variable +1

void mvelocidad() //declaracin de funcion
{
if(puntos==h*50) // si la puntuacin es 50*incremento de h
{
velocidad-=20; //cambio de velocidad *10
h++; //aumento h+1
}
}


A continuacin se hace la declaracin del programa principal main() que
acumula todas las funciones creadas y una rutina de ejecucin ciclada.

Declaracin programa principal
Llamado funcin pintar
Coordenadas(x comida, y comida) imprime primer comida
11

Mientras tecla sea diferente de funcin gameover y tecla Escape entonces
Llamado de funcin borrar cuerpo
Llamado de funcin guardar posicin
Llamado de funcin dibujar cuerpo
Llamado de funcin comida
Llamado de funcin puntuacin
Llamado de funcin ms velocidad
Llamado de funcin teclear

Si direccin es igual a 1 decrementa y
Si direccin es igual a 2 incrementa y
Si direccin es igual a 3 incrementa x
Si direccin es igual a 4 decrementa x
Retardo de velocidad
Pausa
Fin programa principal

int main() //declaracion programa principal
{
pintar(); //llamado funcin pintar
gotoxy(xc,yc);printf("%c",2); //asignacin de primera comida
while(tecla!=ESC && gameover()) //bucle while(mientras).Al presionar ESC sales del juego
{
borrar_cuerpo();
guardar_posicion();
dibujar_cuerpo();
comida();
puntuacion();
mvelocidad();
teclear();
teclear(); //agiliza mando
if(dir==1) y--; //decremento abajo
if(dir==2) y++; //incremento arriba
if(dir==3) x++; //incremento derecha
if(dir==4) x--; //incremento izquierda
Sleep(velocidad); //retardo
}
system("pause>null"); //limpieza pantalla
return 0; //fin programa principal
}




12

Construccin de la solucin
Programa final.
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

int cuerpo[200][2];
int n=1; //controla indices del cuerpo
int tam=3; //tamao del cuerpo
int x=10, y=12; //coordenadas de la serpiente
int dir=3; //variable direccion
int xc=30, yc=15; //coordenadas comida
int velocidad=150, h=1;
int puntos=0;
char tecla;
int mayorp=0;
// NUMEROS ASOCIADOS A LAS FLECHAS DEL TECLADO
#define ARRIBA 72
#define IZQUIERDA 75
#define DERECHA 77
#define ABAJO 80
#define ESC 27


//Funcion posicion x-y
void gotoxy(int x, int y) {
HANDLE hCon;
COORD dwPos;

dwPos.X = x;
dwPos.Y = y;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hCon,dwPos);
}


//Funcion margen de juego
void pintar(){
// Lneas horizontales
for(int h=2; h < 78; h++)
{
gotoxy (h, 3); printf ("%c", 205); // los nmeros hacen referencia al cdigo acsii
gotoxy(h, 23); printf ("%c", 205);
}
//Lneas verticales
for(int v=4; v < 23; v++)
{
gotoxy (2,v); printf ("%c", 186);
gotoxy(77,v); printf ("%c", 186);
}
// Esquinas
gotoxy(2,3); printf ("%c", 201);
gotoxy(2,23); printf ("%c", 200);
gotoxy(77,3); printf ("%c", 187);
gotoxy(77,23); printf ("%c", 188);
}

//funcion que guarda las coordenadas del cuerpo de la serpiente
void guardar_posicion()
{
cuerpo[n][0]=x;
cuerpo[n][1]=y;
n++;
if(n==tam) n=1;
13

}

//impresion con coordenadas guardadas en pantalla
void dibujar_cuerpo(){
for(int i=1;i<tam;i++)
{
gotoxy(cuerpo[i][0],cuerpo[i][1]);
printf("%c",127);
}
}


void borrar_cuerpo()
{
gotoxy(cuerpo[n][0],cuerpo[n][1]);
printf(" ");
}

void teclear()
{
if(kbhit())
{
tecla=getch(); //obtencion de tecla
switch(tecla)
{
case ARRIBA:
if(dir !=2)
dir=1;
break;
case ABAJO:
if(dir!=1)
dir=2;
break;
case DERECHA:
if(dir!=4)
dir=3;
break;
case IZQUIERDA:
if(dir!=3)
dir=4;
break;
}
}
}

//generacion de comida aleatoriamente dentro de margenes
void comida(){
if(x==xc && y==yc)
{
xc=(rand()%73)+4;
yc=(rand()%19)+4;
tam++;
puntos+=10;
gotoxy(xc,yc);printf("%c",2);
}
}

//implesion de puntuacion y nivel
void puntuacion(){
gotoxy(3,1); printf("PUNTUACION %d", puntos);
gotoxy(70,1); printf("NIVEL %d", h);
}


void creditos(){
system("CLS");
pintar();
puntuacion();
gotoxy(70/2,23/2);printf("GAME OVER\n");
printf("\n\n\n\n\n\n\n\n\n\n");
14

gotoxy(20,14);printf("***UNIVERSIDAD IBEROAMERICANA PUEBLA***\n");
gotoxy(18,15);printf("DESARROLLO: \tBertin Rogelio Gomez Rendon\n");
gotoxy(18,16);printf("MAESTRA: \tMaria de Lourdes Aguilar Melo\n");
gotoxy(36,17);printf("Verano 2014\n");
system("pause>null");
}

//funcion perder
bool gameover(){
if(y==3 || y==23 || x==2 || x==77)
{

creditos();
return false;
}
else
{
for (int j=tam-1;j>0;j--)
{
if(cuerpo[j][0]==x && cuerpo[j][1]==y)
{
creditos();
return false;
}
}
}
return true;
}


//aumento de velocidad
void mvelocidad()
{
if(puntos==h*50)
{
velocidad-=20; //cambio de velocidad *10
h++;
}
}


//PROGRAMA PRINCIPAL
int main(){

pintar();
gotoxy(xc,yc);printf("%c",2);

while(tecla!=ESC && gameover()) //bucle while(mientras).Al presionar ESC sales del juego
{
borrar_cuerpo();
guardar_posicion();
dibujar_cuerpo();
comida();
puntuacion();
mvelocidad();
teclear();
teclear();
if(dir==1) y--;
if(dir==2) y++;
if(dir==3) x++;
if(dir==4) x--;
Sleep(velocidad);
}
system("pause>null");
return 0;
}

15

Pruebas


Vista del primer recorrido del programa

Vista tras incremento de nivel y a punto de comer

16


Vista tras perder una partida y creditos


Mantenimiento y recomendaciones
Este como cualquier otro programa tiene un lmite creativo tal cual sea la
imaginacin del desarrollador.
De lo anterior considero posible la implementacin al mismo cdigo de:
1. Ms opciones de juego (con o sin obstculos, con o sin lmite de tiempo,
con o sin choque a paredes)
2. Mostrar mejores puntajes despus de cierto nmero de juegos.
3. Men de inicio de juego y funcin Nuevo juego.
4. Pause y reanudacin del juego.
5. Inclusin de modo grafico para hacer ms vistoso el juego.




17

Conclusiones
Si bien como se especific en un inicio el desarrollo de este juego no suele ser el
de un programa avanzado, resulta a bien mencionar que es un buen ejemplo
de implementacin de cdigo, sentencias y lenguaje C que permite visualizar el
nivel de programacin del desarrollador a lo aprendido en el curso.
Bajo los criterios de implementacin de sentencias revisadas a lo largo de este
curso como son funciones, matrices, pilas, arreglos (arrays) y/o estructuras
considero satisfecho el hecho de poder usar para el desarrollo del mismo
programa ellas adems de demostrar que tienen aplicacin en este y en muchos
otros programas de desarrollo en la actualidad por lo que considero
trascendente y satisfactorio el hecho de poder revisarlas aprenderlas y aplicarlas
en el curso.
Si bien en este cdigo se pudieron haber usado algunas otras sentencias como
las de apuntadores o colas tambin es cierto que la implementacin de una u
otra mientras el programa cumpla con las especificaciones esenciales no debe
afectar el funcionamiento del mismo por lo que me considero satisfecho con el
desarrollo del mismo.

Bibliografa
1. http://www.arcade-history.com/?n=blockade&page=detail&id=287
2. Volver arriba http://brainless.hkc.free.fr/missing/Tandy%20Radio%20Shack%20TRS-80%20-
%20Model%20Ihave.txt
3. Volver arriba http://my.stratos.net/~hewston95/RTM07/RTM07.html
4. Volver arriba http://brainless.hkc.free.fr/missing/Tandy%20Radio%20Shack%20TRS-80%20-
%20Model%20Ihave.txt
5. Volver arriba http://www.atarimagazines.com/compute/issue47/109_1_Worm_Of_Bemer.php

S-ar putea să vă placă și