Je travaille sur un jeu 2D simple. Chaque tick, je veux vérifier une file d'effets qui démarrera un thread pour un certain effet (transitions en fondu, fondu entrant et sortant audio, etc). Par exemple, en appuyant sur "Play" sur l'écran du menu ajoutera un message "FadeOut" à cette file d'attente, qui sera traitée et démarrera un thread pour dessiner un rectangle noir avec une valeur alpha croissante sur mon GamePanel.Comment remplacer une image BufferedImage dessinée à JPanel en dehors de PaintComponent() avec getGraphics()
Je substitue paintComponent() et envoie mon objet Graphics à mon GameStateManager, qui transmet l'objet Graphics aux états actuels draw(). Je n'ai pas actuellement d'état d'effets (ce que je devrais peut-être) pour router l'objet graphics paintComponent(), mais je passe mon gamepanel à mon thread d'effets, où je peux utiliser getGraphics() pour dessiner dessus. Dessiner un rectangle directement sur le GamePanel provoque simplement des scintillements, car le gameloop restaure le jeu.
J'ai trouvé que je peux dessiner un rectangle noir avec un alpha croissant à un BufferedImage, mettre le composite à AlphaComposite.Src (qui provoque le remplacement de l'ancien) puis dessiner le BufferedImage sur le panneau de jeu. Le problème est que les images BufferedImages dessinées sur le panneau de jeu ne sont pas remplacées à chaque tirage, de sorte que le fondu se produit très rapidement car ces images tamponnées noires de divers alphas se superposent.
J'ai écrit ce programme court pour tester les paramètres composites et voir ce qui est surchargé. Tout le dessin est fait dans le draw(), ce qui serait mon run() dans le thread d'effets.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ScratchPad extends JPanel implements Runnable
{
private JFrame oFrame = null;
private Thread oGameThread = null;
private Graphics2D oPanelGraphics = null;
private Graphics2D oImageGraphics = null;
private BufferedImage oImage = null;
public static void main(String args[]) throws Exception
{
new ScratchPad();
}
public ScratchPad()
{
createFrame();
initPanel();
addAndShowComponents();
oGameThread = new Thread(this, "Game_Loop");
oGameThread.start();
}
private void addAndShowComponents()
{
oFrame.add(this);
oFrame.setVisible(true);
}
private void initPanel()
{
this.setOpaque(true);
this.setBackground(Color.cyan);
}
private void createFrame()
{
oFrame = new JFrame("Fade");
oFrame.setSize(700, 300);
oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
oFrame.setLocationRelativeTo(null);
}
public void run()
{
oImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
while(true)
{
try
{
draw();
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
private void draw()
{
oPanelGraphics = (Graphics2D)this.getGraphics();
oImageGraphics = oImage.createGraphics();
oImageGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,90));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.setColor(new Color(0,0,0,60));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 220, 10, null);
oImageGraphics.setColor(new Color(0,0,0,30));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 430, 10, null);
// Drawing this image over location of first image, should overwrite first
// after setting composite to 'Src'
oPanelGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,10));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.dispose();
oPanelGraphics.dispose();
}
} // end class
Ce qui est intéressant est la mise en composite sur « oPanelGraphics » provoque une alpha du BufferedImage pour aller, ce qui produit une image totalement opaque étant tiré sur l'image qui était auparavant là. Même le réglage de la couleur sur autre chose que le noir n'a aucun effet.
Ce qui est aussi intéressant est la mise en composite pour le BufferedImage à:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
provoque rien à afficher. La documentation d'Oracle sur les graphismes de composition dans Java2D indique ceci pour 'SrcIn':
"Si les pixels de la source et de la destination se chevauchent, seuls les pixels source dans la zone de chevauchement sont rendus." Donc, je m'attendrais à avoir le même comportement qu'avec AlphaComposite.Src. Peut-être que quelqu'un là-bas peut faire la lumière sur ce qui se passe avec ces composites, et comment je pourrais obtenir l'effet désiré.
Vous pouvez remplacer l'onDraw (Graphics g2d) dans votre panneau au lieu de faire cette méthode draw()? –
@MarcosVasconcelos Oui, c'est ce que je fais actuellement. Cependant, mon idée de manipuler les effets dans mon jeu (transitions, fondus d'écran et audio et fondus) consistait à avoir des actions (cliquer sur "Jouer" dans le menu, ou des caractères sur certaines tuiles) ajouter des messages à une file d'attente vérifiée chaque tick de jeu. Ces effets déclencheront un fil et seront traités là, et la boucle de jeu peut continuer. Je ne suis actuellement pas en train de router mon objet Graphics fourni paintComponent() à ma classe Effects. C'est pourquoi j'utilise getGraphics dans le thread d'effets – WhitJackman
Basé sur votre code, vous ne surchargez pas du tout 'paintComponent', mais vous utilisez' getGraphics', ce qui n'est pas recommandé, car vous essayez de mettre à jour l'interface en dehors du contexte du cycle de peinture défini par Swing. Vous ne devriez jamais disposer d'un contexte 'Graphics' que vous n'avez pas créé. Je ne vois pas non plus le point de 'BufferedImage'. – MadProgrammer