blog

Android ゲームエンジン libgdx 使い方チュートリアル 5: 一般的な UI クラスとステージ

ボタン、ドロップダウン、リスト、ラベル、イメージ、チェックボックス、エディットボックス、スプリットパネル、スライドパネル、スライダーといったものは、よく使われるUIクラスで、ステージの管理に簡単に取り...

Jun 30, 2025 · 17 min. read
シェア

ボタン、ドロップダウンボックス、リスト、ラベル、イメージ、チェックボックス、エディットボックス、スプリットパネル、スライドパネル、スライダーなどのようなものは、ステージの管理に簡単に組み込むことができるActorに属し、com.badlogic.gdx.scenes.scene2d.uiパッケージに含まれる、より一般的に使用されるUIクラスの一部です。

実際には、UIクラスのコードの実装を詳しく見てみると、彼らは実際にはほとんどWidgetまたはテーブルから継承され、UIをカスタマイズする必要がある場合は、上記の2つのクラスから継承することができます見つけることは困難ではありませんが、ここでTWLの使用のlibgdx部分のレイアウトを説明するために、興味のある友人が見に行くことができます。

各コントロールを紹介する前に、最近の重要なアップデートの一つであるNinePatchを見てみましょう。

NinePatchとは?実は、androidにはネイティブのNinePatchクラスがあり、ボタンでよく使われています。

図のように、イメージを9分割します。真ん中の部分は必要に応じて拡大することができるので、ボタン内容の変更の大きさがイメージによって制限されることはありません。

そして libgdx の NinePatch は実際には 9 つの TextureRegion オブジェクトです。

よく使われるインスタンス化の方法は2つあります:

パブリックナインパッチ

パブリックナインパッチ

public NinePatch (TextureRegion region, int left, int right, int top, int bottom) {     
int middleWidth = region.getRegionWidth() - left - right;     
int middleHeight = region.getRegionHeight() - top - bottom;     
this.patches = new TextureRegion[] {new TextureRegion(region, 0, 0, left, top),     
new TextureRegion(region, left, 0, middleWidth, top), new TextureRegion(region, left + middleWidth, 0, right, top),     
new TextureRegion(region, 0, top, left, middleHeight), new TextureRegion(region, left, top, middleWidth, middleHeight),     
new TextureRegion(region, left + middleWidth, top, right, middleHeight),     
new TextureRegion(region, 0, top + middleHeight, left, bottom),     
new TextureRegion(region, left, top + middleHeight, middleWidth, bottom),     
new TextureRegion(region, left + middleWidth, top + middleHeight, right, bottom)};     
}   

まず中央部分の幅と高さを計算します。まず一番左の1番を切り、その右の1番を切り、さらにその右の1番を切ります。

一番上の列、真ん中の列、一番下の列。

上から下へ、左から右へ。

また、描画時にはどのように処理されるのでしょうか?ソースコードを見てください:

public void draw (SpriteBatch batch, float x, float y, float width, float height) {     
float centerColumnX = x;     
if (patches[BOTTOM_LEFT] != null)     
centerColumnX += patches[BOTTOM_LEFT].getRegionWidth();     
else if (patches[MIDDLE_LEFT] != null)     
centerColumnX += patches[MIDDLE_LEFT].getRegionWidth();     
else if (patches[TOP_LEFT] != null) //     
centerColumnX += patches[TOP_LEFT].getRegionWidth();     
float rightColumnX = x + width;     
if (patches[BOTTOM_RIGHT] != null)     
rightColumnX -= patches[BOTTOM_RIGHT].getRegionWidth();     
else if (patches[MIDDLE_RIGHT] != null)     
rightColumnX += patches[MIDDLE_RIGHT].getRegionWidth();     
else if (patches[TOP_RIGHT] != null) //     
rightColumnX += patches[TOP_RIGHT].getRegionWidth();     
float middleRowY = y;     
if (patches[TOP_LEFT] != null)     
middleRowY += patches[TOP_LEFT].getRegionHeight();     
else if (patches[TOP_CENTER] != null)     
middleRowY += patches[TOP_CENTER].getRegionHeight();     
else if (patches[TOP_RIGHT] != null) //     
middleRowY += patches[TOP_RIGHT].getRegionHeight();     
float topRowY = y + height;     
if (patches[TOP_LEFT] != null)     
topRowY -= patches[TOP_LEFT].getRegionHeight();     
else if (patches[TOP_CENTER] != null)     
topRowY -= patches[TOP_CENTER].getRegionHeight();     
else if (patches[TOP_RIGHT] != null) //     
topRowY -= patches[TOP_RIGHT].getRegionHeight();     
// Bottom row     
if (patches[BOTTOM_LEFT] != null) batch.draw(patches[BOTTOM_LEFT], x, y, centerColumnX - x, middleRowY - y);     
if (patches[BOTTOM_CENTER] != null)     
batch.draw(patches[BOTTOM_CENTER], centerColumnX, y, rightColumnX - centerColumnX, middleRowY - y);     
if (patches[BOTTOM_RIGHT] != null)     
batch.draw(patches[BOTTOM_RIGHT], rightColumnX, y, x + width - rightColumnX, middleRowY - y);     
// Middle row     
if (patches[MIDDLE_LEFT] != null) batch.draw(patches[MIDDLE_LEFT], x, middleRowY, centerColumnX - x, topRowY - middleRowY);     
if (patches[MIDDLE_CENTER] != null)     
batch.draw(patches[MIDDLE_CENTER], centerColumnX, middleRowY, rightColumnX - centerColumnX, topRowY - middleRowY);     
if (patches[MIDDLE_RIGHT] != null)     
batch.draw(patches[MIDDLE_RIGHT], rightColumnX, middleRowY, x + width - rightColumnX, topRowY - middleRowY);     
// Top row     
if (patches[TOP_LEFT] != null) batch.draw(patches[TOP_LEFT], x, topRowY, centerColumnX - x, y + height - topRowY);     
if (patches[TOP_CENTER] != null)     
batch.draw(patches[TOP_CENTER], centerColumnX, topRowY, rightColumnX - centerColumnX, y + height - topRowY);     
if (patches[TOP_RIGHT] != null)     
batch.draw(patches[TOP_RIGHT], rightColumnX, topRowY, x + width - rightColumnX, y + height - topRowY);     
}   

まず左右の列の幅を計算し、中央と上部の高さを計算します。それから下から上へ描画します。正直、このコードは見ていて楽しいと思います。

それでは、いくつかの一般的なコントロールの使い方を説明します。まずステージを作ります。

labelはキャッシュされているので、setTextメソッドではなく、setWrappedTextメソッドで表示内容を置き換えます。

コードは以下の通り:

package comblogs.htynkn.listener;     
import com.badlogic.gdx.ApplicationListener;     
import com.badlogic.gdx.Gdx;     
import com.badlogic.gdx.graphics.GL10;     
import com.badlogic.gdx.graphics.g2d.BitmapFont;     
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;     
import com.badlogic.gdx.scenes.scene2d.Stage;     
import com.badlogic.gdx.scenes.scene2d.actors.Label;     
public class FirstGame implements ApplicationListener {     
private Stage stage;     
Label label;     
@Override     
public void create() {     
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),     
true);     
label = new Label("fpsLabel", new BitmapFont(Gdx.files.internal("cf.fnt"),Gdx.files.internal("cf.png"),false), "label1");     
label.x=5;     
label.y=Gdx.graphics.getHeight()-label.height-5;     
stage.addActor(label);     
Gdx.input.setInputProcessor(stage);     
}     
@Override     
public void dispose() {     
stage.dispose();     
}     
@Override     
public void pause() {     
// TODO Auto-generated method stub     
}     
@Override     
public void render() {     
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);     
label.setWrappedText("FPS: "+Gdx.graphics.getFramesPerSecond(),     
HAlignment.CENTER);     
stage.act(Gdx.graphics.getDeltaTime());     
stage.draw();     
}     
@Override     
public void resize(int width, int height) {     
// TODO Auto-generated method stub     
}     
@Override     
public void resume() {     
// TODO Auto-generated method stub     
}     
}   

効果

ボタンの3つの状態のイメージを保存して、1つのイメージだけにします。

以下のようにコードを修正してください:

package comblogs.htynkn.listener;     
import com.badlogic.gdx.ApplicationListener;     
import com.badlogic.gdx.Gdx;     
import com.badlogic.gdx.graphics.Color;     
import com.badlogic.gdx.graphics.GL10;     
import com.badlogic.gdx.graphics.Texture;     
import com.badlogic.gdx.graphics.g2d.BitmapFont;     
import com.badlogic.gdx.graphics.g2d.NinePatch;     
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;     
import com.badlogic.gdx.scenes.scene2d.Stage;     
import com.badlogic.gdx.scenes.scene2d.actors.Label;     
import com.badlogic.gdx.scenes.scene2d.ui.Button;     
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;     
public class FirstGame implements ApplicationListener {     
private Stage stage;     
Label label;     
Texture texture;     
Button button;     
@Override     
public void create() {     
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),     
true);     
texture = new Texture(Gdx.files.internal("06.png"));     
NinePatch n1 = new NinePatch(texture, 7, 7, 9, 9);     
BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),     
Gdx.files.internal("cf.png"), false);     
label = new Label("fpsLabel", bitmapFont, "label1");     
label.x = 5;     
label.y = Gdx.graphics.getHeight() - label.height - 5;     
stage.addActor(label);     
button = new Button("button", new ButtonStyle(n1, n1, n1, 0f, 0f, 0f,     
0f, bitmapFont, new Color(1, 1, 0, 0.5f)), "button");     
button.x=10;     
button.y=10;     
button.width=100f;     
button.height=32f;     
stage.addActor(button);     
Gdx.input.setInputProcessor(stage);     
}     
@Override     
public void dispose() {     
stage.dispose();     
}     
@Override     
public void pause() {     
// TODO Auto-generated method stub     
}     
@Override     
public void render() {     
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);     
label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),     
HAlignment.CENTER);     
stage.act(Gdx.graphics.getDeltaTime());     
stage.draw();     
}     
@Override     
public void resize(int width, int height) {     
// TODO Auto-generated method stub     
}     
@Override     
public void resume() {     
// TODO Auto-generated method stub     
}     
}   

効果

ボタンには当然クリックイベントが必要で、setClickListenerで設定します:

button.setClickListener(new ClickListener() {     
@Override     
public void click(Actor actor) {     
Gdx.app.log("Info", "クリックイベントをトリガーする");     
}     
});   

CheckBoxのスタイルはCheckBoxStyleで定義され、4つのパラメータ、2つの状態のそれぞれのイメージ、BitmapFontとColourを取ります。

ここでもう一枚イメージを追加します:

原理はほとんど同じなので、コードだけ載せておきます。

package comblogs.htynkn.listener;     
import android.graphics.Paint.Align;     
import com.badlogic.gdx.ApplicationListener;     
import com.badlogic.gdx.Gdx;     
import com.badlogic.gdx.graphics.Color;     
import com.badlogic.gdx.graphics.GL10;     
import com.badlogic.gdx.graphics.Texture;     
import com.badlogic.gdx.graphics.g2d.BitmapFont;     
import com.badlogic.gdx.graphics.g2d.NinePatch;     
import com.badlogic.gdx.graphics.g2d.TextureRegion;     
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;     
import com.badlogic.gdx.scenes.scene2d.Actor;     
import com.badlogic.gdx.scenes.scene2d.Stage;     
import com.badlogic.gdx.scenes.scene2d.actors.Label;     
import com.badlogic.gdx.scenes.scene2d.ui.Button;     
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;     
import com.badlogic.gdx.scenes.scene2d.ui.ClickListener;     
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;     
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle;     
public class FirstGame implements ApplicationListener {     
private Stage stage;     
Label label;     
Texture texture1;     
Texture texture2;     
CheckBox checkBox;     
@Override     
public void create() {     
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),     
true);     
texture1 = new Texture(Gdx.files.internal("06.png"));     
texture2 = new Texture(Gdx.files.internal("07.png"));     
NinePatch n1 = new NinePatch(texture1, 7, 7, 9, 9);     
BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),     
Gdx.files.internal("cf.png"), false);     
label = new Label("fpsLabel", bitmapFont, "label1");     
label.x = 5;     
label.y = Gdx.graphics.getHeight() - label.height - 5;     
CheckBoxStyle style = new CheckBoxStyle(new TextureRegion(texture1),     
new TextureRegion(texture2), bitmapFont, new Color(1, 1, 1,     
0.5f));     
checkBox = new CheckBox("checkbox", style, "checkbox");     
checkBox.x = 100;     
checkBox.y = 100;     
checkBox.width = 158f;     
checkBox.height = 32f;     
checkBox.setText("Yes");     
checkBox.setClickListener(new ClickListener() {     
@Override     
public void click(Actor actor) {     
if (checkBox.isChecked) {     
checkBox.setText("Yes");     
} else {     
checkBox.setText("NO");     
}     
}     
});     
stage.addActor(checkBox);     
stage.addActor(label);     
Gdx.input.setInputProcessor(stage);     
}     
@Override     
public void dispose() {     
stage.dispose();     
}     
@Override     
public void pause() {     
// TODO Auto-generated method stub     
}     
@Override     
public void render() {     
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);     
label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),     
HAlignment.CENTER);     
stage.act(Gdx.graphics.getDeltaTime());     
stage.draw();     
}     
@Override     
public void resize(int width, int height) {     
// TODO Auto-generated method stub     
}     
@Override     
public void resume() {     
// TODO Auto-generated method stub     
}     
}   

効果

UIの残りの部分はほぼ同じで、表示スタイルは対応するStyleまたはSkinで定義されます。ただし、いくつかの UI クラスでは幅と高さを手動で設定する必要があります

スライダーの使い方

SliderStyleにはNinePathとTextureが必要ですが、なぜNinePathが2つないのか最初はわかりませんでしたが、ソースコードをよく見てみると、NinePathは背景として使われ、Textureはスライドする正方形の真ん中であることがわかりました。

設定ファイルによるStyleの設定については、google code wikiには書かれていないようですが、libgdxのフォーラムなどには書かれています:

somePatch1: [    
{ height: 13, width: 9, x: 761, y: 78 },    
{ height: 13, width: 1, x: 770, y: 78 },    
{ height: 13, width: 9, x: 771, y: 78 },    
{ height: 1, width: 9, x: 761, y: 91 },    
{ height: 1, width: 1, x: 770, y: 91 },    
{ height: 1, width: 9, x: 771, y: 91 },    
{ height: 13, width: 9, x: 761, y: 92 },    
{ height: 13, width: 1, x: 770, y: 92 },    
{ height: 13, width: 9, x: 771, y: 92 }    
]   

または

somePatch2: [    
{ height: 13, width: 9, x: 761, y: 78 },    
]   
Read next

ストレージ変更IBM V5000の4つの利点は、古い新しいを破るためにユーザーを支援する

ミッドレンジのストレージ市場に直面して、IBM Storwize V5000は間違いなく画期的な選択肢です。柔軟性が高く、管理が容易で、あらゆるネットワーク環境、クラスタ拡張、仮想化管理に互換性と適応性があります。企業のパフォーマンスとコストの要件を満たすと同時に、柔軟な展開と水平展開という成長企業のニーズにも応えます。

Jun 30, 2025 · 4 min read