如何创建一个内部包含多个多边形可绘制对象的按钮(在 LibGDX 中)

How to create a button with several polygon drawables inside (in LibGDX)

是否有一些简单的方法可以在 LibGDX 中创建一个 Button,其中包含多个多边形可绘制对象。

例如,当简单的 Button 可以描绘成这样时:

和像这样的高级预期按钮:

在我的例子中,必须满足以下条件:

  1. 对象必须扩展 Button class.
  2. 分离的多边形(图中的圆形和三角形)必须具有一种共同的行为 - 相同的向上、向下、悬停样式、相同的点击侦听器等。 (例如,当用户将鼠标悬停在圆圈上时,三角形和圆圈的颜色会变为绿色)

实际上它必须与具有一个多边形的按钮具有完全相同的行为,想象一下圆形和三角形是一个多边形,而不是分开的。

我想到的一种方法是扩展 PolygonRegionDrawable, but to make it drawn correctly I need to override almost all methods from Drawable and TransformDrawable,有更简单的方法吗?

也许可以找到一些 DrawableGroup 或类似的东西?

我认为没有简单的方法可以完成这项工作,这里有一些选择。

Button是一个Table,你可以往里面加东西。

Button button = new Button(skin);
Image img = new Image(...); // insert polygon 1 here
img.setPostion(...); // offset so its in correct position in the button
button.addActor(img);
// add more stuff

遗憾的是,这无法处理各种状态更改,例如结束等。您需要跟踪添加的内容并在按钮更改时更改它们。

另一种选择是将多边形制作成单个图像。 这非常棘手,你会在正确的位置将它们绘制到 FrameBufferObject 中,并从中制作纹理。然后将该纹理用于 Drawable 作为按钮样式。重复您要处理的每个状态。出于性能原因,将它们打包到 atlas 中是最佳选择。大量的纹理切换不是很好。

为了实现这样的功能,我已经实现了两个额外的 classes,它们可以假定一个 Drawables 列表来像只绘制一个一样绘制它。

所以我只是在这里提一下,希望对想要实现相同行为的人有用。

一个抽象 class 假定可绘制对象列表和相关坐标格式:

[drawable1X, drawable1Y, drawable2X, drawable2Y, ..., drawableNX, drawableNY] 

BulkBaseDrawable:

abstract class BulkBaseDrawable implements Drawable {

    Array<Drawable> drawables;
    private float leftWidth, rightWidth, topHeight, bottomHeight, minWidth, minHeight, leftX, bottomY, rightX, topY;

    BulkBaseDrawable(Drawable[] drawables,
                     float... vertices) {
        this.infos = new Array<>(drawables.length);
        init(drawables, vertices);
    }

    @Override
    public float getLeftWidth() {
        return leftWidth;
    }

    @Override
    public void setLeftWidth(float leftWidth) {
        this.leftWidth = leftWidth;
    }

    @Override
    public float getRightWidth() {
        return rightWidth;
    }

    @Override
    public void setRightWidth(float rightWidth) {
        this.rightWidth = rightWidth;
    }

    @Override
    public float getTopHeight() {
        return topHeight;
    }

    @Override
    public void setTopHeight(float topHeight) {
        this.topHeight = topHeight;
    }

    @Override
    public float getBottomHeight() {
        return bottomHeight;
    }

    @Override
    public void setBottomHeight(float bottomHeight) {
        this.bottomHeight = bottomHeight;
    }

    @Override
    public float getMinWidth() {
        return minWidth;
    }

    @Override
    public void setMinWidth(float minWidth) {
        this.minWidth = minWidth;
    }

    @Override
    public float getMinHeight() {
        return minHeight;
    }

    @Override
    public void setMinHeight(float minHeight) {
        this.minHeight = minHeight;
    }

    void init(Drawable[] drawables, float[] vertices) {
        initInfo(drawables, vertices);
        initEdges();
        initSize();
    }

    private void initInfo(Drawable[] drawables, float[] vertices) {
        int i = 0;
        for (Drawable drawable : drawables) {
            infos.add(Info.builder()
                    .x(vertices[i])
                    .y(vertices[i + 1])
                    .width(drawable.getMinWidth())
                    .height(drawable.getMinHeight())
                    .drawable(drawable)
                    .build());
            i += 2;
        }
    }

    private void initSize() {
        minHeight = topY - bottomY;
        minWidth = rightX - leftX;
    }

    private void initEdges() {
        topY = Float.MIN_VALUE;
        rightX = Float.MIN_VALUE;
        bottomY = Float.MAX_VALUE;
        leftX = Float.MAX_VALUE;
        int topI = 0;
        int rightI = 0;
        int bottomI = 0;
        int leftI = 0;
        for (int i = 0; i < infos.size; i++) {
            Info info = infos.get(i);
            if (info.y + info.height > topY) {
                topY = info.y + info.height;
                topI = i;
            }
            if (info.x + info.width > rightX) {
                rightX = info.x + info.width;
                rightI = i;
            }
            if (info.y < bottomY) {
                bottomY = info.y;
                bottomI = i;
            }
            if (info.x < leftX) {
                leftX = info.x;
                leftI = i;
            }
        }
        Drawable top = infos.get(topI).drawable;
        Drawable right = infos.get(rightI).drawable;
        Drawable bottom = infos.get(bottomI).drawable;
        Drawable left = infos.get(leftI).drawable;
        leftWidth = left.getLeftWidth();
        rightWidth = right.getRightWidth();
        topHeight = top.getTopHeight();
        bottomHeight = bottom.getBottomHeight();
    }

    static class Info {

        float x, y, width, height;
        Drawable drawable;

        static InfoBuilder builder() {
            return new InfoBuilder();
        }

        static class InfoBuilder {

            float x, y, width, height;
            Drawable drawable;

            InfoBuilder x(float x) {
                this.x = x;
                return this;
            }

            InfoBuilder y(float y) {
                this.y = y;
                return this;
            }

            InfoBuilder width(float width) {
                this.width = width;
                return this;
            }

            InfoBuilder height(float height) {
                this.height = height;
                return this;
            }

            InfoBuilder drawable(Drawable drawable) {
                this.drawable = drawable;
                return this;
            }

            Info build() {
                return new Info(x, y, width, height, drawable);
            }
        }

        public Info(float x, float y, float width, float height, Drawable drawable) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.drawable = drawable;
        }
    }
}

实际实现BulkRegionDrawable:

public class BulkRegionDrawable extends BulkBaseDrawable {

    public BulkRegionDrawable(Drawable[] drawables, float[] vertices) {
        super(drawables, vertices);
    }

    @Override
    public void draw(Batch batch,
                     float x,
                     float y,
                     float width,
                     float height) {
        for (int i = 0; i < infos.size; i++) {
            Info info = infos.get(i);
            float yK = info.height / getMinHeight();
            float xK = info.width / getMinWidth();
            info.drawable.draw(
                    batch,
                    x + (info.x * width) / getMinWidth(),
                    y + (info.y * height) / getMinHeight(),
                    width * xK,
                    height * yK);
        }
    }
}