junio 16, 2013

Cubo de Rubik en JAVA

Hola amigos de "Buenas Intenciones", en esta le explicare como hacer el cubo de Rubik utilizando las libreria de OpenGL, que es una libreria para graficos por computadora un poco mas avanzada donde utilizaremos codigo en java  3D, con textura, movimientos de cámara, traslación, rotación.

Primero veamos que es OpenGL proporciona una biblioteca básica de funciones para especificar primitivas gráficas, atributos, transformaciones geométricas, transformaciones de visualización y muchas otras operaciones.
Los nombres de las funciones de la biblioteca básica de OpenGL (también llamada de biblioteca del núcleo
de OpenGL) utilizan como prefijo g l , y cada palabra que forma parte del nombre de una función tiene su
primera letra en mayúscula. Los siguientes ejemplos ilustran este convenio de denominación.
                       glBegin,                glClear,             glCopyPixels,                 glPolygonMode

Bueno sin mas que decir empezamos analizando el codigo linea por linea.
NOTA: Todo el codigo es en una sola clase y esta dividido en fragmentos para facilitar el entendimiento.

//Archivo: Rubik.java
//Autor: Ivan Gallardo
import com.sun.opengl.util.Animator;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import com.sun.opengl.util.GLUT;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
import java.io.IOException;

public class Rubik extends JFrame implements KeyListener{
    static GL gl;
    static GLU glu;
    static GLUT glut;
    static GLCanvas canvas;
    private static float rotarX=0;
    private static float rotarY=0;
    private static float rotarZ=0;
    private static float trasladaX=0;
    private static float trasladaY=0;
    private static float trasladaZ=0;
    private Texture cara1, cara2,cara3,cara4, cara5,cara6;
    private static float EscaX=1.0f;
    private static float EscaY=1.0f;
    private static float EscaZ=1.0f;
    private static float EscaXm=1.0f;
    private static float EscaYm=1.0f;
    private static float EscaZm=1.0f;
    static float rojo=0.0f;
    static float verde=0.0f;
    static float azul=0.0f;
Bueno de la linea de comando 3 a la 16 son las librerias necesarias para los diferentes metodos que
utilizaremos en nuestro programa que en Netbeans se originan automaticamente cuando insertamos una sentencia que las necesite asi que con eso no tendremos mayor problema. Bien en nuestra linea 18 esta el nombre de nuestra clase con la extencion de JFrame para nuestro frame de la clase tenemos implementado KeyListener para poder utilizar nuestro teclado y asignarle funciones. De la linea 19 a 38 son nuestras variables que ocuparemos en todo nuestro pragrama ya ire mencionando cada una de ellas conforme vayamos haciendo uso de ellas.
public Rubik(){
        setSize(700, 600);
        setTitle("Cubo De Rubik");
        setResizable(true);
        GraphicListener listener = new GraphicListener();
        canvas = new GLCanvas();
        gl = canvas.getGL();
        glu = new GLU();
        glut = new GLUT();
        canvas.addGLEventListener(listener);    
        getContentPane().add(canvas);
        Animator animator = new Animator(canvas);
        animator.start();
        addKeyListener(this);
        
    }
Bien continuando con nuestro programa en la siguiente linea creamos nuestro constructor con el nombre de nuestra clase que es como se identifica. en la linea 2 asignamos el tamaño de la ventana donde mostraremos nuestra figura, en la linea 3 el titulo de la ventana en este caso es "Cubo de Rubik", la sentencia setResizable puede ser false o true como se muestra en nuestro código y esto sirve para los que no sabemos para maximizar o o minimizar el tamaño de la ventana, en la linea 5 invocamos a la clase GraphicListener con el nombre listener para inicializar o convocar la clase. En la linea 6 utilizaremos nuestra primer variable asignada en el fragmento anterior (linea 22) que es GLCanvas  con el nombre canvas para poder utilizar todos los métodos que esa clase contiene, para que nos sirve el canvas para visualizar básicamente nuestras figura de OpenGL en una forma animada,de las linea 7 a la 9 Utilizaremos las otras 3 variables de OpenGL donde en la variable gl asignamos la clase canvas con sus métodos, las variables glu y glut son variables que contienen una clase de figuras predefinidas que veremos mas adelante, en las tres ultimas lineas de codigo lo unico que se hace es invocar la clase animator e introducir dentro de ella la clase canvas para dar la animacion y procedemos a darle inicio con star(), la ultima es para nuestro teclado y las teclas que seran asignadas mas adelante con su respectiva función.
public static void main(String args[]){
        Rubik r = new Rubik();
        r.setVisible(true);
        r.setDefaultCloseOperation(EXIT_ON_CLOSE);
        r.setLocationRelativeTo(null);
    }
Se podria decir que es la parte mas importante del programa porque es donde esta nuestro main, que es el metodo que inicializa a nuestra clase completa y hace que nuestro programa corra.
public class GraphicListener implements GLEventListener{
        public void display(GLAutoDrawable arg0) {
            gl = arg0.getGL();
            gl.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT);                      
            gl.glMatrixMode(GL.GL_PROJECTION);
            gl.glLoadIdentity();
            glu.gluPerspective(50, 2, 0.1, 30);
            gl.glMatrixMode(GL.GL_MODELVIEW);
            gl.glDepthFunc(GL.GL_LEQUAL); 
            gl.glEnable(GL.GL_DEPTH_TEST);
            gl.glClearDepth(1.0);
            gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_DECAL);
            gl.glLoadIdentity();
            glu.gluLookAt(0.1 + trasladaX, .1 + trasladaY, .5 + trasladaZ, 0.5 + trasladaX,0, -5.5 + trasladaZ, 0.0, 1.0, 0.0);
En esta parte del codigo iniciamos una nueva clase que se llama GraphicListener y le implementamos la libreria de OpenGL con eventos, enseguida creamos un metodo llamado display que es como su nombre lo dice nos permite mostrar nuestro cubo, en la siguiente linea utilizamos nuestra variable gl y le asignamos el argumento arg0 con la libreria de OpenGL, en las proximas lineas utilizamos las libreria de OpenGL para crear la perspectiva, proyeccion, textura, traslacion y las inicializamos como se muestran.
            cara1.enable();
            cara1.bind();
            gl.glScalef(EscaX,EscaY,EscaZ);
            gl.glScalef(EscaXm,EscaYm,EscaZm);
            gl.glRotatef(rotarX, 1f, 1f, 0f);
            gl.glRotatef(rotarY, 0f, 1f, 1f);
            gl.glRotatef(rotarZ, 0f, 0f, 1f);
            gl.glBegin(gl.GL_QUADS);                                            
            gl.glTexCoord2f(1, 1);                
            gl.glVertex3f(0, 0, 0);     
            gl.glTexCoord2f(0, 1);
            gl.glVertex3f(0.2f, 0f, 0);
            gl.glTexCoord2f(0, 0);
            gl.glVertex3f(.2f, .2f, 0);
            gl.glTexCoord2f(1, 0);
            gl.glVertex3f(0f, .2f, 0);
            gl.glEnd();
            cara1.disable();
Atención en esta parte del codigo ya que es una de las partes mas importantes de nuestro programa, bien en la linea 1 utilizamos nuestra primer variable de tipo textura llamada cara1 con el metodo permitir mostrar la primer cara del cubo, en la linea 2 obligamos a nuestro programa a mostrar cara1, de la linea 3 a la 7 utilizimaos las libreria OpenGL de escalacion y rotacion cada uno de estos metodos tiene tres valores booleano dentro del primer metodo que es el glScalef(), colocamos nuestras variables de escalacion positivas y en la linea siguiente mismo metodo pero con variables negativas (en la parte de las teclas veran porque positivo(+) y negativo(-)), el metodo glRotatef() al igual que el glSalef() contiene valores booleanos y en el primero tenemos valores positivos y en el segundo tenemos valores negativos. En la linea de 8 utilizamos la libreria de primitivas de OpenGL del cuadrado para formar nuestra cara principal osea la cara 1, de la linea de codigo 9 a la 16 ponemos la ubicacion de los puntos de coordenadas 3D y los vertices, por ultimo en la 17 y 18 terminamos nuestro muestre de la cara1 y deshabilitamos nuestra cara 1 para poder activar las 5 caras restantes utilizando el mismo codigo.
public void init(GLAutoDrawable arg0){    
            
            try {               
            cara1 = TextureIO.newTexture(new File("Rubik.jpg"), true);            
            cara2 = TextureIO.newTexture(new File("Rubik1.jpg"), true);            
            cara3 = TextureIO.newTexture(new File("Rubik2.jpg"), true);       
            cara4 = TextureIO.newTexture(new File("Rubik3.jpg"), true);       
            cara5 = TextureIO.newTexture(new File("Rubik4.jpg"), true);       
            cara6 = TextureIO.newTexture(new File("Rubik5.jpg"), true);       
            } catch (IOException e) {
                System.exit(1);
            }
            
        }
En este metodo es donde mandaremos a traer a nuestra textura como podemos observar son 6 caras lo que quiere decir que para cada cara necesitamos una textura y finalizamos con un true para que la muestre.
public void keyPressed(KeyEvent arg0){
       if(arg0.getKeyCode()==KeyEvent.VK_ESCAPE){
            rotarX=0;
            rotarY=0;
            rotarZ=0;
            trasladaX=0;
            trasladaY=0;
            trasladaZ=0;
            EscaX=1.0f;
            EscaY=1.0f;
            EscaZ=1.0f;
            EscaXm=1.0f;
            EscaYm=1.0f;
            EscaZm=1.0f;
            rojo=0.0f;
            verde=0.0f;
            azul=0.0f;
        }
        if(arg0.getKeyCode()==KeyEvent.VK_X){
            rotarX+=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_A){
            rotarX-=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_Y){
            rotarY+=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_B){
            rotarY-=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_Z){
            rotarZ+=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_C){
            rotarZ-=1.0f;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_RIGHT){
            trasladaX+=.10f;
        }

          if(arg0.getKeyCode()==KeyEvent.VK_LEFT){
            trasladaX-=.10f;
        }

         if(arg0.getKeyCode()==KeyEvent.VK_UP){
            trasladaY+=.10f;
        }

          if(arg0.getKeyCode()==KeyEvent.VK_DOWN){
            trasladaY-=.10f;
          }

        if(arg0.getKeyCode()==KeyEvent.VK_1){
            trasladaZ+=.1;
          }

        if(arg0.getKeyCode()==KeyEvent.VK_2){
            trasladaZ-=.10f;
          }
        if(arg0.getKeyCode()==KeyEvent.VK_3){
            rotarY+=1.0;
        }

        if(arg0.getKeyCode()==KeyEvent.VK_4){
            rotarY-=1.0;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_I){
            EscaX +=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_O){
            EscaY +=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_P){
            EscaZ +=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_J){
            EscaXm -=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_K){
            EscaYm -=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_L){
            EscaZm -=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_E){
            rojo +=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_R){
            verde +=0.1f;
        }
        else if (arg0.getKeyCode()== KeyEvent.VK_T){
            azul +=0.1f;
        }
    }

    public void keyReleased(KeyEvent arg0){}
    public void keyTyped(KeyEvent arg0){}
Estamos en la ultima parte de nuestro programa es la parte donde asignamos a cada tecla una funcion o una variable con un valor ya sea en aumento o disminución para darle valores a los metodos donde fueron colocadas la unica q sirve con un reset es la tecla escape que esa es restaurar todos los valores de las variables como estaban al inicio.

Bueno sin mas que decir aqui esta una imagen de nuestro cubo y mas abajo el codigo java del programa espero y les haya servido suerte.

Descarga el código aquí:

4 comentarios: