在 Javafx 中使用键盘移动两个矩形
Moving Two Rectangles with keyboard in Javafx
我是编程新手,我一直在使用 JavaFX 开发一款两人游戏。一名玩家使用 W/S 移动他的 "paddle",另一名玩家使用 Up/Down 箭头移动他的。我一直遇到的问题是一次只能有一个玩家移动他的球拍。我不知道如何获得它,以便他们每个人都可以同时移动各自的桨。我让一个键盘事件处理程序控制两个桨,我认为这就是问题所在。我制作了两个单独的键盘处理程序,但遇到了另一组问题,我认为是由内置的 setFocusTraversable 方法引起的。我希望我正在尝试做的事情是有道理的。有什么想法吗?
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
public class Game{
Rectangle leftPaddle;
double leftPaddleY = 260;
Rectangle rightPaddle;
double rightPaddleY = 260;
public void createGame(Group gameDisplay){
//creates background
Rectangle background = new Rectangle(0,0,800,600);
background.getStyleClass().add("background");
//draws field lines
Canvas game = new Canvas(800, 600);
GraphicsContext gc = game.getGraphicsContext2D();
gc.setStroke(Paint.valueOf("WHITE"));
gc.setLineWidth(5);
gc.strokeLine(400, 0, 400, 600);
gc.strokeOval(300, 200, 200, 200);
gc.strokeRect(0, 150, 100, 300);
gc.strokeRect(700, 150, 100, 300);
gc.setStroke(Paint.valueOf("BLACK"));
gc.setLineWidth(8);
gc.strokeRect(0, 0, 800, 600);
//creates red paddle
leftPaddle = new Rectangle(30, leftPaddleY, 20, 70);
leftPaddle.setOnKeyPressed(paddleMovement);
leftPaddle.setFocusTraversable(true);
leftPaddle.setFill(Color.RED);
//creates blue paddle
rightPaddle = new Rectangle(750, rightPaddleY, 20, 70);
rightPaddle.setOnKeyPressed(paddleMovement);
rightPaddle.setFocusTraversable(true);
rightPaddle.setFill(Color.BLUE);
gameDisplay.getStylesheets().add(getClass().getResource("GameDisplay.css").toExternalForm());
gameDisplay.getChildren().addAll(background, game, leftPaddle, rightPaddle);
}
public EventHandler<KeyEvent> paddleMovement = new EventHandler<KeyEvent>(){
@Override
public void handle(KeyEvent event) {
//red paddle movement
if(event.getCode().equals(KeyCode.W)){
leftPaddle.setY(leftPaddleY -= 6);
if(leftPaddle.getY() < 0){
leftPaddle.setY(0);
leftPaddleY = 0;
}
}
if(event.getCode().equals(KeyCode.S)){
leftPaddle.setY(leftPaddleY += 6);
if(leftPaddle.getY() < 0){
leftPaddle.setY(0);
leftPaddleY = 0;
}
}
//blue paddle movement
if(event.getCode().equals(KeyCode.UP)){
rightPaddle.setY(rightPaddleY -= 6);
if(rightPaddle.getY() < 0){
rightPaddle.setY(0);
rightPaddleY = 0;
}
}
if(event.getCode().equals(KeyCode.DOWN)){
rightPaddle.setY(rightPaddleY += 6);
if(rightPaddle.getY() < 0){
rightPaddle.setY(0);
rightPaddleY = 0;
}
}
}
};
}
keyPressed
事件只会在最后一个按键按下时重复触发。
要解决此问题,只需 "remember" 每个球拍的所需运动并同时收听 keyReleased
事件。您可以使用 AnimationTimer
来执行动作以每帧执行更新(您也可以使用 Timeline
来更好地控制更新频率)。
此外,我建议对成员变量的可见性进行更多限制,因为通常您不希望其他 classes 能够直接写入您的 class 的字段.我还建议在单个 Node
中处理事件。一次只能有一个 Node
获得焦点,在不同地方处理事件只会导致重复代码。
public class Game {
private Rectangle leftPaddle;
private double leftPaddleY = 260;
private Rectangle rightPaddle;
private double rightPaddleY = 260;
private double leftPaddleDY;
private double rightPaddleDY;
private AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
// update paddle positions
leftPaddleY += leftPaddleDY;
rightPaddleY += rightPaddleDY;
if (leftPaddleY < 0) {
leftPaddleY = 0;
}
if (rightPaddleY < 0) {
rightPaddleY = 0;
}
leftPaddle.setY(leftPaddleY);
rightPaddle.setY(rightPaddleY);
}
};
public void createGame(Group gameDisplay) {
//creates background
Rectangle background = new Rectangle(0, 0, 800, 600);
background.getStyleClass().add("background");
//draws field lines
Canvas game = new Canvas(800, 600);
GraphicsContext gc = game.getGraphicsContext2D();
gc.setStroke(Paint.valueOf("WHITE"));
gc.setLineWidth(5);
gc.strokeLine(400, 0, 400, 600);
gc.strokeOval(300, 200, 200, 200);
gc.strokeRect(0, 150, 100, 300);
gc.strokeRect(700, 150, 100, 300);
gc.setStroke(Paint.valueOf("BLACK"));
gc.setLineWidth(8);
gc.strokeRect(0, 0, 800, 600);
//creates red paddle
leftPaddle = new Rectangle(30, leftPaddleY, 20, 70);
leftPaddle.setFill(Color.RED);
//creates blue paddle
rightPaddle = new Rectangle(750, rightPaddleY, 20, 70);
rightPaddle.setFill(Color.BLUE);
// register event handlers to Canvas
game.setFocusTraversable(true);
game.setOnKeyPressed(keyPressed);
game.setOnKeyReleased(keyReleased);
gameDisplay.getStylesheets().add(getClass().getResource("GameDisplay.css").toExternalForm());
gameDisplay.getChildren().addAll(background, game, leftPaddle, rightPaddle);
// start updates of paddle positions
timer.start();
}
private EventHandler<KeyEvent> keyReleased = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
// set movement to 0, if the released key was responsible for the paddle
switch (event.getCode()) {
case W:
case S:
leftPaddleDY = 0;
break;
case UP:
case DOWN:
rightPaddleDY = 0;
break;
}
}
};
private EventHandler<KeyEvent> keyPressed = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
// start movement according to key pressed
switch (event.getCode()) {
case W:
leftPaddleDY = -6;
break;
case S:
leftPaddleDY = 6;
break;
case UP:
rightPaddleDY = -6;
break;
case DOWN:
rightPaddleDY = 6;
break;
}
}
};
}
我是编程新手,我一直在使用 JavaFX 开发一款两人游戏。一名玩家使用 W/S 移动他的 "paddle",另一名玩家使用 Up/Down 箭头移动他的。我一直遇到的问题是一次只能有一个玩家移动他的球拍。我不知道如何获得它,以便他们每个人都可以同时移动各自的桨。我让一个键盘事件处理程序控制两个桨,我认为这就是问题所在。我制作了两个单独的键盘处理程序,但遇到了另一组问题,我认为是由内置的 setFocusTraversable 方法引起的。我希望我正在尝试做的事情是有道理的。有什么想法吗?
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
public class Game{
Rectangle leftPaddle;
double leftPaddleY = 260;
Rectangle rightPaddle;
double rightPaddleY = 260;
public void createGame(Group gameDisplay){
//creates background
Rectangle background = new Rectangle(0,0,800,600);
background.getStyleClass().add("background");
//draws field lines
Canvas game = new Canvas(800, 600);
GraphicsContext gc = game.getGraphicsContext2D();
gc.setStroke(Paint.valueOf("WHITE"));
gc.setLineWidth(5);
gc.strokeLine(400, 0, 400, 600);
gc.strokeOval(300, 200, 200, 200);
gc.strokeRect(0, 150, 100, 300);
gc.strokeRect(700, 150, 100, 300);
gc.setStroke(Paint.valueOf("BLACK"));
gc.setLineWidth(8);
gc.strokeRect(0, 0, 800, 600);
//creates red paddle
leftPaddle = new Rectangle(30, leftPaddleY, 20, 70);
leftPaddle.setOnKeyPressed(paddleMovement);
leftPaddle.setFocusTraversable(true);
leftPaddle.setFill(Color.RED);
//creates blue paddle
rightPaddle = new Rectangle(750, rightPaddleY, 20, 70);
rightPaddle.setOnKeyPressed(paddleMovement);
rightPaddle.setFocusTraversable(true);
rightPaddle.setFill(Color.BLUE);
gameDisplay.getStylesheets().add(getClass().getResource("GameDisplay.css").toExternalForm());
gameDisplay.getChildren().addAll(background, game, leftPaddle, rightPaddle);
}
public EventHandler<KeyEvent> paddleMovement = new EventHandler<KeyEvent>(){
@Override
public void handle(KeyEvent event) {
//red paddle movement
if(event.getCode().equals(KeyCode.W)){
leftPaddle.setY(leftPaddleY -= 6);
if(leftPaddle.getY() < 0){
leftPaddle.setY(0);
leftPaddleY = 0;
}
}
if(event.getCode().equals(KeyCode.S)){
leftPaddle.setY(leftPaddleY += 6);
if(leftPaddle.getY() < 0){
leftPaddle.setY(0);
leftPaddleY = 0;
}
}
//blue paddle movement
if(event.getCode().equals(KeyCode.UP)){
rightPaddle.setY(rightPaddleY -= 6);
if(rightPaddle.getY() < 0){
rightPaddle.setY(0);
rightPaddleY = 0;
}
}
if(event.getCode().equals(KeyCode.DOWN)){
rightPaddle.setY(rightPaddleY += 6);
if(rightPaddle.getY() < 0){
rightPaddle.setY(0);
rightPaddleY = 0;
}
}
}
};
}
keyPressed
事件只会在最后一个按键按下时重复触发。
要解决此问题,只需 "remember" 每个球拍的所需运动并同时收听 keyReleased
事件。您可以使用 AnimationTimer
来执行动作以每帧执行更新(您也可以使用 Timeline
来更好地控制更新频率)。
此外,我建议对成员变量的可见性进行更多限制,因为通常您不希望其他 classes 能够直接写入您的 class 的字段.我还建议在单个 Node
中处理事件。一次只能有一个 Node
获得焦点,在不同地方处理事件只会导致重复代码。
public class Game {
private Rectangle leftPaddle;
private double leftPaddleY = 260;
private Rectangle rightPaddle;
private double rightPaddleY = 260;
private double leftPaddleDY;
private double rightPaddleDY;
private AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
// update paddle positions
leftPaddleY += leftPaddleDY;
rightPaddleY += rightPaddleDY;
if (leftPaddleY < 0) {
leftPaddleY = 0;
}
if (rightPaddleY < 0) {
rightPaddleY = 0;
}
leftPaddle.setY(leftPaddleY);
rightPaddle.setY(rightPaddleY);
}
};
public void createGame(Group gameDisplay) {
//creates background
Rectangle background = new Rectangle(0, 0, 800, 600);
background.getStyleClass().add("background");
//draws field lines
Canvas game = new Canvas(800, 600);
GraphicsContext gc = game.getGraphicsContext2D();
gc.setStroke(Paint.valueOf("WHITE"));
gc.setLineWidth(5);
gc.strokeLine(400, 0, 400, 600);
gc.strokeOval(300, 200, 200, 200);
gc.strokeRect(0, 150, 100, 300);
gc.strokeRect(700, 150, 100, 300);
gc.setStroke(Paint.valueOf("BLACK"));
gc.setLineWidth(8);
gc.strokeRect(0, 0, 800, 600);
//creates red paddle
leftPaddle = new Rectangle(30, leftPaddleY, 20, 70);
leftPaddle.setFill(Color.RED);
//creates blue paddle
rightPaddle = new Rectangle(750, rightPaddleY, 20, 70);
rightPaddle.setFill(Color.BLUE);
// register event handlers to Canvas
game.setFocusTraversable(true);
game.setOnKeyPressed(keyPressed);
game.setOnKeyReleased(keyReleased);
gameDisplay.getStylesheets().add(getClass().getResource("GameDisplay.css").toExternalForm());
gameDisplay.getChildren().addAll(background, game, leftPaddle, rightPaddle);
// start updates of paddle positions
timer.start();
}
private EventHandler<KeyEvent> keyReleased = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
// set movement to 0, if the released key was responsible for the paddle
switch (event.getCode()) {
case W:
case S:
leftPaddleDY = 0;
break;
case UP:
case DOWN:
rightPaddleDY = 0;
break;
}
}
};
private EventHandler<KeyEvent> keyPressed = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
// start movement according to key pressed
switch (event.getCode()) {
case W:
leftPaddleDY = -6;
break;
case S:
leftPaddleDY = 6;
break;
case UP:
rightPaddleDY = -6;
break;
case DOWN:
rightPaddleDY = 6;
break;
}
}
};
}