Snehの応答は、すべてのボタンに対して別々のクラスを作成する代わりに、ボタンを作成したときに毎回座標とact()メソッドを指定するたびに匿名の内部クラスを使用することができました。私はこれを行うための可能な短い方法としてラムダ構文を調べましたが、それには限界がありました。私は柔軟な解決策に終わったが、私のニーズに合わせてそれをさらに減らした。両方の方法を以下に示します。
私のゲーム内の各ゲーム画面は、ボタンなどのHashMapを持つ、LibGDXのScreen
を拡張しますが、サイズ変更のビューポートを更新するように普遍的な機能を追加しMyScreen
クラスからサブクラス化され私はMyScreen
クラスにbuttonPressed()
メソッドを追加しました。このメソッドは、1つのパラメータとしてenumを取ります。私は可能なすべてのボタン(MAINMENU_PLAY、MAINMENU_MAPDESIGNERなど)を含むButtonValues
enumを持っています。各ゲーム画面では、buttonPressed()
がオーバーライドされ、スイッチが正しいアクションを実行するために使用される:
public void buttonPressed(ButtonValues b) {
switch(b) {
case MAINMENU_PLAY:
beginGame();
case MAINMENU_MAPDESIGNER:
switchToMapDesigner();
}
}
ではなくbuttonPressed()
を必要とする、独自にアクションを実行できるように、他のソリューションは、ボタン・ストアにラムダ式を有しますどのボタンが押されたかに基づいて正しいアクションを実行する仲介者として働くことができます。
ボタンを追加するには、それはその座標とタイプ(列挙型)で作成され、ボタンのHashMapのに追加されます。
Button b = new Button(this,
new Rectangle(300 - t.getRegionWidth()/2, 1.9f * 60, t.getRegionWidth(), t.getRegionHeight()),
tex, ButtonValues.MAINMENU_PLAY);
buttons.put("buttonPlay", b);
、ちょうどbuttons.remove("buttonPlay").
それを削除するには、それが画面から消えますゲームによって忘れられてしまいます。
引数はゲーム画面でbuttonPressed()
を呼び出すことができるので、ボタンを所有するゲーム画面、座標を持つ矩形、テクスチャ(描画に使用する)、および列挙値です。そのポイントは、ボタンの中に含まれているかどうかを
public class Button {
public Rectangle r;
public TextureRegion image;
private MyScreen screen;
private ButtonValues b;
public Button(MyScreen screen, Rectangle r, TextureRegion image, ButtonValues b) {
this.screen = screen;
this.r = r;
this.image = image;
this.b = b;
}
public void act() {
screen.buttonPressed(b);
}
public boolean isClicked(float x, float y) {
return x > r.x && y > r.y && x < r.x + r.width && y < r.y + r.height;
}
}
isClicked()
だけの(x、y)の中に取り込み、チェック:
そしてここでは、Buttonクラスです。マウスをクリックすると、すべてのボタンを繰り返して、isClicked
の場合はact()
に電話します。
私が行った2番目の方法は、ButtonValues列挙型の代わりにラムダ式を使用して同様でした。 Buttonクラス似ていますが、これらの変化と(それが聞こえるよりもずっと簡単です):
フィールドButtonValues b
はRunnable r
に置き換えられ、これは、コンストラクタから削除されます。追加されたsetAction()
メソッドは、Runnable
を受け取り、r
を渡されたRunnableに設定します。 act()
の方法はちょうどr.run()
です。例:
public class Button {
[Rectangle, Texture, Screen]
Runnable r;
public Button(screen, rectangle, texture) {...}
public void setAction(Runnable r) { this.r = r; }
public void act() { r.run(); }
}
ボタンを作成するには、私は次のようにします。
Button b = new Button(this,
new Rectangle(300 - t.getRegionWidth()/2, 1.9f * 60, t.getRegionWidth(), t.getRegionHeight()),
tex);
b.setAction(() -> b.screen.doSomething());
buttons.put("buttonPlay", b);
まず、ボタンはそれを含むゲーム画面クラス、そのバウンディングボックス、およびそのテクスチャを使用して作成されます。次に、2番目のコマンドで、私はそのアクションを設定します - この場合、b.screen.doSomething();.この時点でbとb.screenは存在しないため、コンストラクタに渡すことはできません。 setAction()
はRunnable
で、act()
が呼び出されたときに呼び出されるButton
のRunnableに設定されます。しかし、Runnable
はラムダ構文で作成できるので、匿名のRunnable
クラスを作成する必要はなく、実行する関数を渡すことができます。
この方法では、柔軟性は大幅に向上しますが、1つの注意点があります。 Button
のscreen
フィールドには、すべてのゲーム画面が拡張されるベース画面クラスであるMyScreen
が格納されています。ボタンの機能は、MyScreen
クラスの一部であるメソッドを使用することができます(buttonPressed()
をMyScreen
にして、ラムダ式を完全に取り除くことができたことがわかりました)。明らかな解決策は、screen
フィールドをキャストすることですが、私にとってはbuttonPressed()
メソッドを使用するだけでは余分なコードを書く価値はありませんでした。
私は(MyScreen
を拡張する)私のMainMenuScreen
クラスでbeginGame()
メソッドを持っていた場合、ボタンに渡されたラムダ式は、MainMenuScreen
にキャストを関与させる必要があります。残念ながら
b.setAction(() -> ((MainMenuScreen) b.screen).beginGame());
、でもワイルドカード構文は」doesnのここで助けてください。
そして最後に、完全性のために、ボタンを操作するゲームループ内のコード:ヘルパークラスに位置してそれらを描画する
public abstract class MyScreen implements Screen {
protected HashMap<String, Button> buttons; // initialize this in the constructor
// this is called in every game screen's game loop
protected void handleInput() {
if (Gdx.input.justTouched()) {
Vector2 touchCoords = new Vector2(Gdx.input.getX(), Gdx.input.getY());
g.viewport.unproject(touchCoords);
for (HashMap.Entry<String, Button> b : buttons.entrySet()) {
if (b.getValue().isClicked(touchCoords.x, touchCoords.y))
b.getValue().act();
}
}
}
}
そして、:Scene2Dで
public void drawButtons(HashMap<String, Button> buttons) {
for (HashMap.Entry<String, Button> b : buttons.entrySet()) {
sb.draw(b.getValue().image, b.getValue().r.x, b.getValue().r.y);
}
}
見て、それGUIのものを作るためのものです。それを使用するか、ゲームのコンセプトをコピーしてください。 –