Java游戏2D重叠阴影与Swing

时间:2016-07-05 20:58:41

标签: java swing paintcomponent java-2d

我目前正在使用Swing作为我的主要绘图组件开发2D Java游戏。每个对象都有一个阴影(BufferedImage),但每个阴影都与其他阴影重叠。是否可以只让阴影不相互重叠?因为如果对象在它下面,我仍然希望阴影在玩家上方绘制,而不是如果对象在玩家之上。为清晰起见,这是一张图片:

Screenshot

我看过alpha合成,我想我需要Source Out?我还想过让所有阴影(没有透明度)在一个图层上绘制,然后用透明度绘制它,然后它不会像以前那样在玩家和其他对象上绘制。

我有一个Draw对象,它是一个JPanel并覆盖了paintComponent方法。在这个方法中,我绘制当前房间的地板,然后迭代属于当前房间的对象列表,并调用每个对象的绘制方法来绘制所有内容。

对象绘制方法:

public void draw(Graphics g) {
    if (visible && checkInScreen()) {

        // The required drawing location
        int drawLocationX = getX() - globalCameraX;
        int drawLocationY = getY() - globalCameraY;

        if (shadow) {
            g.drawImage(shadowImages.get(imageIndex),
                    drawLocationX + shadowOffset.x + (getImageWidth()/2),
                    drawLocationY + shadowOffset.y, null);
        }
        g.drawImage(images.get(imageIndex), drawLocationX, drawLocationY, null);

        //Collisionbox
        if (SHOW_COLLISION_BOXES){
            g.setColor(Color.WHITE);
            g.drawRect(drawLocationX + getCollBoxX(), drawLocationY + getCollBoxY(), getCollBoxW() - getCollBoxX(), getCollBoxH() - getCollBoxY());
        }
    }
}

如果已经提出这个问题,我很抱歉,但我找不到类似的东西。

2 个答案:

答案 0 :(得分:1)

我要做的是要有一个阴影层位图。我的意思是: 将阴影纹理保存为布尔值的二维数组(表示阴影像素的位置)。

你可以用它来做逻辑或阴影贴图一起创建一个单独的图层,可以在树纹理后面分层以创建阴影。

您可能希望将布尔值更改为浮点数以表示阴影的颜色/强度,然后使用更大的计算将阴影合并在一起。

下面的ShadowMap类用于存储每个阴影的数据:

class ShadowMap {

    public int xPos, yPos;
    public boolean[][] array;

    public ShadowMap(int xPos, int yPos, boolean[][] array) {
        this.xPos = xPos;
        this.yPos = yPos;
        this.array = array;
    }

}

ShadowLayer类为整个屏幕创建一个2D数组,包含每个像素是否存在阴影:

class ShadowLayer {

    public static boolean[][] array = new boolean[SCREEN_WIDTH][SCREEN_HEIGHT];

    public static makeNew(ShadowMap[] shadows) {
        for (int x = 0; x < SCREEN_WIDTH; x++) {
            for (int y = 0; y < SCREEN_HEIGHT; y++) {
                array[x][y] = false;
            }
        }
        for (ShadowMap map : shadows) {
            for (int i = 0; i < SCREEN_WIDTH; i++) {
                for (int j = 0; j < SCREEN_HEIGHT; j++) {
                    // Logical or such that the pixel at (x, y) has a shadow 
                    // if any shadow map also has a shadow at pixel (x, y)
                    array[i + map.xPos][j + map.yPos] |= map.array[i][j];
                }
            }
        }
    }

}

使用此ShadowLayer类,如果ShadowMap在同一像素上有阴影,则只需要使屏幕上的每个像素变暗:

public static Color ajustPixelForShadows(int x, int y, Color pixel) {
    return ShadowMap.array[x][y] ? pixel.darken() : pixel;
}

答案 1 :(得分:1)

我承认我不熟悉Swing,因此我不确定该特定界面是否可行,但以下解决方案可用于各种2D图形引擎。

你需要一个离屏&#34;阴影层&#34;绘制到匹配屏幕尺寸。将阴影层初始化为纯白色。

对于从后向前绘制的每个对象(y排序),按顺序执行以下操作,使用阴影层:

  • 将对象的阴影形状以单一实心深灰色绘制到阴影层

  • 将对象本身绘制为阴影图层,作为纯白色精灵(即对象位图中的所有非透明像素均为白色)

当然,也将对象本身绘制到屏幕上。

然后,一旦所有对象都被绘制到屏幕和阴影层,使用多重混合将阴影层绘制到屏幕上。多重混合可确保阴影会使绘制的任何内容变暗(与alpha混合不同,非常轻的阴影可能会实际上减轻它们被绘制的颜色)。它还会使图层的纯白色部分无效,这就是你想要的。

上述步骤意味着在每个对象绘制阴影后,它会在最终场景中将其自身绘制为阴影图层时删除其下方的任何阴影。因此,它不会在自身上投下阴影,并且物体不会将阴影投射到技术上位于其前面的其他物体上。

对象仍然可以根据需要将阴影投射到其后面的其他对象上,因为尚未被重叠对象擦除的阴影的任何部分仍然适用(或者如果它们被删除,则可能是由后来的对象重新绘制)。并且,由于您将阴影作为单个非半透明颜色绘制到阴影层,因此多个阴影重叠也不会相互影响,这当然是主要观点。

您可以根据可用内容修改此技术。例如,您最初可以使用完全透明的阴影图层而不是白色,并且可以使用&#34;擦除&#34;混合模式[(src * 0)+(dst *(1 - srcAlpha))]来绘制擦除阴影下方的对象。如果您希望将阴影图层绘制到屏幕上,则可以使用alpha而不是乘法混合。