[解決済み] JavaFXのKeyListenerの書き方
質問
JavaFXパネル上でボールを動かすゲームを作りたいのですが、そのために
W
,
A
,
S
,
D
キーになります。
私の場合は
getPosX()
と
setPosX()
を書きたいのですが、どう書けばいいのかわかりません。
KeyListener
を計算するようなものです。
setPosX(getPosX()+1)
を押すと
D
.
どうすればいいんだ?
どのように解決するのですか?
からの JavaRanch フォーラムの投稿 .
キーを押したり離したりするハンドラをシーン上に追加し、アプリケーションに記録されている動作状態の変数を更新します。 アニメーション・タイマーは、JavaFX のパルス・メカニズム(デフォルトでは、1秒間に 60 回のイベントを発生させる上限があります)にフックしているので、一種のゲーム・ループと言えます。 タイマーの中では、動作状態の変数がチェックされ、そのデルタアクションがキャラクターの位置に適用されます。
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Hold down an arrow key to have your hero move around the screen.
* Hold down the shift key to have the hero run.
*/
public class Runner extends Application {
private static final double W = 600, H = 400;
private static final String HERO_IMAGE_LOC =
"http://icons.iconarchive.com/icons/raindropmemory/legendora/64/Hero-icon.png";
private Image heroImage;
private Node hero;
boolean running, goNorth, goSouth, goEast, goWest;
@Override
public void start(Stage stage) throws Exception {
heroImage = new Image(HERO_IMAGE_LOC);
hero = new ImageView(heroImage);
Group dungeon = new Group(hero);
moveHeroTo(W / 2, H / 2);
Scene scene = new Scene(dungeon, W, H, Color.FORESTGREEN);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP: goNorth = true; break;
case DOWN: goSouth = true; break;
case LEFT: goWest = true; break;
case RIGHT: goEast = true; break;
case SHIFT: running = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP: goNorth = false; break;
case DOWN: goSouth = false; break;
case LEFT: goWest = false; break;
case RIGHT: goEast = false; break;
case SHIFT: running = false; break;
}
}
});
stage.setScene(scene);
stage.show();
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
int dx = 0, dy = 0;
if (goNorth) dy -= 1;
if (goSouth) dy += 1;
if (goEast) dx += 1;
if (goWest) dx -= 1;
if (running) { dx *= 3; dy *= 3; }
moveHeroBy(dx, dy);
}
};
timer.start();
}
private void moveHeroBy(int dx, int dy) {
if (dx == 0 && dy == 0) return;
final double cx = hero.getBoundsInLocal().getWidth() / 2;
final double cy = hero.getBoundsInLocal().getHeight() / 2;
double x = cx + hero.getLayoutX() + dx;
double y = cy + hero.getLayoutY() + dy;
moveHeroTo(x, y);
}
private void moveHeroTo(double x, double y) {
final double cx = hero.getBoundsInLocal().getWidth() / 2;
final double cy = hero.getBoundsInLocal().getHeight() / 2;
if (x - cx >= 0 &&
x + cx <= W &&
y - cy >= 0 &&
y + cy <= H) {
hero.relocate(x - cx, y - cy);
}
}
public static void main(String[] args) { launch(args); }
}
すでに提供されている情報で十分な場合は、この回答の残りの部分を無視してください。
この質問に対する答えは上記のソリューションで十分ですが、もし興味があれば、より洗練された入力ハンドラ(より一般的で分離された、入力と更新の処理ロジック)を、このデモのブレイクアウトゲームで見ることができます。
サンプルブレイクアウトゲームの汎用入力ハンドラの例。
class InputHandler implements EventHandler<KeyEvent> {
final private Set<KeyCode> activeKeys = new HashSet<>();
@Override
public void handle(KeyEvent event) {
if (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
activeKeys.add(event.getCode());
} else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
activeKeys.remove(event.getCode());
}
}
public Set<KeyCode> getActiveKeys() {
return Collections.unmodifiableSet(activeKeys);
}
}
一方
ObservableSet
アクティブなキーのセットには、適切なセット変更リスナーを使用することもできますが、私は、スナップショットでアクティブだったキーの変更不可能なセットを返すアクセサを使用しました。
汎用インプットハンドラの使用例。
Scene gameScene = createGameScene();
// register the input handler to the game scene.
InputHandler inputHandler = new InputHandler();
gameScene.setOnKeyPressed(inputHandler);
gameScene.setOnKeyReleased(inputHandler);
gameLoop = createGameLoop();
// . . .
private AnimationTimer createGameLoop() {
return new AnimationTimer() {
public void handle(long now) {
update(now, inputHandler.getActiveKeys());
if (gameState.isGameOver()) {
this.stop();
}
}
};
}
public void update(long now, Set<KeyCode> activeKeys) {
applyInputToPaddle(activeKeys);
// . . . rest of logic to update game state and view.
}
// The paddle is sprite implementation with
// an in-built velocity setting that is used to
// update its position for each frame.
//
// on user input, The paddle velocity changes
// to point in the correct predefined direction.
private void applyInputToPaddle(Set<KeyCode> activeKeys) {
Point2D paddleVelocity = Point2D.ZERO;
if (activeKeys.contains(KeyCode.LEFT)) {
paddleVelocity = paddleVelocity.add(paddleLeftVelocity);
}
if (activeKeys.contains(KeyCode.RIGHT)) {
paddleVelocity = paddleVelocity.add(paddleRightVelocity);
}
gameState.getPaddle().setVelocity(paddleVelocity);
}
関連
-
[解決済み] JavaFX 8の背景色に関する問題
-
[解決済み] JavaFX: キャンバスをクリアする方法
-
[解決済み] JavaFX: 初期化中にコントローラからステージを取得する方法は?
-
[解決済み] javafxでsetOnActionイベントを使用する方法
-
[解決済み] JavaFXです。ChangeListenerの実行
-
[解決済み] JavaFXによるGridPane内のラベルの整列
-
[解決済み] JavaFX Stage/Sceneの自動リサイズ
-
[解決済み] JavaFXのKeyListenerの書き方
-
[解決済み] Java 8 List<V> を Map<K, V> に変換する。
-
[解決済み】 パラメータの受け渡し JavaFX FXML
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン