我正在尝试使用Java和JavaFX创建多人“四人乒乓”。网络部分运行良好。服务器处理所有游戏逻辑,并将球的位置和所有球员的位置发送给所有四个客户端。
现在,我需要向客户端添加GUI。但是,问题从这里开始。 我需要了解两件事:如何在不冻结GUI的情况下从不同的线程更新JavaFX节点(例如,每次服务器发送新坐标时都设置球位置),以及如何告诉GUI再次从另一个位置设置GUI不同的线程?
客户端的体系结构如下:我有一个客户端类,它处理所有网络和协议内容,主要是发送到服务器和从服务器接收。
我考虑过将JavaFX GUI类设置为客户端的入口点,然后在其中创建一个新的客户端对象。然后,GUI可以调用客户端对象上的方法,例如client.move(DIRECTION);
或client.sendMessage("Hello")
。那不是问题,但是我找不到针对客户端-> GUI的另一种好的解决方案。
客户端必须以某种方式能够修改节点,例如球。当服务器发送新的BALL_POSITION x y
命令时,客户端必须以某种方式告诉GUI新的球位置。我不能使用Platform.runLater(Runnable);
,因为如果球位置每100毫秒左右更新一次,则GUI冻结。对于球员的位置,这是相同的。
使用SimpleIntegerProperty
对球的位置有效。我在GUI中为此属性添加了一个侦听器,然后在不冻结GUI的情况下对其进行了更新。
那是正确的方法还是我应该完全不同?
又如何告诉GUI在客户端内部切换场景,而该客户端在与GUI不同的线程中运行?
我尝试的控球位置(简化):
Client.java
class Client extends Thread {
private Ball ball;
Client() {
this.ball = new Ball();
new Thread(ball).start();
}
Ball getBall() {
return this.ball;
}
}
Ball.java
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
class Ball implements Runnable {
private IntegerProperty ballX;
private IntegerProperty ballY;
Ball() {
ballX = new SimpleIntegerProperty(this, "ballX", 0);
ballY = new SimpleIntegerProperty(this, "ballY", 0);
}
public void setPosition(int x, int y) {
this.ballX.setValue(x);
this.ballX.setValue(y);
}
IntegerProperty getBallX() {
return this.ballX;
}
IntegerProperty getBallY() {
return this.ballY;
}
}
Protocol.java
switch(command) {
case(BALL_POSITION):
...
client.getBall().setPosition(x, y);
}
GameGUI.java
Circle circle = new Circle(0, 0, 30);
final Client client = new Client();
...
final AtomicInteger count1 = new AtomicInteger(-1);
client.getBall().getBallX().addListener(new ChangeListener<Number>() {
@Override
public void changed(final ObservableValue<? extends Number> observable,
final Number oldValue, final Number newValue) {
if (count1.getAndSet(newValue.intValue()) == -1) {
Platform.runLater(new Runnable() {
@Override
public void run() {
int value = count1.getAndSet(-1);
ballXLabel.setText("BallX: " + value);
circle.setCenterX(value);
}
});
}
}
});
这在开始时就可以了,但是我真的不知道这是否应该这样做。
另外,如果服务器发送命令,例如GAME_END
,我将如何切换场景?
我真的希望有人愿意帮助我,谢谢!!