Libgdx在运行时更改纹理颜色

9
在使用libgdx制作的游戏中,我有一个TextureAtlas,其中存储了我的Player的所有AnimationTextureRegion。默认情况下,Player有一件蓝色的T恤(例如)。现在我想能够拥有多个Player,每个都应该有另一种T恤颜色。因此,基本上,我想将第二个Player的蓝色替换为红色,并将第三个Player的蓝色替换为绿色,依此类推。我确定我可以使用PixMap来做到这一点,但不想这样做。因为那样我就失去了TextureAtlas的优势(?)。 还有其他方法吗?或者我需要将每个“颜色版本”作为TextureRegion放入TextureAtlas中吗?
另一个小问题: 使用Gimp(和可能是其他一些程序),您可以为“.gif”文件使用颜色索引。这通过为文件中的每种颜色保存一个索引,然后使用此索引来描述像素来减小所有Texture的大小。因此,对于每个红色像素,您将拥有“1”而不是“#FF0000”,并且在文件的某个地方,您将拥有“1 =#FF0000”。如果我们然后使用颜色索引将“.gif”文件打包到TextureAtlas中,那么索引是否会丢失,并恢复默认的RGB颜色,还是会出现问题?
非常感谢!

只需将T恤纹理变为白色,然后在渲染红色玩家之前使用spriteBatch.setColor(1, 0, 0, 1)即可。 - noone
1
我总是使用一些 SpriteSprite#setColor(Color tint) 进行此操作 :) - NiziL
如果我这样做,整个“TextureRegion”都会受到影响,还是我错了?它只会影响白色部分吗? - Robert P
@Nizil 这将与 spriteBatch.setColor(1, 0, 0, 1) 相同,但仅适用于 Sprites,我有 TextureRegions。无论如何还是谢谢 (: - Robert P
3个回答

4
一种制作方法是设置最大玩家数,为每个人制作T恤,并将它们打包到纹理图集中,然后添加到一个TextureRegion数组中。现在,您只需要在索引之间切换即可。
另一种方法是使用batch.setColor。
void    setColor(Color tint)
void    setColor(float color) 
void    setColor(float r, float g, float b, float a) 

对于你绘制的每件T恤,只需设置精灵批处理的颜色,在绘制完所有T恤后,将精灵批处理的颜色再次设置为白色。

您也可以使用Sprite类的setColor函数来实现此操作。

如果您的T恤尺寸不是很大,并且您的最大玩家数量很少,我建议使用第一种方法。


1
你是如何想到数字15的?为什么更喜欢第一种方法?对我来说似乎是更糟糕的选择。改变颜色基本上会产生无限数量的不同衬衫,而你只需要维护单个衬衫的纹理即可。 - noone
这只是我的观点,一款游戏可能不会有超过15个玩家,不管怎样我已经编辑过了。我会使用这种方法,因为它是最简单的方式,对于小尺码的球衣和玩家数量,就像我所说的,很容易为每个玩家分配一个索引。 - Boldijar Paul
谢谢你的回答。如果每种颜色只有一件T恤,那就没有问题了,但是玩家的“动画”将包含更多的“纹理”,所以这不是一个真正的选择,或者至少是我不想使用的最后一个选择... “setColor()”很有趣,但它会影响整个“纹理”吗? - Robert P
1
它将影响整个贴图,但黑色将保持不变,而白色将变为批次的颜色。您不应该使用任何其他颜色,因为那些颜色会被混合在一起看起来很奇怪。 - noone
@noone 但最终结果应该是一个带有彩色T恤的“Player”(类比人类)。所以使用“setColor”方法无法实现这一点吗? - Robert P

4
我遇到了同样的问题,即使用相同的纹理生成随机颜色的武器。
所以我写了这个。基本上,我制作了一个要编辑的纹理的像素图。
然后你遍历所有的像素,同时检查某些颜色是否是纹理的特定部分。(我建议使用不同的灰度值,因为RGB是相同的)
当它在需要改变颜色的像素上时,我使用一个颜色选择器方法来获取那些像素组的颜色,这个方法基本上是随机的,从一个预制的颜色数组中获取颜色,然后将特定的像素更改为新的颜色。
/**
 * Requires a asset's textureName, and requires gray scale colors of the
 * parts
 * 
 * @param texturename
 * @param colorBlade
 * @param colorEdge
 * @param colorAffinity
 * @param colorGrip
 * @return
 */
private static Texture genTexture(String texturename, int colorBlade,
        int colorEdge, int colorAffinity, int colorGrip, int colorExtra) {
    Texture tex = Game.res.getTexture(texturename);

    TextureData textureData = tex.getTextureData();
    textureData.prepare();

    Color tintBlade = chooseColor(mainColors);
    Color tintEdge = new Color(tintBlade.r + 0.1f, tintBlade.g + 0.1f,
            tintBlade.b + 0.1f, 1);

    Color tintAffinity = chooseColor(affinityColors);
    Color tintGrip;
    Color tintExtra = chooseColor(extraColors);

    boolean colorsAreSet = false;

    do {
        tintGrip = chooseColor(mainColors);

        if (tintAffinity != tintBlade && tintAffinity != tintGrip
                && tintGrip != tintBlade) {
            colorsAreSet = true;
        }
    } while (!colorsAreSet);

    Pixmap pixmap = tex.getTextureData().consumePixmap();

    for (int y = 0; y < pixmap.getHeight(); y++) {
        for (int x = 0; x < pixmap.getWidth(); x++) {

            Color color = new Color();
            Color.rgba8888ToColor(color, pixmap.getPixel(x, y));
            int colorInt[] = getColorFromHex(color);

            if (colorInt[0] == colorBlade && colorInt[1] == colorBlade
                    && colorInt[2] == colorBlade) {
                pixmap.setColor(tintBlade);
                pixmap.fillRectangle(x, y, 1, 1);
            } else if (colorInt[0] == colorEdge && colorInt[1] == colorEdge
                    && colorInt[2] == colorEdge) {
                pixmap.setColor(tintEdge);
                pixmap.fillRectangle(x, y, 1, 1);
            } else if (colorInt[0] == colorAffinity
                    && colorInt[1] == colorAffinity
                    && colorInt[2] == colorAffinity) {
                pixmap.setColor(tintAffinity);
                pixmap.fillRectangle(x, y, 1, 1);
            } else if (colorInt[0] == colorGrip && colorInt[1] == colorGrip
                    && colorInt[2] == colorGrip) {
                pixmap.setColor(tintGrip);
                pixmap.fillRectangle(x, y, 1, 1);
            }
            else if (colorInt[0] == colorExtra && colorInt[1] == colorExtra
                && colorInt[2] == colorExtra) {
            pixmap.setColor(tintExtra);
            pixmap.fillRectangle(x, y, 1, 1);
            }
        }
    }

    tex = new Texture(pixmap);
    textureData.disposePixmap();
    pixmap.dispose();

    return tex;
}

希望这能有所帮助。
请不要简单地复制粘贴,尽量根据自己的需要重构内容,否则你将无法学到任何东西。


嗨,Rose Blax,感谢您提供的解决方案。这基本上是我想做的事情。但问题在于:这是否会消除“TextureAtlas”的优势,因为您创建了一个新的“Texture”,还是仍然使用“TextureAtlas”? - Robert P
我会说尝试去弄清楚,因为我没有尝试过,所以不知道。 - Maarten
我建议在两个for循环之外只调用一次new Color(),然后在那里设置rgba值。创建实例的计算成本很高,因此在不必要时避免这样做。 - PianoMastR64

2
Rose Blax做得非常好。但是如果你想通过使用SpriteBatch或者对于那些有相同问题但不想使用Pixmap的人来说,这里有一个方法...当然我很喜欢使用Pixmap,但是我已经看到使用“spritebatch/sprite.setcolor(r,g,b,a)”会带来一些挑战,因为它会改变所有纹理颜色而不仅仅是T恤...这就是为什么我来到这里,是的,可以使用这种方式仅更改T恤。准备好了吗? :D
1-将要绘制的部分变成灰度或白色 2-在texturepack或不同的纹理中拆分需要绘制的部分:例如T恤,您需要一个包,其中T恤不在角色内...是的,只有头、手臂和腿的人。T-short可以在同一个包中或不在同一个包中。但是保持它们之间的空隙以便未来放置T恤。
它看起来像这样: 查看此资产 不需要害怕。我知道那张图片已经把整个角色分开了,但是如果你只想更改T恤,那么你只需要将其与身体其他部分分开。

3 - 你将绘制它们两个,但不是同一个TextureRegion,你的代码将如下所示:

public void draw(SpriteBatch batch){
        //First we draw the player with a hole in his body
        batch.draw(playerA,0,0,75,100);
        //Here we set the color of next texture to be drawn as RED.
        batch.setColor(Color.RED);
        //Now we draw the t-shirt of the player in same x and half y.
        //That t-short has to be drawn in right position. That's why calc it.
        batch.draw(tshirtA, 0,50,50);
        //For don't affect others textures then make it white back.
        batch.setColor(Color.WHITE);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接