Java 将BuffereImage的像素设置为透明

Java 将BuffereImage的像素设置为透明,java,swing,game-engine,bufferedimage,alpha,Java,Swing,Game Engine,Bufferedimage,Alpha,如何快速有效地将buffereImage的所有像素设置为透明,以便只需为每个帧重新绘制所需的精灵图形 我正在用java设计一个简单的游戏引擎,它更新背景和前景buffereImage,并将它们绘制到一个组合VolatileImage,以便有效地进行缩放,从而绘制到JPanel。这个可扩展的模型允许我添加更多的图层,并在每个绘图图层上迭代 我将我的应用程序简化为下面给出的一个类来演示我的问题。使用箭头键在图像上移动红方块。挑战是我想将更新游戏图形从绘制合成图形到游戏引擎的过程解耦。我已经研究了这个

如何快速有效地将
buffereImage
的所有像素设置为透明,以便只需为每个帧重新绘制所需的精灵图形

我正在用java设计一个简单的游戏引擎,它更新背景和前景
buffereImage
,并将它们绘制到一个组合
VolatileImage
,以便有效地进行缩放,从而绘制到
JPanel
。这个可扩展的模型允许我添加更多的图层,并在每个绘图图层上迭代

我将我的应用程序简化为下面给出的一个类来演示我的问题。使用箭头键在图像上移动红方块。挑战是我想将更新游戏图形从绘制合成图形到游戏引擎的过程解耦。我已经研究了这个问题的看似彻底的答案,但不知道如何将它们应用到我的申请中:

这里是无法正确清除像素的关键部分。注释掉的部分来自我已经读过的堆栈溢出答案,但它们要么将背景绘制为不透明的黑色或白色。我知道在我的实现中,
背景图像
以透明像素开始,因为当应用程序开始时,您可以看到红色精灵后面的
背景图像
的随机像素噪声。现在,图像未被清除,因此先前绘制的图像仍保留

/** Update the foregroundGraphics. */
private void updateGraphics(){
    Graphics2D fgGraphics = (Graphics2D) foregroundImage.getGraphics(); 

    // set image pixels to transparent
    //fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
    //fgGraphics.setColor(new Color(0,0,0,0));
    //fgGraphics.clearRect(0, 0, width, height);
    //fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

    // draw again.
    fgGraphics.setColor(Color.RED);
    fgGraphics.fillRect(sx, sy, spriteSize, spriteSize);
    fgGraphics.dispose();
}
下面是我的全部示例代码:

/**
 * The goal is to draw two BufferedImages quickly onto a scalable JPanel, using 
 * a VolatileImage as a composite.
 */
public class Example extends JPanel implements Runnable, KeyListener
{   
    private static final long   serialVersionUID = 1L;
    private int                 width;
    private int                 height;
    private Object              imageLock;
    private Random              random;
    private JFrame              frame;
    private Container           contentPane;
    private BufferedImage       backgroundImage;
    private BufferedImage       foregroundImage;
    private VolatileImage       compositeImage;
    private Graphics2D          compositeGraphics;
    private int[]               backgroundPixels;
    private int[]               foregroundPixels;
    // throttle the framerate.
    private long                prevUpdate; 
    private int                 frameRate;
    private int                 maximumWait;
    // movement values.
    private int speed;
    private int sx;
    private int sy;
    private int dx;
    private int dy;
    private int spriteSize;

    /** Setup required fields. */
    public Example(){
        width = 512;
        height = 288;
        super.setPreferredSize(new Dimension(width, height));
        imageLock = new Object();
        random = new Random();
        frame = new JFrame("BufferedImage Example");
        frame.addKeyListener(this);
        contentPane = frame.getContentPane();
        contentPane.add(this, BorderLayout.CENTER); 
        // used to create hardware-accelerated images.
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        backgroundImage = gc.createCompatibleImage(width, height,Transparency.TRANSLUCENT);
        foregroundImage = gc.createCompatibleImage(width, height,Transparency.TRANSLUCENT);
        compositeImage = gc.createCompatibleVolatileImage(width, height,Transparency.TRANSLUCENT);
        compositeGraphics = compositeImage.createGraphics();
        compositeGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        compositeGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        backgroundPixels = ((DataBufferInt) backgroundImage.getRaster().getDataBuffer()).getData();
        foregroundPixels = ((DataBufferInt) foregroundImage.getRaster().getDataBuffer()).getData();     
        //initialize the background image.
        for(int i = 0; i < backgroundPixels.length; i++){
            backgroundPixels[i] = random.nextInt();
        }
        // used to throttle frames per second
        frameRate = 180;
        maximumWait = 1000 / frameRate;
        prevUpdate = System.currentTimeMillis();
        // used to update sprite state.
        speed = 1;
        dx = 0;
        dy = 0;
        sx = 0;
        sy = 0;     
        spriteSize = 32;
    }

    /** Renders the compositeImage to the Example, scaling to fit. */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        // draw the composite, scaled to the JPanel.
        synchronized (imageLock) {
            ((Graphics2D) g).drawImage(compositeImage, 0, 0, super.getWidth(), super.getHeight(), 0, 0, width, height, null);
        }
        // force repaint.
        repaint();
    }

    /** Update the BufferedImage states. */
    @Override
    public void run() {
        while(true){
            updateSprite();
            updateGraphics();
            updateComposite();
            throttleUpdateSpeed();
        }
    }

    /** Update the Sprite's position. */
    private void updateSprite(){
        // update the sprite state from the inputs.
        dx = 0;
        dy = 0;         
        if (Command.UP.isPressed()) dy -= speed;
        if (Command.DOWN.isPressed()) dy += speed;
        if (Command.LEFT.isPressed()) dx -= speed;
        if (Command.RIGHT.isPressed()) dx += speed;
        sx += dx;
        sy += dy;
        // adjust to keep in bounds.
        sx = sx < 0 ? 0 : sx + spriteSize >= width ? width - spriteSize : sx;
        sy = sy < 0 ? 0 : sy + spriteSize >= height ? height - spriteSize : sy;
    }

    /** Update the foregroundGraphics. */
    private void updateGraphics(){
        Graphics2D fgGraphics = (Graphics2D) foregroundImage.getGraphics(); 

        // set image pixels to transparent
        //fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
        //fgGraphics.setColor(new Color(255, 255, 255, 255));
        //fgGraphics.clearRect(0, 0, width, height);
        //fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

        // draw again.
        fgGraphics.setColor(Color.RED);
        fgGraphics.fillRect(sx, sy, spriteSize, spriteSize);
        fgGraphics.dispose();
    }

    /** Draw the background and foreground images to the volatile composite. */
    private void updateComposite(){
        synchronized (imageLock) {
            compositeGraphics.drawImage(backgroundImage, 0, 0, null);
            compositeGraphics.drawImage(foregroundImage, 0, 0, null);
        }

    }

    /** Keep the update rate around 60 FPS. */
    public void throttleUpdateSpeed(){
        try {
            Thread.sleep(Math.max(0, maximumWait - (System.currentTimeMillis() - prevUpdate)));
            prevUpdate = System.currentTimeMillis();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /** Ignore key typed events. */
    @Override
    public void keyTyped(KeyEvent e) {}

    /** Handle key presses. */
    @Override
    public void keyPressed(KeyEvent e) {
        setCommandPressedFrom(e.getKeyCode(), true);
    }

    /** Handle key releases. */
    @Override
    public void keyReleased(KeyEvent e) {
        setCommandPressedFrom(e.getKeyCode(), false);
    }

    /** Switch over key codes and set the associated Command's pressed value. */
    private void setCommandPressedFrom(int keycode, boolean pressed){
        switch (keycode) {
        case KeyEvent.VK_UP:
            Command.UP.setPressed(pressed);
            break;
        case KeyEvent.VK_DOWN:
            Command.DOWN.setPressed(pressed);
            break;
        case KeyEvent.VK_LEFT:
            Command.LEFT.setPressed(pressed);
            break;
        case KeyEvent.VK_RIGHT:
            Command.RIGHT.setPressed(pressed);
            break;
        }
    }
    /** Commands are used to interface with key press values. */
    public enum Command{
        UP, DOWN, LEFT, RIGHT;      
        private boolean pressed;

        /** Press the Command. */
        public void press() {
            if (!pressed) pressed = true;
        }
        /** Release the Command. */
        public void release() {
            if (pressed) pressed = false;
        }       
        /** Check if the Command is pressed. */
        public boolean isPressed() {
            return pressed;
        }       
        /** Set if the Command is pressed. */
        public void setPressed(boolean pressed) {
            if (pressed) press();
            else release();
        }
    }

    /** Begin the Example. */
    public void start(){
        try {           
            // create and display the frame.
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    Example e = new Example();
                    frame.pack();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });         
            // start updating from key inputs.
            Thread t = new Thread(this);
            t.start();          
        }
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /** Start the application. */
    public static void main(String[] args){
        Example e = new Example();
        e.start();
    }   
}
/**
*目标是使用
*作为复合物的挥发物。
*/
公共类示例扩展了JPanel实现可运行的KeyListener
{   
私有静态最终长serialVersionUID=1L;
私有整数宽度;
私人内部高度;
私有对象映像锁;
私有随机;
私有JFrame;
专用容器内容窗格;
私有缓冲图像背景图像;
专用缓冲区图像前景图像;
私人挥发图像合成图像;
专用图形2D合成图;
私有int[]背景像素;
私有int[]像素;
//限制帧速率。
私人长期更新;
私有整数帧率;
私有int最大等待;
//运动值。
私人整数速度;
私人int sx;
私人int sy;
私人int dx;
私家侦探;
私人智力精神化;
/**设置必填字段*/
公共示例(){
宽度=512;
高度=288;
super.setPreferredSize(新尺寸(宽度、高度));
imageLock=新对象();
随机=新随机();
frame=newjframe(“BufferedImage示例”);
frame.addKeyListener(这个);
contentPane=frame.getContentPane();
contentPane.add(这个,BorderLayout.CENTER);
//用于创建硬件加速映像。
GraphicsConfiguration gc=GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
backgroundImage=gc.createCompatibleImage(宽度、高度、透明度、半透明);
foregroundImage=gc.createCompatibleImage(宽度、高度、透明度、半透明);
compositeImage=gc.createCompatibleVolatileImage(宽度、高度、透明度、半透明);
compositeGraphics=compositeImage.createGraphics();
compositeGraphics.setRenderingHint(RenderingHits.KEY\u抗锯齿,RenderingHits.VALUE\u抗锯齿\u开启);
compositeGraphics.setRenderingHint(renderingHits.KEY\u RENDERING,renderingHits.VALUE\u RENDER\u QUALITY);
backgroundPixels=((DataBufferInt)backgroundImage.getRaster().getDataBuffer()).getData();
foregroundPixels=((DataBufferInt)foregroundImage.getRaster().getDataBuffer()).getData();
//初始化背景图像。
对于(int i=0;i=宽度?宽度-spriteSize:sx;
sy=sy<0?0:sy+spriteSize>=高度?高度-spriteSize:sy;
}
/**更新foregroundGraphics*/
私有void updateGraphics(){
Graphics2D fgGraphics=(Graphics2D)foregroundImage.getGraphics();
//将图像像素设置为透明
//fgGraphics.setC
    // clear pixels
    fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
    fgGraphics.setColor(new Color(255,255,255,255));
    fgGraphics.fillRect(0, 0, width, height);
    fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
    // draw new graphics
    // clear pixels
    fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT));
    fgGraphics.setColor(new Color(255,255,255,0));
    fgGraphics.fillRect(0, 0, width, height);
    fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
    // draw new graphics