如何创建一个内部包含多个多边形可绘制对象的按钮(在 LibGDX 中)
How to create a button with several polygon drawables inside (in LibGDX)
是否有一些简单的方法可以在 LibGDX 中创建一个 Button,其中包含多个多边形可绘制对象。
例如,当简单的 Button 可以描绘成这样时:
和像这样的高级预期按钮:
在我的例子中,必须满足以下条件:
- 对象必须扩展 Button class.
- 分离的多边形(图中的圆形和三角形)必须具有一种共同的行为 - 相同的向上、向下、悬停样式、相同的点击侦听器等。 (例如,当用户将鼠标悬停在圆圈上时,三角形和圆圈的颜色会变为绿色)
实际上它必须与具有一个多边形的按钮具有完全相同的行为,想象一下圆形和三角形是一个多边形,而不是分开的。
我想到的一种方法是扩展 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);
}
}
}
是否有一些简单的方法可以在 LibGDX 中创建一个 Button,其中包含多个多边形可绘制对象。
例如,当简单的 Button 可以描绘成这样时:
和像这样的高级预期按钮:
在我的例子中,必须满足以下条件:
- 对象必须扩展 Button class.
- 分离的多边形(图中的圆形和三角形)必须具有一种共同的行为 - 相同的向上、向下、悬停样式、相同的点击侦听器等。 (例如,当用户将鼠标悬停在圆圈上时,三角形和圆圈的颜色会变为绿色)
实际上它必须与具有一个多边形的按钮具有完全相同的行为,想象一下圆形和三角形是一个多边形,而不是分开的。
我想到的一种方法是扩展 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);
}
}
}