BufferedImage non viene cancellato prima di ogni rendering

Sto cercando di imparare come build un gioco semplice attraverso un tutorial che sto guardando. Fino ad ora tutto andava bene, ma quando sposto l’immagine l’immagine precedente non viene cancellata o eliminata. Non sono sicuro esattamente di cosa si stia sbagliando, o perché sia ​​successo. Ho 3 classi, una class principale, una class di giocatori e una class bufferimageloader.

Classe principale:

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; } 

}

Classe del giocatore:

 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(); } } 

Classe 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; } } 

Questo è l’output che ottengo quando avvio e l’immagine si sposta:

inserisci la descrizione dell'immagine qui

Questa è una semplice applicazione Swing chiamata Moving Eyes. I bulbi oculari nella GUI seguono il cursore del mouse mentre muovi il cursore nell’area di disegno della GUI.

Mi rendo conto che non sta facendo quello che vuoi fare. Fornisco questo codice in modo da poter vedere come eseguire un’animazione Swing semplice. Puoi usare questo codice come base per fare la tua animazione.

Ecco la GUI Swing.

Moving Eyes

Ho usato il modello modello / vista / controllore durante la creazione di questa GUI Swing. Ciò significa che:

  1. La vista può leggere valori dal modello.
  2. La vista potrebbe non aggiornare il modello.
  3. Il controller aggiornerà il modello.
  4. Il controller ridisegna / riconvalida la vista.

Fondamentalmente, il modello è ignorante della vista e del controller. Ciò consente di modificare la visualizzazione e il controller da Swing a un sito Web o un’app Android.

Il pattern model / view / controller consente di concentrarsi su una parte della GUI Swing alla volta. In generale, prima creerai il modello, poi la vista e infine i controller. Dovrai tornare indietro e aggiungere campi al modello.

Ed ecco il codice:

 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) (py - origin.y), (double) (px - 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(); } } } 

Modello

La class Eye è un object Java che contiene l’origine dell’occhio (cerchio) e l’origine del bulbo oculare. La class Eye è il modello in questo semplice esempio.

vista

La class MovingEyes è la class che definisce JFrame. La class MovingEyes è parte della vista. Il metodo principale di questa class richiama il metodo invokeLater di SwingUtilities per assicurare che i componenti Swing siano definiti e modificati nel thread Event Dispatch.

Usiamo un JFrame. Non estendiamo un JFrame. L’unica volta che estendi un componente Swing o una qualsiasi class Java, è quando desideri sovrascrivere uno dei metodi della class. Vedremo questo quando parlo del DrawingPanel.

Il costruttore della class MovingEyes definisce 2 istanze della class Eye. Il metodo run definisce JFrame. Il codice nel metodo run sarà simile per tutte le GUI Swing.

La class DrawingPanel costituisce il resto della vista. La class DrawingPanel estende JPanel perché vogliamo sovrascrivere il metodo paintComponent. Il costruttore della class DrawingPanel imposta la dimensione preferita dell’area di disegno e aggiunge il listener di movimento del mouse. L’ascoltatore di movimento del mouse è il controller di questa GUI Swing.

Il metodo paintComponent della class DrawingPanel chiama prima il metodo super paintComponent. Ciò mantiene la catena di vernice Swing e dovrebbe sempre essere la prima dichiarazione del metodo paintComponent sovrascritto.

Il resto del codice nel metodo paintComponent della class DrawingPanel disegna gli occhi. Abbiamo solo il codice di disegno (pittura) nel metodo paintComponent. Il codice di controllo appartiene al controller.

controllore

La class EyeballListener è la class controller. Puoi avere più di una class controller in una GUI Swing più complicata.

La class EyeballListener estende MouseMotionAdapter. È ansible implementare MouseMotionListener. Sto sovrascrivendo un metodo, quindi il codice è più breve quando estendo MouseMotionAdapter.

Il metodo mouseMoved della class EyeballListener triggers un object MouseEvent quando viene spostato il mouse. Calcoliamo una nuova posizione per il centro di un bulbo oculare trovando l’angolo theta dal centro dell’occhio alla posizione del mouse. L’angolo theta viene utilizzato per calcolare il nuovo centro del bulbo oculare.

Ogni istanza Eye viene aggiornata separatamente nel ciclo for. Dopo l’aggiornamento di entrambi gli occhi, il riquadro di disegno viene ridipinto. Questo accade così velocemente che non c’è bisogno di un ciclo di animazione in un thread separato.

Un ciclo di animazione aggiorna il modello, disegna la vista e attende un determinato periodo di tempo. Si utilizzerà un thread separato per il ciclo di animazione, in modo che la GUI nel thread di Invio eventi rimanga retriggers. Se la tua GUI non è retriggers, stai probabilmente facendo troppo lavoro sul thread Event Dispatch.

Hai guardato il codice di esempio per BufferStrategy? https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferStrategy.html

Devi solo creare un object BufferStrategy all’inizio del programma, non tutti i frame. Ma il motivo per cui la tua vecchia immagine non viene cancellata è perché non la elimini mai. Potresti chiamare fillRect per farlo.