En un post anterior, desarrollamos un swing para simular un efecto FLIP y recibí algunos mensajes pidiéndome un ejemplo de como usarlo. Cuando creamos un swing personalizado estos tienen casi las mismas propiedades que el resto de swing conocidos, esto se debe a que la mayoría de los componentes descienden de JComponent. Claro esta que también tienen sus propios métodos, por tanto se usan como cualquier otro swing.
Para mostrar el uso de ese componente FLIP, desarrollamos un sencillo juego de memoria. Este tipo de juegos sirve para desarrollar la memoria de los niños y niñas de una forma divertida, que es jugando 🙂 si señor profesor de mi infancia perdida, también se aprende jugando 😉
Sin más preámbulo describiremos a continuación el proyecto en cuestión:
La estructura del juego de memoria es la siguiente:
En el paquete org.bolivia.game se encuentra un JFrame (GameFrame) que es la interfaz del juego compuesto por un JPanel y un JButton.
Tenemos también a la clase JFlipButton que es nuestro componente con el efecto flip con unas pequeñas modificaciones del original.
En el paquete org.bolivia.game.resources se encuentran las imágenes que se usan en el proyecto. En este caso son 10 imágenes de 100×100 pixeles en formato JPG
Clase JFlipButton
package org.bolivia.game; import java.awt.BasicStroke; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.GeneralPath; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.Timer; /** * @web https://www.jc-mouse.net/ * @author Mouse */ public class JFlipButton extends JComponent implements MouseListener { private Timer timer = null; private boolean inTransition = false; private int speed = 4;//velocidad de flip en milisegundos private int displacement = 2;//desplazamiento en pixeles public boolean isFront = true; private boolean inward = true;//sentido del desplazamiento //iconos por defecto private Icon iconBack = new ImageIcon(getClass().getResource("/org/bolivia/game/resources/moe.jpg")); private Icon iconFront = new ImageIcon(getClass().getResource("/org/bolivia/game/resources/cover.jpg")); private Image image = ((ImageIcon)iconFront).getImage(); //variables de desplazamiento private int displacementHorizontal = 0; private float displacementLeft = 0; private float displacementRight = 0; //tamaño por defecto private Dimension dimension = new Dimension(100,100); // private String nameCharacter = ""; private int index = -1; /**Constructor de clase*/ public JFlipButton(){ super(); setSize(dimension); setPreferredSize(dimension); setVisible(true); setCursor(new Cursor(Cursor.HAND_CURSOR)); addMouseListener(JFlipButton.this); } @Override public void paintComponent(Graphics g){ Graphics2D g2 =(Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke( 1f )); //coordenas de imagen GeneralPath p = new GeneralPath(); p.moveTo(displacementHorizontal, displacementLeft);//esquina A p.lineTo(getWidth()-displacementHorizontal, displacementRight);//esquina B p.lineTo(getWidth()-displacementHorizontal, getHeight()-displacementRight);//esquina D p.lineTo( displacementHorizontal, getHeight()-displacementLeft );//esquina C p.closePath(); Shape shp = p; g2.setClip(shp); g2.drawImage(image, 0, 0,getWidth() - displacementHorizontal,getHeight(), null); g2.setClip(null); g2.draw(shp); g.dispose(); } /** * Metodo que realiza los cambios en las variables de desplazamiento * @return Void */ public void flipAnimate(){ inTransition = !inTransition; //declaramos un evento para modificar el desplazamiento vertical y horizontal ActionListener animation = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { if(inward){ displacementHorizontal += displacement; displacementRight += (displacementRight>=getHeight()/2)?0:displacement/(getSize().getWidth()/getSize().getHeight()+1f); }else{ displacementHorizontal -= displacement; displacementLeft -=displacement/(getSize().getWidth()/getSize().getHeight()+1f); } //repinta graficos repaint(); //si se llego al medio del componente -> cambia de sentido if(displacementHorizontal >= getWidth()/2){ inward = false; displacementLeft = displacementRight; displacementRight=0; // if( isFront ){//mostrar imagen de atras isFront=false; image=((ImageIcon)iconBack).getImage(); }else{//mostrar imagen de adelante isFront =true; image=((ImageIcon)iconFront).getImage(); } } //volvio a su posicion inicial -> detener animacion if( inward == false && displacementHorizontal == 0 ){ inTransition=false; timer.stop(); displacementLeft=0; displacementRight=0; displacementHorizontal=0; inward = true; } } }; // if( inTransition ) { if(timer != null)timer.stop(); timer = new Timer( speed, animation); timer.start(); //inicia animacion } } public void cancel(){ if(timer != null)timer.stop(); inTransition=false; } @Override public void mouseClicked(MouseEvent e) { flipAnimate(); } @Override public void mousePressed(MouseEvent e) {/*...*/} @Override public void mouseReleased(MouseEvent e) {/*...*/} @Override public void mouseEntered(MouseEvent e) {/*...*/} @Override public void mouseExited(MouseEvent e) {/*...*/} public Icon getIconBack() { return iconBack; } public void setIconBack(Icon iconBack) { this.iconBack = iconBack; } public Icon getIconFront() { return iconFront; } public void setIconFront(Icon iconFront) { this.iconFront = iconFront; } public int getDisplacement() { return displacement; } public void setDisplacement(int displacement) { this.displacement = displacement; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } public String getNameCharacter() { return nameCharacter; } public void setNameCharacter(String nameCharacter) { this.nameCharacter = nameCharacter; iconBack = new ImageIcon(getClass().getResource("/org/bolivia/game/resources/"+ this.nameCharacter +".jpg")); } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } }
La lógica del juego se controlo desde la clase GameFrame
public class GameFrame extends javax.swing.JFrame { private List<String> characters = new LinkedList<String>(); private Character character1 = new Character(); private Character character2 = new Character(); private int hits = 0; /** * Creates new form GameFrame */ public GameFrame() { initComponents(); setTitle("Game Memory [https://www.jc-mouse.net/]"); setLocationRelativeTo(null); //layout jPanel1.setLayout(new GridLayout(4, 4)); //se añaden las figuras al panel for(int i=0;i<16;i++){ jPanel1.add( new JFlipButton() ); } //se crea nuevo juego newGame(); //se añade eventos para cada casilla for(int i=0;i<16;i++){ final JFlipButton button = (JFlipButton) jPanel1.getComponent(i); button.addMouseListener( new MouseListener(){ @Override public void mouseClicked(MouseEvent e) { /* --------- controla el juego en si -------- */ if( button.isFront ){//si imagen esta tapada if( character1.isEmpty() ){ character1.setKey( button.getIndex() ); character1.setName( button.getNameCharacter() ); }else if( character2.isEmpty() ){ character2.setKey( button.getIndex() ); character2.setName( button.getNameCharacter() ); //si figuras de ambas casillas son iguales if(character1.getName().equals( character2.getName() ) ){ character1.setKey( -1 ); character1.setName( "" ); character2.setKey( -1 ); character2.setName( "" ); hits +=1; //completo el juego? if(hits==8){//si JOptionPane.showMessageDialog(null, "--------------------------- YOU WIN!!! ---------------------------", "Atención", JOptionPane.INFORMATION_MESSAGE); } }else{//no son iguales //se comienza un hilo que espera X tiempo hasta que la casilla de completamente la vuelta new Thread(){ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException ex) {} //oculta figuras ((JFlipButton) jPanel1.getComponent(character1.getKey())).flipAnimate(); ((JFlipButton) jPanel1.getComponent(character2.getKey())).flipAnimate(); character1.setKey( -1 ); character1.setName( "" ); character2.setKey( -1 ); character2.setName( "" ); } }.start(); } } }else{ button.cancel();//se cancela animacion } } @Override public void mousePressed(MouseEvent e) {/* nada q ver circulando jovenes... */} @Override public void mouseReleased(MouseEvent e) {/* nada q ver circulando jovenes... */} @Override public void mouseEntered(MouseEvent e) {/* nada q ver circulando jovenes... */} @Override public void mouseExited(MouseEvent e) {/* nada q ver circulando jovenes... */} }); } // } /** * Nuevo juegos */ private void newGame(){ characters.clear(); //personajes characters.add("castulo"); characters.add("bart"); characters.add("homero"); characters.add("lionel"); characters.add("lisa"); characters.add("maggie"); characters.add("marge"); characters.add("ned"); characters.add("castulo"); characters.add("bart"); characters.add("homero"); characters.add("lionel"); characters.add("lisa"); characters.add("maggie"); characters.add("marge"); characters.add("ned"); //asigna los personajes a cada casilla for(int i=0;i<16;i++){ ((JFlipButton) jPanel1.getComponent(i)).setNameCharacter(getCharacter()); ((JFlipButton) jPanel1.getComponent(i)).setIndex(i); if( !((JFlipButton) jPanel1.getComponent(i)).isFront ) ((JFlipButton) jPanel1.getComponent(i)).flipAnimate(); } //reinicia variables character1 = new Character(); character2 = new Character(); hits=0; } /** * desordena lista y retorna un personaje * @return String Nombre del personaje */ private String getCharacter(){ Collections.shuffle(characters); return characters.remove(0); } /** * clase privada para manejar las 2 figuras que deben ser comparadas */ private class Character{ private int key=-1; private String name=""; public int getKey() { return key; } public void setKey(int key) { this.key = key; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isEmpty(){ if(key==-1 && name.equals("")) return true; else return false; } }
Todo el proyecto se encuentra comentado hasta más no poder, cualquiera con un conocimiento intermedio de java podrá entenderlo, sino, abajo están los comentarios que responderé con gusto.
En el siguiente video un demo del juego en funcionamiento
Descarga el código desde este enlace pobre
enjoy!!!
Un TextView autocompletado nos facilita el ingreso de información en aplicaciones móviles ya que te muestra posibles opc[...]
En un post anterior conocimos que es y como funciona un parámetro de entrada IN en procedimientos almacenados y lenguaje[...]
En este tutorial construiremos una aplicación en JavaFX para leer datos de un servicio web Herramientas IDE Netbeans 8.x[...]
En este segundo post sobre Android y SQLite, veremos el uso de los métodos de gestión de base de datos más utilizados, e[...]
Un Tabbed Activity te permite cambiar la vista entre fragmentos desplazando el dedo de izquierda a derecha o de derech[...]
Los gráficos de líneas muestran una serie como un conjunto de puntos conectados mediante una línea. Los valores se repre[...]