如何重叠Java图形和图像,使它看起来不错? [英] How to overlap java graphics and an Image and make it look nice?

查看:114
本文介绍了如何重叠Java图形和图像,使它看起来不错?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题非常具体。我正在开发一款游戏,其中有一个魔药瓶可以从敌人身上掉落。药水瓶的图像是一个带有黑色边框的透明瓶子,以及不透明的白色背景。之所以有不透明的白色背景,是因为我还需要画出瓶子里剩下多少药水。我目前的做法是:


  1. 绘制一个高度为H的矩形,表示剩下多少药水

  2. 在矩形顶部绘制魔药罐图像。

因此,这将重叠用于表示的丑陋红色矩形魔药的透明区域周围不透明的白色空间剩下的药水量。以下是结果图片:




My question is pretty specific. I'm developing a game in which there is a potion jar that can drop from enemies. The image for the potion jar is a transparent jar with a black border, and an opaque white background. The reason why there is an opaque white background is because I also need to draw how much potion is left in the jar. My current method for doing this is:

  1. Draw a rectangle of height H that signifies how much potion is left
  2. Draw the potion jar image on top of the rectangle.

Thus, this will overlap the ugly red rectangle drawn to signify the amount of potion remaining with the opaque white space around the potion's transparent area. Here is an image of the result:

http://i.imgur.com/j7ydEBF.png

The problem arises because the potion jar really does look pretty bad in game. The white background just looks horrible.

My question is: Is there any way to remove that opaque white background, while still being able to "fill" the potion jar exactly in the space that the image defines it as?

解决方案

Basically, you can create a "mask" of the original image, which can be generated from the non-opaque portions of the image.

So I created two potion images (sure you could use a sprite sheet). One which has an opaque center and one that is transparent (just the outline).

From this, I'm able to generate a mask of first image (in the color I want), use subimage to reduce the amount of the image I want to use then render it and the outline

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestOverlay {

    public static void main(String[] args) {
        new TestOverlay();
    }

    public TestOverlay() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage potionBase;
        private BufferedImage potionOutline;
        private float value = 1f;

        public TestPane() {
            try {
                potionBase = ImageIO.read(new File("Potion.png"));
                potionOutline = ImageIO.read(new File("PotionOutline.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            Timer timer = new Timer(40, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    value = value - 0.01f;
                    if (value < 0) {
                        value = 1f;
                    }
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return potionBase == null ? super.getPreferredSize() : new Dimension(potionBase.getWidth(), potionBase.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            BufferedImage mask = generateMask(potionBase, Color.RED, 1f);

            int y = (int) (mask.getHeight() * (1f - value));
            if (y < mask.getHeight()) {

                mask = mask.getSubimage(0, y, mask.getWidth(), mask.getHeight() - y);

            }

            int x = (getWidth() - mask.getWidth()) / 2;
            y = y + ((getHeight() - potionOutline.getHeight()) / 2);

            g2d.drawImage(mask, x, y, this);
            y = ((getHeight() - potionOutline.getHeight()) / 2);
            g2d.drawImage(potionOutline, x, y, this);
            g2d.dispose();
        }

    }

    public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {

        int imgWidth = imgSource.getWidth();
        int imgHeight = imgSource.getHeight();

        BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
        Graphics2D g2 = imgMask.createGraphics();

        g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

        g2.drawImage(imgSource, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
        g2.setColor(color);

        g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
        g2.dispose();

        return imgMask;

    }

    public static BufferedImage createCompatibleImage(int width, int height, int transparency) {

        BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
        image.coerceData(true);
        return image;

    }

    public static GraphicsConfiguration getGraphicsConfiguration() {

        return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

    }

}

Now, having gone through the problem, what I should have done was simply create a "filled" potion and a "empty" potion (whose inner container is empty) and simply used the same process of generating a sub image (of the filled jar) instead of generating the mask...but it was fun working up to it ;)

Basically, what this means, is the "empty" jar can be completely transparent (except for the outline) and you can paint "within" it...

This is based on the concept of tinting an image as demonstrated here

这篇关于如何重叠Java图形和图像,使它看起来不错?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆