java bufferedimage

java - BufferedImage no se borra antes de cada renderizado



(2)

¿Viste el código de ejemplo para BufferStrategy? https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferStrategy.html

Solo necesita crear un objeto BufferStrategy al inicio del programa, no todos los cuadros. Pero la razón por la que su imagen anterior no se elimina es porque nunca la elimina. Puede llamar a fillRect para hacer eso.

Estoy tratando de aprender cómo construir un juego simple a través de un tutorial que estoy viendo. Hasta ahora todo estaba bien, pero cuando muevo la imagen, la imagen anterior no se borra ni se elimina. No estoy seguro exactamente qué está mal o por qué está sucediendo. Tengo 3 clases, una clase principal, una clase de jugador y una clase de bufferimageloader.

Clase principal:

import java.awt.Canvas; import java.awt.Graphics; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.io.IOException; import javax.swing.JFrame; public class Main extends Canvas implements Runnable { private boolean running = false; private Thread thread; private BufferedImage player; private Player p; public void init(){ // load and initiliaze BufferedImageLoader loader = new BufferedImageLoader(); try { player = loader.loadImage("/player_shotgun2.png"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } p = new Player(100, 100, this); } private synchronized void start(){ if(running) return; running = true; thread = new Thread(this); thread.start(); } private synchronized void stop(){ if(!running) return; running = false; try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.exit(1); } public void run() { init(); long lastTime = System.nanoTime(); final double amountOfTicks = 60.0; double ns = 1000000000 / amountOfTicks;// 1 second divided by 60, run 60 times per second double delta = 0; int updates = 0; int frames = 0; long timer = System.currentTimeMillis(); System.out.println("hi"); while(running){ long now = System.nanoTime(); delta += (now - lastTime) / ns; lastTime = now; if(delta >= 1){// delta = 1 = 1 second tick(); updates++; delta--; } render(); frames++; if(System.currentTimeMillis() - timer > 1000){ timer+= 1000; System.out.println(updates + " Ticks, Fps " + frames); updates = 0; frames = 0; } } stop(); } // Everything thats is updated in the game private void tick(){ p.tick(); } // Everything that is rendered in the game private void render(){ BufferStrategy bs = this.getBufferStrategy(); if(bs == null){ createBufferStrategy(3); return; } Graphics g = bs.getDrawGraphics(); ////////////////////////////// p.render(g); ////////////////////////////// g.dispose(); bs.show(); } public static void main(String[] args) { // TODO Auto-generated method stub Main main = new Main(); JFrame window = new JFrame(); window.setSize(500,600); window.setTitle("Zombie Game"); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setVisible(true); window.add(main); main.start(); } public BufferedImage getPlayerImage(){ return player; }

}

Clase de jugador:

import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; public class Player extends JPanel { private double x; private double y; public BufferedImage player; public Player(double x, double y, Main main){ this.x = x; this.y = y; player = main.getPlayerImage(); } public void tick(){ x++; } public void render(Graphics g){ super.paintComponent(g); g.drawImage(player, (int)x, (int)y, null); g.dispose(); } }

Clase Bufferedimageloader:

import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; public class BufferedImageLoader { private BufferedImage image; public BufferedImage loadImage(String path) throws IOException{ image = ImageIO.read(getClass().getResource(path)); return image; } }

Este es el resultado que obtengo cuando inicio y la imagen se mueve:


Esta es una aplicación simple de Swing llamada Moving Eyes. Los globos oculares en la GUI siguen el cursor del mouse mientras mueve el cursor en el área de dibujo de la GUI.

Me doy cuenta de que no está haciendo lo que quieres hacer. Proporciono este código para que pueda ver cómo hacer una animación simple de Swing. Puede usar este código como base para hacer su propia animación.

Aquí está la interfaz gráfica de usuario de Swing.

Utilicé el modelo / vista / modelo de controlador al crear esta GUI de Swing. Esto significa que:

  1. La vista puede leer valores del modelo.
  2. La vista puede no actualizar el modelo.
  3. El controlador actualizará el modelo.
  4. El controlador volverá a pintar / revalidar la vista.

Básicamente, el modelo ignora la vista y el controlador. Esto le permite cambiar la vista y el controlador de Swing a un sitio web o una aplicación de Android.

El patrón de modelo / vista / controlador le permite concentrarse en una parte de la GUI de Swing a la vez. En general, primero creará el modelo, luego la vista y finalmente los controladores. Deberá regresar y agregar campos al modelo.

Y aquí está el código:

package com.ggl.testing; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class MovingEyes implements Runnable { private static final int drawingWidth = 400; private static final int drawingHeight = 400; private static final int eyeballHeight = 150; private static final int eyeballWidthMargin = 125; private DrawingPanel drawingPanel; private Eye[] eyes; private JFrame frame; public static void main(String[] args) { SwingUtilities.invokeLater(new MovingEyes()); } public MovingEyes() { this.eyes = new Eye[2]; this.eyes[0] = new Eye(new Point(eyeballWidthMargin, eyeballHeight)); this.eyes[1] = new Eye(new Point(drawingWidth - eyeballWidthMargin, eyeballHeight)); } @Override public void run() { frame = new JFrame("Moving Eyes"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); drawingPanel = new DrawingPanel(drawingWidth, drawingHeight); frame.add(drawingPanel); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public class DrawingPanel extends JPanel { private static final long serialVersionUID = -2977860217912678180L; private static final int eyeballOuterRadius = 50; private static final int eyeballInnerRadius = 20; public DrawingPanel(int width, int height) { this.addMouseMotionListener(new EyeballListener(this, eyeballOuterRadius - eyeballInnerRadius - 5)); this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(width, height)); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.BLACK); for (Eye eye : eyes) { drawCircle(g, eye.getOrigin(), eyeballOuterRadius); fillCircle(g, eye.getEyeballOrigin(), eyeballInnerRadius); } } private void drawCircle(Graphics g, Point origin, int radius) { g.drawOval(origin.x - radius, origin.y - radius, radius + radius, radius + radius); } private void fillCircle(Graphics g, Point origin, int radius) { g.fillOval(origin.x - radius, origin.y - radius, radius + radius, radius + radius); } } public class Eye { private final Point origin; private Point eyeballOrigin; public Eye(Point origin) { this.origin = origin; this.eyeballOrigin = origin; } public Point getEyeballOrigin() { return eyeballOrigin; } public void setEyeballOrigin(Point eyeballOrigin) { this.eyeballOrigin = eyeballOrigin; } public Point getOrigin() { return origin; } } public class EyeballListener extends MouseMotionAdapter { private final double eyeballDistance; private final DrawingPanel drawingPanel; public EyeballListener(DrawingPanel drawingPanel, double eyeballDistance) { this.drawingPanel = drawingPanel; this.eyeballDistance = eyeballDistance; } @Override public void mouseMoved(MouseEvent event) { Point p = event.getPoint(); for (Eye eye : eyes) { Point origin = eye.getOrigin(); double theta = Math.atan2((double) (p.y - origin.y), (double) (p.x - origin.x)); int x = (int) Math.round(Math.cos(theta) * eyeballDistance) + origin.x; int y = (int) Math.round(Math.sin(theta) * eyeballDistance) + origin.y; eye.setEyeballOrigin(new Point(x, y)); } drawingPanel.repaint(); } } }

Modelo

La clase Eye es un objeto Java que contiene el origen del ojo (círculo) y el origen del globo ocular. La clase Eye es el modelo en este simple ejemplo.

Ver

La clase MovingEyes es la clase que define el JFrame. La clase MovingEyes es parte de la vista. El método principal de esta clase invoca el método invokeLater de SwingUtilities para garantizar que los componentes de Swing se definan y modifiquen en el subproceso de envío de eventos.

Usamos un JFrame. No extendemos un JFrame. El único momento en que extiende un componente Swing, o cualquier clase de Java, es cuando desea anular uno de los métodos de la clase. Veremos esto cuando hable sobre el DrawingPanel.

El constructor de la clase MovingEyes define 2 instancias de la clase Eye. El método de ejecución define el JFrame. El código en el método de ejecución será similar para todas las GUI de Swing.

La clase DrawingPanel constituye el resto de la vista. La clase DrawingPanel extiende JPanel porque queremos anular el método paintComponent. El constructor de la clase DrawingPanel establece el tamaño preferido del área de dibujo y agrega el detector de movimiento del mouse. El oyente de movimiento del mouse es el controlador de esta GUI de Swing.

El método paintComponent de la clase DrawingPanel primero llama al método super paintComponent. Esto mantiene la cadena de pintura Swing, y siempre debe ser la primera declaración del método paintComponent sobrescrito.

El resto del código en el método paintComponent de la clase DrawingPanel dibuja los ojos. Solo tenemos código de dibujo (pintura) en el método paintComponent. El código de control pertenece al controlador.

Controlador

La clase EyeballListener es la clase de controlador. Puede tener más de una clase de controlador en una GUI Swing más complicada.

La clase EyeballListener extiende MouseMotionAdapter. Puede implementar MouseMotionListener. Estoy anulando un método, por lo que el código es más corto cuando extiendo el MouseMotionAdapter.

El método mouseMoved de la clase EyeballListener dispara un MouseEvent cuando se mueve el mouse. Calculamos una nueva posición para el centro de un globo ocular al encontrar el ángulo theta desde el centro del ojo hasta la posición del mouse. El ángulo theta se usa para calcular el nuevo centro del globo ocular.

Cada instancia de Eye se actualiza por separado en el ciclo for. Después de actualizar ambos ojos, el panel de dibujo se vuelve a pintar. Esto sucede tan rápido que no hay necesidad de un bucle de animación en un hilo separado.

Un bucle de animación actualiza el modelo, dibuja la vista y espera un período de tiempo específico. Usaría un hilo separado para el bucle de animación, de modo que la GUI en el hilo de Despacho de eventos siga respondiendo. Si su GUI no responde, probablemente esté haciendo demasiado trabajo en el hilo de Despacho de eventos.