Mostrando entradas con la etiqueta c. Mostrar todas las entradas
Mostrando entradas con la etiqueta c. Mostrar todas las entradas

jueves, 11 de octubre de 2012

Space Invaders OpenGL (GLUT)


Space Invaders

Space invaders es un juego diseñado originalmente por Toshihiro Nishikado de Taito Corporation en el año 1978, que tuvo un gran éxito en el mercado, considerándoselo un clásico hasta el día de hoy, del cual se crearon versiones para distintas consolas y sistemas, pues curiosamente este no contaba con protección de copyright.

El juego se trata de eliminar oleadas de marcianos con un cañón el cual el jugador controla, antes de que estos lleguen a la “tierra”.
En el juego aleatoriamente y con una cantidad de puntaje indefinida aparece una nave extraterrestre de color rojo que proporciona al jugador, si este logra destruirla una cantidad aleatoria de puntaje, ademas en la pantalla de juego hay lo que parecen ser 4 bunkers que “ayudan” a defender la tierra.

En la versión creada en esta ocasión, hay algunas diferencias que por razones de tiempo no termine de programar, aunque en su esencia, se puede aprecia del juego su lógica y estética.

No ha sido fácil “emular” la estética del juego, puesto que encontrar los sprites originales en la web, a sido un trabajo muy duro, puesto que la cantidad de imitaciones del juego es basta, asi en el proceso de desarrollo, se obtuvieron resultados hasta llegar a tener una lo mas parecido al “original”, o mas bien al que todos conocen.

Screen durante el desarrollo del juego

Para el desarrollo de la aplicación se ocuparos los sprites de la siguiente imagen como modelos, alcanzando una estética bastante similar.


Screen original del juego

Screen actual del desarrollo
Los elementos faltantes dentro del diseño aun se encentran en fase de implementación, por falta de tiempo, aunque en teoría estos no son de una gran complejidad, puesto que la parte lógica “gruesa” del diseño ya se encuentra programada y entendida en el código.

Para finalizar con la presentación de la aplicación una ultima imagen correspondiente a la pantalla de inicio del juego, espero que lo disfruten.

Screen vista actual
Descripción de funciones y archivos usados:

space_slpha.c: En este archivo se encuentra la linea general del juego, ademas de las funcionalidades de glut que apoyan el proceso, tales como el apoyo al teclado, el re dimensionamiento de objetos..
  • void IniciarGLUT(); esta es una función de propósito general no especifica para el juego, libera de código extra en la función main(); ya que se encarga de tareas especificas de glut que no necesariamente son tarea de la linea principal de un programa.
  • void PintarEscena(); esta función se encarga de exhibir todos lo objetos del juego y debe ser específicamente llamada por la función glutDisplayFunc(“PintarEscena”); de lo contrario no hará nada.
  • void ReProyectar(int w, int h); esta función se encarga de ajustar los tamaños si es que la ventana se redimensiona, ademas crea la escala con la que se trabajara en el resto del juego, los argumentos “w”, “h” usan como argumento el tamaño actual de la pantalla. Esta función debe ser llamada o enviada como argumento específicamente a la función glutReshapeFunc(ReProyectar); de lo contrario tampoco se hará nada.
  • void ControlTeclado(unsigned char key, int x, int y); fácil, esta función controla las teclas que no son especiales dentro del juego “ENTER” y “ESC” y debe ser argumentada para la función glutKeyboardFunc(ControlTeclado); y sus argumentos propios son un “key” correspondiente a una tecla y un “x” , “y” que aunque en mi caso particular no ocupo debe ser igualmente anexado.
  • void ControlFlechas(int key, int x, int y); igualmente fácil, esta función se encarga de los eventos que ocurren con la flechas del teclado, puesto a que estas son teclas especiales, no se consideran dentro de la funcion descrita anteriormente por tanto son argumentadas a glutSpecialFunc(ControlFlechas); y también cuentan entra sus argumentos un “key” que es la flecha oprimida, y un “x”, “y” que no utilizo.


space_alpha.h: En este archivo se concentran las acciones propias del juego y no la funcionalidades de glut como por ejemplo la pantalla de juego, la pantalla principal y la acción de disparar, ademas de la variables globales que apoyan los cálculos y conjunto de flags que permiten las acciones

  • void cargar_variables(); esta función se encarga de establecer los valores iniciales (si es que se necesita) de la mayoría de la variables globales del juego.
  • void disparo(); se encarga de la acción de disparo cuando el usuario ataca.
  • void pantalla_de_juego(); pantalla de juego, básicamente el alma del juego, posiciona enemigos y jugador en la pantalla aparte de hacer los cálculos de rectángulos mínimos que se necesitan para detectar las colisiones, (el calculo del choque directo entre jugador y extraterrestre no se encuentra hecho aunque si se detecta si un disparo destruye a un enemigo(es efectivamente destruido)).
  • void presentación(); simple y estética, es la pantalla de “bienvenida al juego”, cabe señalar que si se esta un tiempo mirando la pantalla la nave roja o “UFO” escapara de la vista del usuario (efecto de una animación programada no una torpeza).
  • void Avanzar(int x); función recursiva que se encarga del manejo de contadores y posiciones necesarias para la correcta ejecución del juego aparte de dar continuidad en caso de que el usuario no intervenga “jugando”

space_sprites.h: aquí se encuentra la parte artística de todo este asunto, este archivo contiene el conjunto de sprites en matrices, y las respectivas funciones que manejan dichas matrices, básicamente todas la funciones hacen lo mismo pero al ser diferentes los tamaños de cada objeto no me propuse el crear una función genérica para todos los sprites, aunque si agrupe los de características similares.
  • void ubicar_sprite(int sprite, float six, float siy, float tam_pix); pone enemigos y jugador en pantalla “sprite”, es el subindice correspondiente al sprite deseado:
0 - “CALAMAR”
1 - “CANGREJO”
2 - “PULPO”
3 - “UFO”
4 - “NAVE”

Las variables “six”, “siy”, son posiciones eje coordenados para los objetos, y “tam_pix” define el tamaño del pixel usado para imprimir el objeto.

  • void simbolo(int sprite, float six, float siy); similar al anterior, pero imprime símbolos definidos en la matriz que maneja, no define tamaño de pixel:

0 - “?”
1 - “!”
2 - “=”

  • void say_space(float six, float siy); pone la palabra space en pantalla en la posición (six, siy);
  • void say_invaders(float six, float siy); pone la palabra invaders en pantalla en la posición (six, siy);
  • void say_pts(float six, float siy); pone la sigla pts. en pantalla en la posición (six, siy);
  • void numero(int num, float six, float siy); función similar al a ubicar sprite pero esta imprime números en pantalla donde, “num” es el numero a imprimir.
  • void bala(float six, float siy); pone el disparo en pantalla cuando se dispara;
  • void mostrar_text(char cadena[], float x, float y); imprime texto sin sprite donde “cadena[]” es el texto a imprimir, y (“x”, “y”) la posición.



    Enlace descarga código fuente: Space_invaders.rar








jueves, 24 de mayo de 2012

Hola Mundo .NES... en C!!

Eso mismo pues, roms de NES generadas con simple y conocido lenguaje C, se trata de un compilador de C para sistemas basados en el procesador 6502 llamado cc65. El cc65 es capaz de compilar para sistemas Commodore, Atari y teóricamente Apple II (todos basados en el 6502), si bien yo me oriente principalmente en NES (por ser mi consola favorita) la información completa esta disponible en el sitio oficial del compilador para que prueben en el resto de los sistemas:

http://www.cc65.org/

A continuación el código del programa mas simple disponible prácticamente para cualquier lenguaje, esta vez compilable para roms de la vieja NES:

#include <conio.h>
int main (){
    gotoxy(6, 10);
    cprintf("Hola Mundo con cc65...\n");
    gotoxy(6, 12);  
    cprintf("Saludos Mirager...");
    while(1){}
    return 0;
}

Si bien para un programador, que conozca el lenguaje C esto es un código muchos menos que básico, a la hora de compilar habrá que tomar en cuenta las limitaciones de cada consola, este ejemplo debería ser compilable para todas ellas al no requerir de ninguna característica especial.
Otro dato a considerar es la forma en que se compilan los objetos, pues existe una forma paso a paso (lenta pero segura) y una forma rápida (con defectos), a continuación las dos opciones

A)


La forma paso a paso resultara útil una vez avanzando un poco con este tema para el uso de joystick y características propias de cada sistema, para este simple código seria de la siguiente forma:

holamundo.c -> cc65 -> holamundo.s ->  ca65 -> holamundo.o -> ld65 -> holamundo.nes (en esta parte se deberá linkar la librería del sistema requerido, en este caso nes.lib)

a continuación una imagen descriptiva:



Si tienes un emulador de NES instalado y configurado para abrir las roms automáticamente, el resultado debería verse como este (de lo contrario deberás abrir la roms manualmente desde el emulador (demasiado obvio)):


B)


La forma rápida para este código pasa por programa que se encarga de generar los ficheros necesarios para la compilación de la rom:

holamundo.c -> ld65 ->holamundo.nes

probablemente por alguna mala utilización mía el resultado se ve similar pero no idéntico, seguramente habrán usuarios del cc65 que conozcan bien las limitaciones de este compilador, de todos modos aqui va una imagen descriptiva:




Y el resultado generado es mas o menos así:



Podrán darse cuenta que en el caso de las letras mayúsculas en vez de diferenciarlas en tamaño con respecto a las minúsculas les agrega un fondo y ennegrece, si alguien esta sobrado de tiempo y descubre si se debe a una mala utilización del programa, siempre estaré agradecido de que me lo diga o comente :D

Mirager  

lunes, 21 de mayo de 2012

Perdida de precisión punto flotante (float) en C

Experimentando con distintas formulas implementadas en C, recién después de muchos años de ocupar este lenguaje caí en cuenta de la perdida de datos que acarrea el uso en operaciones sucesivas del tipo de dato float, tanto así que ociosamente me di el trabajo de hacer un programa que demostrara dicha perdida.
La información en general en Internet respecto a este punto es bastante limitada siendo la fuente que mejor explica este tema una pagina relacionada con la queridisima empresa para mis compañeros linuxeros microsoft :D


fuente: http://msdn.microsoft.com/es-es/library/c151dt3s.aspx


Si alguno de mi compañeros anda por ahi sobrado de 5 minutos para hacer copy paste del código, y lo prueba en linux, agradecería que me comente sus resultados :D


#include <stdio.h>


int main(){
    float a;
    float numero;
    float ultimo;
    printf("Elija el numero para calcular la precision: ");
    scanf("%f", &numero);
    for(a=0;a<=numero;a+=0.1){
        //printf("\n%f", a);
        //printf("\n%.21f", a);
        printf("\n\tnumero mostrado: %f, numero real %.21f", a, a);
        ultimo=a;
    }
    printf("\n");
    printf("\nNumero ingresado %d", (int)numero);
    printf("\nNumero en punto flotante %f", numero);
    printf("\nNumero en punto flotante con precision %.21f", numero);
    printf("\nUltimo numero del ciclo: %f", ultimo);
    printf("\nUltimo numero del ciclo con precision: %.21f", ultimo);

    printf("\n\nEstos numeros se obtienen cuando se corta el ciclo (for):\n");
    printf("\nNumero final procesado en punto flotante %f", a);
    printf("\nNumero final procesado en punto flotante con precision %.21f", a);
    getch();
    return 0;
}