Java proporciona la clase Graphics, que permite dibujar elipses, cuadrados, líneas, mostrar texto y también tiene muchos otros métodos de dibujo.
Para cualquier programador, es esencial el entendimiento de la clase Graphics, antes de adentrarse en el dibujo en Java.
La clase Graphics proporciona el entorno de trabajo para cualquier operación gráfica que se realice dentro del AWT.
Para poder pintar, un programa necesita un contexto gráfico válido, representado por una instancia de la clase Graphics.
Pero esta clase no se puede instanciar directamente; así que debemos crear un componente y pasarlo al programa como un argumento al método paint().
El único argumento del método paint() es un objeto de esta clase.
La clase Graphics dispone de métodos para soportar tres categorías de operaciones gráficas:
1) Dibujo de primitivas gráficas,
2) Dibujo de texto,
3) Presentación de imágenes en formatos *.gif y *.jpeg.
Además, la clase Graphics mantiene un contexto gráfico: un área de dibujo actual, un color de dibujo del Background y otro del Foreground, un Font con todas sus propiedades, etc.Los ejes están situados en la esquina superior izquierda. Las coordenadas se miden siempre en pixels.
Problema 1
Crear una aplicación que utilice las primitivas gráficas principales que provee la clase Graphics:import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Grafico1 extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Grafico1 frame = new Grafico1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Grafico1() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
setBounds(0,0,800,600);
}
public void paint (Graphics g)
{
super.paint(g);
g.setColor (Color.blue);
g.drawLine (0, 70, 100, 70);
g.drawRect (150, 70, 50, 70);
g.drawRoundRect (250, 70, 50, 70, 6, 6);
g.drawOval (350, 70, 50, 70);
int [] vx1 = {500, 550, 450};
int [] vy1 = {70, 120, 120};
g.drawPolygon (vx1, vy1, 3);
g.setColor (Color.red);
g.fillRect (150, 270, 50, 70);
g.fillRoundRect (250, 270, 50, 70, 6, 6);
g.fillOval (350, 270, 50, 70);
int [] vx2 = {500, 550, 450};
int [] vy2 = {270, 320, 320};
g.fillPolygon (vx2, vy2, 3);
}
}
Sobreescribimos el método paint heredado de la clase JFrame: public void paint (Graphics g)
{
El método paint se ejecuta cada vez que el JFrame debe ser redibujado y llega como parámetro un objeto de la clase Graphics. Este objeto nos permite acceder al fondo del JFrame y utilizando las primitivas gráficas dibujar líneas, rectángulos, elipses etc.Lo primero que hacemos dentro de este método es llamar al método paint de la clase superior para que se pinte el fondo del JFrame y otras componentes contenidas dentro (para llamar al método paint de la clase JFrame debemos anteceder la palabra clave super y pasar el parámetro respectivo):
super.paint(g);Mediante el método setColor activamos un color:
g.setColor (Color.blue);Dibuja una línea desde la coordenada (0,70) es decir columna 0 y fila 70 en píxeles, hasta la coordenada (100,70). La línea es de color azul:
g.drawLine (0, 70, 100, 70);Dibujamos un rectángulo desde la coordenada (150,70) con un ancho de 50 píxeles y un alto de 70, solo se pinta el perímetro del rectángulo de color azul):
g.drawRect (150, 70, 50, 70);Similar a drawRect más un valor de redondeo de los vertices que le indicamos en el quinto y sexto parámetro:
g.drawRoundRect (250, 70, 50, 70, 6, 6);Dibujamos un óvalo:
g.drawOval (350, 70, 50, 70);Dibujamos un triángulo (debemos indicar mediante dos vectores los vértices de cada punto del triángulo), el primer punto es el (500,70) el segundo punto es el (550,120) y por último el punto (450,120):
int [] vx1 = {500, 550, 450};
int [] vy1 = {70, 120, 120};
g.drawPolygon (vx1, vy1, 3);
De forma similar los métodos fillRect, fillRoundRect, fillOval y fillPolygon son similares a los anteriores con la diferencia que pinta su interior con el color activo de la última llamada al método setColor: g.setColor (Color.red);
g.fillRect (150, 270, 50, 70);
g.fillRoundRect (250, 270, 50, 70, 6, 6);
g.fillOval (350, 270, 50, 70);
int [] vx2 = {500, 550, 450};
int [] vy2 = {270, 320, 320};
g.fillPolygon (vx2, vy2, 3);
Dibujar texto
La clase Graphics permite ?dibujar? texto, como alternativa al texto mostrado en los componentes JLabel, JTextField y JTextArea. El método que permite graficar texto sobre el JFrame es:drawString(String str, int x, int y);
Problema 2
Crear una aplicación que utilice las primitiva drawString de Java:import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Grafico1 extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Grafico1 frame = new Grafico1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Grafico1() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
setBounds(0,0,800,600);
}
public void paint (Graphics g)
{
super.paint(g);
g.setColor (Color.blue);
g.drawString("Primer linea",10,200);
g.drawString("Segunda linea",10,300);
}
}
Clase Color
La clase java.awt.Color encapsula colores utilizando el formato RGB (Red, Green, Blue). Las componentes de cada color primario en el color resultante se expresan con números enteros entre 0 y 255, siendo 0 la intensidad mínima de ese color y 255 la máxima. En la clase Color existen constantes para colores predeterminados de uso frecuente: black, white, green, blue, red, yellow, magenta, cyan, orange, pink, gray, darkGray, lightGray.Problema 3
Crear una aplicación que dibuje 255 líneas creando un color distinto para cada una de ellas:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Grafico1 extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Grafico1 frame = new Grafico1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Grafico1() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
setBounds(0,0,800,255);
}
public void paint (Graphics g)
{
super.paint(g);
int fila = 0;
for (int rojo = 0 ; rojo <= 255 ; rojo++)
{
Color col = new Color (rojo, 0, 0);
g.setColor (col);
g.drawLine (0, fila, 800, fila);
fila++;
}
}
}
Dentro de un for creamos objetos de la clase Color y fijamos el color de la línea seguidamente (con esto logramos un degradé del negro al rojo): int fila = 0;
for (int rojo = 0 ; rojo <= 255 ; rojo++)
{
Color col = new Color (rojo, 0, 0);
g.setColor (col);
g.drawLine (0, fila, 800, fila);
fila++;
}
Presentación de imágenes
Java permite incorporar imágenes de tipo GIF y JPEG definidas en ficheros. Se dispone para ello de la clase java.awt.Image. Para cargar una imagen hay que indicar la localización del archivo y cargarlo mediante el método getImage(). Este método existe en las clases java.awt.Toolkit.Entonces, para cargar una imagen hay que comenzar creando un objeto (o una referencia) Image y llamar al método getImage() (de Toolkit); Una vez cargada la imagen, hay que representarla, para lo cual se redefine el método paint() para llamar al método drawImage() de la clase Graphics. Los objetos Graphics pueden mostrar imágenes a través del método: drawImage(). Dicho método admite varias formas, aunque casi siempre hay que incluir el nombre del objeto imagen creado.
Clase Image
Una imagen es un objeto gráfico rectangular compuesto por pixels coloreados. Cada pixel en una imagen describe un color de una particular localización de la imagen.A continuación, algunos métodos de la clase Image:
La clase Graphics provee el método drawImage() para dibujar imagenes; este método admite varias formas:
- drawImage (Image i, int x, int y, ImageObserver o) - drawImage (Image i,int x,int y,int width,int height,ImageObserver o)
Problema 4
Crear una aplicación que muestre un archivo jpg dentro de un JFrame.
Luego de crear el proyecto debemos disponer un archivo en la carpeta raiz del proyecto (el archivo debe llamarse imagen1.jpg)import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Grafico1 extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Grafico1 frame = new Grafico1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Grafico1() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
setBounds(0,0,800,600);
}
public void paint (Graphics g)
{
super.paint(g);
Toolkit t = Toolkit.getDefaultToolkit ();
Image imagen = t.getImage ("imagen1.jpg");
g.drawImage (imagen, 0, 0, this);
}
}
Creamos un objeto de la clase Toolkit llamando al método estático de la misma clase:Toolkit t = Toolkit.getDefaultToolkit ();Creamos un objeto de la clase Image llamando al método getImage de la clase Toolkit pasando como parámetro el archivo con la imagen:
Image imagen = t.getImage ("imagen1.jpg");
Por último llamamos al método drawImage con la referencia al objeto de tipo Image, la columna, la fila y la referencia al JFrame donde debe dibujarse:g.drawImage (imagen, 0, 0, this);
Método repaint()
Este es el método que con más frecuencia es llamado por el programador. El método repaint() llama ?lo antes posible? al método paint() del componente.El método repaint() puede ser:
repaint() repaint(int x, int y, int w, int h)Las segunda forma permiten definir una zona rectangular de la ventana a la que aplicar el método.
Problema 5
Crear una aplicación que muestre un círculo en medio de la pantalla y mediante dos botones permitir que se desplace a izquierda o derecha.import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Grafico1 extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
private int columna;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Grafico1 frame = new Grafico1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Grafico1() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton bi = new JButton("Izquierda");
bi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
columna=columna-10;
repaint();
}
});
bi.setBounds(105, 482, 89, 23);
contentPane.add(bi);
JButton bd = new JButton("Derecha");
bd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
columna=columna+10;
repaint();
}
});
bd.setBounds(556, 482, 89, 23);
contentPane.add(bd);
setBounds(0,0,800,600);
columna=400;
}
public void paint (Graphics g)
{
super.paint(g);
g.setColor (Color.red);
g.fillOval (columna, 300, 100, 100);
}
}
Definimos un atributo columna:private int columna;Cuando se presiona el botón (bi) restamos 10 al atributo columna y pedimos que se ejecute el método paint (esto último llamando al método repaint()), el método repaint borra todo lo dibujado dentro del JFrame y llama al paint:
bi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
columna=columna-10;
repaint();
}
});
El método paint dibuja un círculo utilizando como posición el valor del atributo columna: public void paint (Graphics g)
{
super.paint(g);
g.setColor (Color.red);
g.fillOval (columna, 300, 100, 100);
}
Problema 6
Se debe desarrollar una pantalla para configurar ciertas características de un procesador de texto.Debe aparecer y poder seleccionarse los márgenes superior e inferior de la página.
Los márgenes pueden ir en el rango de 0 a 10. Desplazar las líneas a medida que modificamos los márgenes.
Por otro lado tenemos la orientación de página. La misma se administra a través de un JComboBox que tiene dos valores posibles (Horizontal y Vertical). Cuando está seleccionado en el JComboBox el String Horizontal dibujar un rectángulo con base mayor a la altura, y cuando está seleccionado el String Vertical dibujar un rectángulo con una base menor.
Cuando se presiona el botón inicializar la configuración de márgenes se inicializan con 0 y se selecciona orientación horizontal.
El código fuente que resuelve esta aplicación es:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JSpinner;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ProcesadorTexto extends JFrame {
private JPanel contentPane;
private JSpinner sp1;
private JSpinner sp2;
private JComboBox comboBox;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ProcesadorTexto frame = new ProcesadorTexto();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ProcesadorTexto() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 573, 481);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
sp1 = new JSpinner();
sp1.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent arg0) {
repaint();
}
});
sp1.setModel(new SpinnerNumberModel(0, 0, 10, 1));
sp1.setBounds(162, 51, 55, 28);
contentPane.add(sp1);
sp2 = new JSpinner();
sp2.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
repaint();
}
});
sp2.setModel(new SpinnerNumberModel(0, 0, 10, 1));
sp2.setBounds(162, 150, 55, 28);
contentPane.add(sp2);
JLabel lblMargenInferior = new JLabel("Margen inferior");
lblMargenInferior.setBounds(162, 26, 109, 14);
contentPane.add(lblMargenInferior);
JLabel lblMargenSuperior = new JLabel("Margen superior");
lblMargenSuperior.setBounds(162, 127, 109, 14);
contentPane.add(lblMargenSuperior);
JLabel lblHoja = new JLabel("Hoja");
lblHoja.setBounds(46, 26, 46, 14);
contentPane.add(lblHoja);
comboBox = new JComboBox();
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent arg0) {
repaint();
}
});
comboBox.setModel(new DefaultComboBoxModel(new String[] {"Horizontal", "Vertical"}));
comboBox.setBounds(321, 55, 196, 20);
contentPane.add(comboBox);
JLabel lblHorientacinDePgina = new JLabel("Horientaciu00F3n de pu00E1gina.");
lblHorientacinDePgina.setBounds(321, 26, 203, 14);
contentPane.add(lblHorientacinDePgina);
JButton btnInicializar = new JButton("Inicializar");
btnInicializar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
sp1.setValue(0);
sp2.setValue(0);
comboBox.setSelectedIndex(0);
repaint();
}
});
btnInicializar.setBounds(45, 247, 165, 23);
contentPane.add(btnInicializar);
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.blue);
g.drawRect(30,80,100,140);
int ms=Integer.parseInt(sp1.getValue().toString());
int mi=Integer.parseInt(sp2.getValue().toString());
g.setColor(Color.red);
g.drawLine(30,80+ms,130,80+ms);
g.drawLine(30,220-mi,130,220-mi);
String direccion=(String)comboBox.getSelectedItem();
if (direccion.equals("Horizontal"))
g.drawRect(320,120,200,100 );
else
g.drawRect(320,120,100,200 );
}
}
Explicación del código.
Para el evento stateChanged de los controles JSpinner se debe llamar al método repaint() para que se grafique nuevamente las líneas de márgenes: sp1.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent arg0) {
repaint();
}
});
sp2.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
repaint();
}
});
En el método paint dibujamos primero un rectángulo de color azul que representa la hoja: g.setColor(Color.blue);
g.drawRect(30,80,100,140);
Extraemos los valores seleccionados de cada control JSpinner y los convertimos a tipo entero: int ms=Integer.parseInt(sp1.getValue().toString());
int mi=Integer.parseInt(sp2.getValue().toString());
Activamos el color rojo y dibujamos las dos líneas, la superior coincide con el comienzo del rectángulo (sumamos tantos pixeles en la fila como lo indica el primer JSpinner): g.setColor(Color.red);
g.drawLine(30,80+ms,130,80+ms);
La segunda línea le restamos el valor del JSpinner:g.drawLine(30,220-mi,130,220-mi);Para saber la orientación de la hoja debemos extraer el valor seleccionado del JComboBox y mediante un if verificar si el String seleccionado es "Horizontal":
String direccion=(String)comboBox.getSelectedItem();
if (direccion.equals("Horizontal"))
g.drawRect(320,120,200,100 );
else
g.drawRect(320,120,100,200 );
Por último cuando se presiona el botón inicializar procedemos a fijar nuevos valores a los JSpinner y al JComboBox (luego redibujamos): btnInicializar.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
sp1.setValue(0);
sp2.setValue(0);
comboBox.setSelectedIndex(0);
repaint();
}
});
Problemas propuestos
- Confeccionar un programa que permita configurar las características del mouse.
Por un lado debemos seleccionar la velocidad de desplazamiento de la flecha del mouse. Disponer un JSpinner para poder seleccionarse los valores 0,25,50,75 y 100.
Por otro lado debemos poder seleccionar cual de los dos botones del mouse será el principal, tenemos para esta función un JComboBox con dos opciones: izquierdo o derecho.
Cuando se selecciona el botón (cambio en el JComboBox) actualizar el gráfico mostrando el botón del mouse seleccionado (graficar en el método paint el mouse en pantalla)
En una aduana hay una máquina que sortea las personas cuyo equipaje serán revisados.La persona selecciona si viene del Interior del país o del Exterior (a través de un JComboBox), y por otro lado selecciona la cantidad de bultos (JSpinner).
Luego presiona el botón sortear y aparece al lado de este botón un círculo rojo o verde. (En caso de ser rojo se revisa su equipaje, en caso de ser verde, no se revisa)
Para el sorteo generar un valor aleatorio entre 1 y 3. Si se genera un 1 se revisa, si se genera un 2 o 3 no se revisa.
Validar que también este seleccionado un valor distinto a cero en bultos (los valores pueden ir de 0 a 10).
Si la cantidad de bultos supera a 5 se revisa siempre sus bultos (es decir que aparece un círculo rojo).
Luego de sortear fijar en cero cantidad de bultos.
Mostrar en el título del JFrame la cantidad de bultos revisados y no revisados hasta el momento.
package tetris;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
/**
* Esta clase implementa una hebra que hace que se mueva continuamente hacia abajo la Figura actual.
* La hebra se encarga también de ir refrescando la pantalla
* dónde se dibuja todo. Además controla si la Figura
* choca contra un muro o contra las piezas ya colocadas.
*/
public class Mueve implements Runnable{
private int delay;
private boolean continuar=true;
private boolean suspendFlag=true;
private TetrisMidlet tetrisMidlet;
/**
* Constructor de la clase, que inicializa la referencia utilizadas por
* la hebra al TetrisMidlet, establece el retardo en milisegundos
* entre movimiento y movimiento de la Figura actual, y comienza a ejecutar
* la hebra.
*/
Mueve(TetrisMidlet tetris,int nivel){
tetrisMidlet = tetris;
delay=actualizaRetardo(nivel);
Thread t=new Thread(this);
t.start();
}
/**
* Código que constituye las sentencias de la hebra. En este caso, se encarga
* de hacer que se mueva continuamente hacia abajo la figura actual
* La hebra se encarga también de ir refrescando la pantalla donde se dibuja todo.
* Además controla si la figura ha llegado a la parte de abajo para detenerla.
*/
public void run(){
try{
while(continuar){
synchronized(this){
while(suspendFlag){
wait();
}
}
Thread.sleep(delay);
if(!tetrisMidlet.getRejilla().seChoca(tetrisMidlet.getFigura(),Figura.ABAJO)){
tetrisMidlet.getFigura().mueve(Figura.ABAJO);
if(tetrisMidlet.getCanvas()!=null)
tetrisMidlet.getCanvas().repaint();
}
else{
boolean valor=tetrisMidlet.getRejilla().copiaFiguraEnRejilla(tetrisMidlet.getFigura());
tetrisMidlet.getRejilla().eliminarFilasLlenas();
if(tetrisMidlet.getCanvas()!=null)
tetrisMidlet.getCanvas().repaint();
if(!valor)
tetrisMidlet.nuevaFigura();
else{
System.out.println("He llegado al final");
continuar=false;
}
}
}// end while(continuar)
} catch(InterruptedException e){
System.out.println("Hilo MueveSerpiente interrumpido");
}
}
/**
* Detiene momentaneamente la ejecución de la hebra, haciendo que la Figura actual
* quede parada.
*/
synchronized public void suspender(){
tetrisMidlet.getCanvas().repaint();
suspendFlag=true;
}
/**
* Reanuda el movimiento de la hebra. La Figura actual vuelve a moverse.
*/
public synchronized void reanudar(){
tetrisMidlet.getCanvas().repaint();
suspendFlag = false;
notify();
}
/**
* Termina la ejecución de la hebra.
*/
public void parar(){
continuar=false;
}
/**
* Nos dice si la hebra está o no parada.
* @return true si la hebra de movimiento está parada, false en otro caso
*/
synchronized public boolean getParado(){
return suspendFlag;
}
/**
* La siguiente función actualiza el retardo que espera la hebra
* para mover la Figura actual. El nivel más lento será
* el 0 (retardo 700) y el más rápido el 10 (retardo 50)
*/
private int actualizaRetardo(int nivel) {
if (nivel>10) nivel=10;
else if (nivel<0) nivel=0;
return ( 400-(nivel*35) );
}
}
=======================================================================
/
// Animacion.java
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Sep-1996 04:10:25
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------
import java.awt.*;
import java.applet.Applet;
public class Animacion extends Applet implements Runnable {
Image imagenes[];
MediaTracker tracker;
int indice = 0;
Thread animacion;
int maxAncho,maxAlto;
Image offScrImage; // Componente off-screen para doble buffering
Graphics offScrGC;
// Nos indicará si ya se puede pintar
boolean cargado = false;
// Inicializamos el applet, establecemos su tamaño y
// cargamos las imágenes
public void init() {
// Establecemos el supervisor de imágenes
tracker = new MediaTracker( this );
// Fijamos el tamaño del applet
maxAncho = 100;
maxAlto = 100;
imagenes = new Image[18];
// Establecemos el doble buffer y dimensionamos el applet
try {
offScrImage = createImage( maxAncho,maxAlto );
offScrGC = offScrImage.getGraphics();
offScrGC.setColor( Color.lightGray );
offScrGC.fillRect( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
} catch( Exception e ) {
e.printStackTrace();
}
// Cargamos las imágenes en un array
for( int i=0; i < 18; i++ )
{
String fichero =
new String( "tierra"+String.valueOf(i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),fichero );
// Registramos las imágenes con el tracker
tracker.addImage( imagenes[i],i );
showStatus( "Cargando Imagen: "+fichero );
}
showStatus( "" );
try {
// Utilizamos el tracker para comprobar que todas las
// imágenes están cargadas
tracker.waitForAll();
} catch( InterruptedException e ) {
;
}
cargado = true;
}
// Pintamos el fotograma que corresponda
public void paint( Graphics g ) {
if( cargado )
g.drawImage( offScrImage,0,0,this );
}
// Arrancamos y establecemos la primera imagen
public void start() {
if( tracker.checkID( indice ) )
offScrGC.drawImage( imagenes[indice],0,0,this );
animacion = new Thread( this );
animacion.start();
}
// Aquí hacemos el trabajo de animación
// Muestra una imagen, para, muestra la siguiente...
public void run() {
// Obtiene el identificador del thread
Thread thActual = Thread.currentThread();
// Nos aseguramos de que se ejecuta cuando estamos en un thread
// y además es el actual
while( animacion != null && animacion == thActual )
{
if( tracker.checkID( indice ) )
{
// Obtenemos la siguiente imagen
offScrGC.drawImage( imagenes[indice],0,0,this );
indice++;
// Volvemos al principio y seguimos, para el bucle
if( indice >= imagenes.length )
indice = 0;
}
// Ralentizamos la animación para que parezca normal
try {
animacion.sleep( 200 );
} catch( InterruptedException e ) {
;
}
// Pintamos el siguiente fotograma
repaint();
}
}
}
=========================================================================Este es un ejemplo de un applet, Animacion.java, que crea un thread de animación que nos presenta el globo terráqueo en rotación.
Aquí podemos ver que estamos creando un thread de sí mismo, concurrencia.
Además, animacion.start() llama al start() del thread, no del applet, que automáticamente llamará a run():
import java.awt.*;
import java.applet.Applet;
public class Animacion extends Applet implements Runnable {
Image imagenes[];
MediaTracker tracker;
int indice = 0;
Thread animacion;
int maxAncho,maxAlto;
Image offScrImage; // Componente off-screen para doble buffering
Graphics offScrGC;
// Nos indicará si ya se puede pintar
boolean cargado = false;
// Inicializamos el applet, establecemos su tamaño y
// cargamos las imágenes
public void init() {
// Establecemos el supervisor de imágenes
tracker = new MediaTracker( this );
// Fijamos el tamaño del applet
maxAncho = 100;
maxAlto = 100;
imagenes = new Image[36];
// Establecemos el doble buffer y dimensionamos el applet
try {
offScrImage = createImage( maxAncho,maxAlto );
offScrGC = offScrImage.getGraphics();
offScrGC.setColor( Color.lightGray );
offScrGC.fillRect( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
} catch( Exception e ) {
e.printStackTrace();
}
// Cargamos las imágenes en un array
for( int i=0; i < 36; i++ )
{
String fichero =
new String( "Tierra"+String.valueOf(i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),fichero );
// Registramos las imágenes con el tracker
tracker.addImage( imagenes[i],i );
}
try {
// Utilizamos el tracker para comprobar que todas las
// imágenes están cargadas
tracker.waitForAll();
} catch( InterruptedException e ) {
;
}
cargado = true;
}
// Pintamos el fotograma que corresponda
public void paint( Graphics g ) {
if( cargado )
g.drawImage( offScrImage,0,0,this );
}
// Arrancamos y establecemos la primera imagen
public void start() {
if( tracker.checkID( indice ) )
offScrGC.drawImage( imagenes[indice],0,0,this );
animacion = new Thread( this );
animacion.start();
}
// Aquí hacemos el trabajo de animación
// Muestra una imagen, para, muestra la siguiente...
public void run() {
// Obtiene el identificador del thread
Thread thActual = Thread.currentThread();
// Nos aseguramos de que se ejecuta cuando estamos en un
// thread y además es el actual
while( animacion != null && animacion == thActual )
{
if( tracker.checkID( indice ) )
{
// Obtenemos la siguiente imagen
offScrGC.drawImage( imagenes[indice],0,0,this );
indice++;
// Volvemos al principio y seguimos, para el bucle
if( indice >= imagenes.length )
indice = 0;
}
// Ralentizamos la animación para que parezca normal
try {
animacion.sleep( 200 );
} catch( InterruptedException e ) {
;
}
// Pintamos el siguiente fotograma
repaint();
}
}
}
En el ejemplo podemos observar más cosas.La variable
thActual es propia de cada thread que se lance, y la variable animacion la estarán viendo todos los threads.No hay duplicidad de procesos, sino que todos comparten las mismas variables; cada thread, sin embargo, tiene su pila local de variables, que no comparte con nadie y que son las que están declaradas dentro de las llaves del método run().
La excepción InterruptedExcepcion salta en el caso en que se haya tenido al thread parado más tiempo del debido.
Es imprescindible recoger esta excepción cuando se están implementando threads, tanto es así, que en el caso de no recogerla, el compilador generará un error.
import java.awt.*;import java.awt.event.*;import java.applet.*;public class Principal extends Applet{ Figura f1, f2;public void init(){String velocidadGiro = getParameter("fps");int vg = (velocidadGiro != null) ? Integer.parseInt(velocidadGiro) : 10;f1=new Figura(20, 50, 100, 100, vg, Color.GREEN);f1.setSize(200,200);f1.start();f2=new Figura(40, 50, 100, 100, vg*5, Color.RED);f2.setSize(200,200);f2.start();add(f2);add(f1);}} |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| import java.awt.*;import java.awt.event.*;import java.applet.*;import java.awt.geom.*;import java.awt.Graphics2D;// Esta clase es el plano de figuras que se pintan en un canvas y pueden rotarpublic class Figura extends Canvas implements Runnable{private int delay;private int x, y, ancho, alto;private Color color;public Figura(int x, int y, int ancho, int alto, int vg, Color c){this.delay = (vg > 0) ? (1000 / vg) : 100;this.x=x;this.y=y;this.ancho=ancho;this.alto=ancho;this.color=c;}private Thread animate;public void start(){this.animate = new Thread(this);this.animate.start();}public void stop() {animate = null;}double grados=0;double r = 0; // en radianespublic void run(){while (Thread.currentThread() == this.animate){r= Math.toRadians(grados);repaint();try {Thread.sleep(delay);} catch (InterruptedException e) {break;}grados++;}}// aquí NÓTESE que para la rotacion se utilizan unos métodos muy interesantes de Graphics2Dpublic void paint(Graphics g){// super.paint(g); //se borra el contenido anteriorAffineTransform en = new AffineTransform();en.rotate(r, this.x+(this.alto/2), this.y+(this.alto/2));//se asigna el angulo y centro de rotacion((Graphics2D) g).setTransform(en);//se dibuja la figurag.setColor(this.color);g.drawRect(this.x, this.y, this.ancho, this.alto);}} |
================juego===========================
Un "juego" interactivo
Aquí está el fuente completo de un programa en Java que te permite emplear las flechas del teclado para mover una bola dentro de una ventana:import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Demo2 extends JComponent {
private final static int ANCHO = 512;
private final static int ALTO = 384;
private final static int DIAMETRO = 20;
private float x, y;
private float vx, vy;
private boolean arriba, abajo, izquierda, derecha;
public Demo2() {
setPreferredSize(new Dimension(ANCHO, ALTO));
x = 10;
y = 20;
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
actualiza(e.getKeyCode(), true);
}
public void keyReleased(KeyEvent e) {
actualiza(e.getKeyCode(), false);
}
private void actualiza(int keyCode, boolean pressed) {
switch (keyCode) {
case KeyEvent.VK_UP:
arriba = pressed;
break;
case KeyEvent.VK_DOWN:
abajo = pressed;
break;
case KeyEvent.VK_LEFT:
izquierda = pressed;
break;
case KeyEvent.VK_RIGHT:
derecha = pressed;
break;
}
}
});
setFocusable(true);
}
private float clamp(float valor, float min, float max) {
if (valor > max)
return max;
if (valor < min)
return min;
return valor;
}
private void fisica(float dt) {
vx = 0;
vy = 0;
if (arriba)
vy = -300;
if (abajo)
vy = 300;
if (izquierda)
vx = -300;
if (derecha)
vx = 300;
x = clamp(x + vx * dt, 0, ANCHO - DIAMETRO);
y = clamp(y + vy * dt, 0, ALTO - DIAMETRO);
}
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, ANCHO, ALTO);
g.setColor(Color.RED);
g.fillOval(Math.round(x), Math.round(y), DIAMETRO, DIAMETRO);
}
private void dibuja() throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
paintImmediately(0, 0, ANCHO, ALTO);
}
});
}
public void cicloPrincipalJuego() throws Exception {
long tiempoViejo = System.nanoTime();
while (true) {
long tiempoNuevo = System.nanoTime();
float dt = (tiempoNuevo - tiempoViejo) / 1000000000f;
tiempoViejo = tiempoNuevo;
fisica(dt);
dibuja();
}
}
public static void main(String[] args) throws Exception {
JFrame jf = new JFrame("Demo2");
jf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jf.setResizable(false);
Demo2 demo2 = new Demo2();
jf.getContentPane().add(demo2);
jf.pack();
jf.setVisible(true);
demo2.cicloPrincipalJuego();
}
}
Para compilar y ejecutar este programa sigue los mismos pasos que para el programa del artículo anterior. La única diferencia es que ahora tienes que guardar el programa dentro de un archivo que se llame
Demo2.java.Cómo funciona el programa
Veamos ahora el programa parte por parte para entender cómo funciona. Este programa es muy similar al programaDemo1.java del artículo anterior, por lo tanto sólo vamos a explicar los cambios que le hicimos. En el artículo anterior ("Para hacer un juego con Java") puedes averiguar cómo funciona el resto del programa.
Cómo saber si está presionada una flecha del teclado
El primer cambio en el programa es que ahora tenemos cuatro nuevas variables de instancia:private boolean arriba, abajo, izquierda, derecha;Cada una de esas variables booleanas es verdadera cuando la tecla correspondiente del teclado está presionada.
Claro que esto no ocurre automáticamente, tenemos que programar algún mecanismo para detectar cuando el usario presiona o suelta alguna de esas teclas y actualizar en ese momento la variable correspondiente.
Ese mecanismo está programado en el constructor de nuestra clase
Demo2. Aquí esta el fuente del constructor, con los cambios respecto al ejemplo del artículo anterior en negritas para resaltar las diferencias:
public Demo2() {
setPreferredSize(new Dimension(ANCHO, ALTO));
x = 10;
y = 20;
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
actualiza(e.getKeyCode(), true);
}
public void keyReleased(KeyEvent e) {
actualiza(e.getKeyCode(), false);
}
private void actualiza(int keyCode, boolean pressed) {
switch (keyCode) {
case KeyEvent.VK_UP:
arriba = pressed;
break;
case KeyEvent.VK_DOWN:
abajo = pressed;
break;
case KeyEvent.VK_LEFT:
izquierda = pressed;
break;
case KeyEvent.VK_RIGHT:
derecha = pressed;
break;
}
}
});
setFocusable(true);
}
Nota: otro cambio es que ya no estamos dandole un valor inicial al vector velocidad (variables vx y vy) dentro del constructor.Los componentes de Swing permiten que se registren con ellos unos objetos listeners (escuchadores) a los que les avisan cuando ocurren ciertos eventos dentro del componente.
Nuestra clase
Demo2 extiende (hereda de) la clase JComponent y eso hace que sea un componente de Swing. Unos de los eventos que pueden ocurrir es que el usuario presione o suelte una tecla estando ese componente seleccionado (más adelante explicamos lo que quiere decir que un componente esté seleccionado).
Para poder registarse con un componente de Swing y enterarse de los eventos relacionados con el teclado se necesita un listener que implemente la interfaz
KeyListener. Esa interfaz define tres métodos, de los cuales hay dos que nos interesan:
keyPressed() y keyReleased. Para no tener que implementar el tercer método, que no nos interesa para este programa, creamos una clase anómima que hereda de la clase KeyAdapter, la cual implementa la interfaz KeyListener con implementaciones "vacias" de sus métodos (que no hacen nada).Cada vez que el jugador presiona una tecla, el componente llama el método
keyPressed() de todos sus listeners de tipo KeyListener pasándoles como argumento un objeto KeyEvent. Cuando el jugador suelta la tecla, el componente llama el método
keyReleased() de esos mismos listeners, una vez más pasándoles como argumento un objeto KeyEvent.Los objetos
KeyEvent tienen un método getKeyCode() que devuelve un entero indicando cual fue la tecla que se presionó o se soltó. La clase
KeyEvent también define unas constantes que permiten identificar con un nombre simbólico el entero que corresponde a cada tecla. Las constantes para las flechas son: VK_UP, VK_DOWN, VK_LEFT y VK_RIGHT.Nuestras implementaciones de
keyPressed() y keyReleased() obtienen el key code de la tecla correspondiente y se lo pasan al método actualiza(): un método privado de nuestra clase anónima. También le pasan un valor booleano que es verdadero cuando se presiona una tecla y falso al soltarla. El método
actualiza() simplemente usa un switch para ver si el key code de la tecla es el de alguna de las flechas y, en caso de que sea así, almacena el valor booleano en la variable correspondiente.Una venta de Swing puede contener varios componentes.
En un momento dado sólo uno de esos componentes es el componente activo.
Es decir que únicamente uno de esos componentes es el que está interactuando con el usuario (imaginate una ventana con varios campos de texto, lo que escribes aparece solamente en uno de esos campos).
Típicamente, el usuario selecciona el componente activo con un click del mouse.
En Swing, cuando un componente es el componente activo se dice que "está enfocado" (es el foco de antención). Para que un componente pueda estar enfocado necesitamos indicarle a Swing que es un componente enfocable (focusable). Eso es lo que hacemos con la última linea del constructor:
setFocusable(true);
Física interactiva
El segundo cambio del programa es que ahora la física tiene que tomar en cuenta si alguna de las teclas de las flechas está presionada. Este es el nuevo método para calcular la física:private void fisica(float dt) {
vx = 0;
vy = 0;
if (arriba)
vy = -300;
if (abajo)
vy = 300;
if (izquierda)
vx = -300;
if (derecha)
vx = 300;
x = clamp(x + vx * dt, 0, ANCHO - DIAMETRO);
y = clamp(y + vy * dt, 0, ALTO - DIAMETRO);
}
Empezamos por asumir que la velocidad, tanto en su componente horizontal como en su componente vertical, es cero. Después checamos las variables booleanas que nos indican si se está presionada la tecla de alguna de las flechas y, cuando eso ocurre, modificamos el componente correspondiente del vector velocidad.
Ya que actualizamos los componentes horizontal y vertical del vector velocidad, de acuerdo a las teclas que están presionadas, los empleamos para calcular la nueva posición de la bola.
Al igual que en el ejemplo anterior, multiplicamos la velocidad por el tiempo transcurrido y le sumamos el resultado a la posición actual empleando las expresiones
x + vx * dt y y + vy * dt. Aquí también debemos tener cuidado de que que la bola no se salga de la ventana. Esta vez decidimos emplear un método llamado
clamp() para asegurar que los valores de las variables x y y se mantengan dentro de los límites válidos. El método
clamp() espera tres argumentos: el nuevo valor, el límite inferior y el limite superior.Cuando el nuevo valor está dentro de los límites, el método
clamp() simplemente devuelve ese mismo valor. Pero, cuando se sale de esos límites, devuelve el límite inferior si el nuevo valor era menor que él o el límite superior si el nuevo valor era mayor que él.
En inglés la palabra clamp significa abrazadera y también existe el verbo to clamp que significa asegurar: fijar sólidamente.
Estamos fijando los valores dentro de un rango válido, en el caso horizontal el valor mínimo de
x es cero (cuando la bola está en el extremo izquierdo de la ventana) y el valor máximo es ANCHO - DIAMETRO (cuando la bola está en el extremo derecho de la ventana).Y lo único que falta es la implementación del método
clamp(). Este método es tan sencillo que no requiere ninguna explicación:
private float clamp(float valor, float min, float max) {
if (valor > max)
return max;
if (valor < min)
return min;
return valor;
}
=============================================
Movimiento de Sprites en Java
Saludos amigos, les traigo un pequeño tutorial de Movimiento de Sprites en Java. Uno de los motivos que me llevó ha realizarlo era la poca información que hay en español acerca de estos temas.
Lo primero que debemos hacer es crear nuestro proyecto para generar nuestra ventana, adjunto el código para centrarnos directamente en el movimiento de sprites.
Como veremos a continuación esta es nuestra clase inicial del Proyecto a que hemos llamado “Mover_Sprites”.
El método move, cambia las coordenadas del Sprite, Estas con “X” y “Y” y estos valores son usados por el método paint para dibujar el Sprite en pantalla.
Aquí les presento 2 métodos uno simple que consiste solo en controlar los movimientos y otro un poco mas avanzado para darle una limitante a nuestra nave y no se salga de pantalla.
Método simple:
Espero les sirva este pequeño tutorial y disculpen un poco la presentación del código pero soy un poco nuevo todavía pero ya iré mejorando.
Les dejo las imágenes del Proyecto:
Lo primero que debemos hacer es crear nuestro proyecto para generar nuestra ventana, adjunto el código para centrarnos directamente en el movimiento de sprites.
Como veremos a continuación esta es nuestra clase inicial del Proyecto a que hemos llamado “Mover_Sprites”.
import javax.swing.JFrame;
public class Mover_Sprites extends JFrame{
private static final long serialVersionUID = 1L;
public Mover_Sprites()
{
add(new Escenario());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(640, 480);
setLocationRelativeTo(null);
setTitle("Mover Sprites");
setResizable(false);
setVisible(true);
}
public static void main(String[] args)
{
new Mover_Sprites();
}
}
Ahora tenemos otra clase que será nuestro escenario principal, que será donde montaremos el fondo y el sprite que usaremos para movernos en la pantalla.import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Escenario extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private Timer timer;
private Nave nave;
private String escenario = "Luna_Espacio_640_480.jpg";
ImageIcon image_icon;
public Escenario(){
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
image_icon = new ImageIcon(this.getClass().getResource(escenario));
nave = new Nave();
timer = new Timer(5, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(image_icon.getImage(), 0, 0, this);
g2d.drawImage(nave.getImage(), nave.getX(), nave.getY(), this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e){
nave.move();
repaint();
}
private class TAdapter extends KeyAdapter{
public void keyReleased(KeyEvent e){
nave.keyReleased(e);
}
public void keyPressed(KeyEvent e){
nave.keyPressed(e);
}
}
}
El método paint, se encarga de dibujar a nuestra nave para este caso y al escenario. Donde le indicaremos la imagen que queremos pintar y las coordenadas del objeto.g2d.drawImage(nave.getImage(), nave.getX(), nave.getY(), this);
El método actionPerformed es llamado cada 5ms, que se encarga de pintar los movimientos del Sprite y del Escenario.public void actionPerformed(ActionEvent e){
nave.move();
repaint();
}
Nuestra clase Nave, será la que contendrá todos los movientos de nuestra nave.import java.awt.Image; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; public class Nave { private String nave = "nave_pequeña.png"; private int dx; private int dy; private int x; private int y; private Image image; public Nave() { ImageIcon image_icon = new ImageIcon(this.getClass().getResource(nave)); image = image_icon.getImage(); x = 40; y = 60; } public void move() { if (dx > 0 && x <= 640 - 38) x += dx; else if (dx < 0 && x >= 2) x += dx; if (dy > 0 && y <= 480 - 50) y += dy; else if (dy < 0 && y >= 2) y += dy; } public int getX() { return x; } public int getY() { return y; } public Image getImage() { return image; } public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_RIGHT) { dx = 5; } if (key == KeyEvent.VK_LEFT) { dx = -5; } if (key == KeyEvent.VK_UP) { dy = -5; } if (key == KeyEvent.VK_DOWN) { dy = 5; } } public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_RIGHT) { dx = 0; } if (key == KeyEvent.VK_LEFT) { dx = 0; } if (key == KeyEvent.VK_UP) { dy = 0; } if (key == KeyEvent.VK_DOWN) { dy = 0; } } }Los métodos keyPressed y keyReleased, son los encargados de controlar los movimientos de nuestra nave tanto al presionar com al soltar las teclas.
El método move, cambia las coordenadas del Sprite, Estas con “X” y “Y” y estos valores son usados por el método paint para dibujar el Sprite en pantalla.
Aquí les presento 2 métodos uno simple que consiste solo en controlar los movimientos y otro un poco mas avanzado para darle una limitante a nuestra nave y no se salga de pantalla.
Método simple:
public void move(){
x += dx;
y += dy;
}
Método no tan simple, partiendo de este método pueden darle la limitante de pantalla a su nave, para este tutotial simplemente queme los bordes de la pantalla y los reste por el tamaño de la nave.public void move()
{
if (dx > 0 && x <= 640 - 38)
x += dx;
else
if (dx < 0 && x >= 2)
x += dx;
if (dy > 0 && y <= 480 - 50)
y += dy;
else
if (dy < 0 && y >= 2)
y += dy;
}
Cuando soltemos la tecla izquierda del cursor, la nave se dentendrá. Lo mismo y controlando cada dirección haremos para el resto.if (key == KeyEvent.VK_LEFT){ dx = 0; }Resultado final.
Espero les sirva este pequeño tutorial y disculpen un poco la presentación del código pero soy un poco nuevo todavía pero ya iré mejorando.
Les dejo las imágenes del Proyecto:











tenia que ser del cbtis copia de la copia de la copia de la copia
ResponderBorrarjajaj xd
Borrar