Итак, я делал игру с JavaFX и хотел, чтобы fps всегда был на 60. Однако, хотя обычно класс таймера анимации в JavaFX ограничивает число кадров в секунду на 60, в моем случае это не так. Я попробовал несколько различных решений для этого, которые показаны в строках:
System.setProperty("quantum.multithreading", "false");
System.setProperty("javafx.animation.fullspeed", "true");
System.setProperty("javafx.animation.pulse", "60");
System.setProperty("javafx.animation.framerate", "60");
Однако эти решения не работают. Я немного больше проверил ошибки и думаю, что моя ошибка вызвана тем, что частота обновления экрана изменяет ограниченную частоту кадров в JavaFX, т. Е. Когда частота обновления экрана составляет 60 Гц, частота кадров составляет 60 кадров в секунду, а когда частота обновления экрана равна 48 Гц, частота кадров составляет 48 кадров в секунду. Мне было интересно, как бы я остановил изменение частоты кадров на основе частоты обновления экрана и держал ее на постоянной скорости 60 кадров в секунду. Вот мой код ниже, любая помощь будет оценена:
package battlegame;
import java.io.IOException;
import battlegame.graphics.Assets;
import battlegame.input.KeyboardController;
import battlegame.world.World;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class Game extends Application{
public static int screenWidth = 960;
public static int screenHeight = 540;
private final long[] frameTimes = new long[100];
private int frameTimeIndex = 0 ;
private boolean arrayFilled = false ;
private Canvas canvas;
private boolean upTyped = true;
private Stage stage;
private Scene scene;
private Group group;
private GraphicsContext g;
private final LongProperty lastUpdateTime = new SimpleLongProperty(0);
private static World currentWorld;
private static KeyboardController keyController;
public Game() {
keyController = new KeyboardController();
}
public void begin(String args[]) {
launch(args);
}
public void initialise() throws IOException {
canvas = new Canvas(screenWidth, screenHeight);
group = new Group(canvas);
scene = new Scene(group);
g = canvas.getGraphicsContext2D();
Assets.init();
currentWorld = new World("/testlvl.txt");
currentWorld.init();
System.setProperty("quantum.multithreading", "false");
System.setProperty("javafx.animation.fullspeed", "true");
System.setProperty("javafx.animation.pulse", "60");
System.setProperty("javafx.animation.framerate", "60");
}
@Override
public void start(Stage primaryStage)throws Exception {
initialise();
final AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long timestamp) {
long oldFrameTime = frameTimes[frameTimeIndex] ;
frameTimes[frameTimeIndex] = timestamp ;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
if (frameTimeIndex == 0) {
arrayFilled = true ;
}
if (arrayFilled) {
long elapsedNanos = timestamp - oldFrameTime ;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
System.out.println(frameRate);
}
if (lastUpdateTime.get() > 0) {
tick();
render();
}
lastUpdateTime.set(timestamp);
}
};
stage = primaryStage;
stage.getIcons().add(new Image(Game.class.getResourceAsStream("/GameIcon.png")));
stage.setScene(scene);
stage.setResizable(true);
stage.setOnCloseRequest(event -> {
timer.stop();
});
stage.show();
scene.addEventHandler(KeyEvent.KEY_PRESSED, (key) -> {
if(upTyped && (key.getCode() == KeyCode.W || key.getCode() == KeyCode.UP || key.getCode() == KeyCode.SPACE)) {
keyController.up = true;
upTyped = false;
}
if(key.getCode() == KeyCode.A || key.getCode() == KeyCode.LEFT) {
keyController.left = true;
}
if(key.getCode() == KeyCode.S || key.getCode() == KeyCode.DOWN) {
keyController.down = true;
}
if(key.getCode() == KeyCode.D || key.getCode() == KeyCode.RIGHT) {
keyController.right = true;
}
if(key.getCode() == KeyCode.Z || key.getCode() == KeyCode.O || key.getCode() == KeyCode.ENTER) {
keyController.select = true;
}
if(key.getCode() == KeyCode.P || key.getCode() == KeyCode.X) {
keyController.action = true;
}
});
/*scene.addEventHandler(KeyEvent.KEY_TYPED, (key) -> {
if(key.getCode() == KeyCode.W || key.getCode() == KeyCode.UP || key.getCode() == KeyCode.SPACE) {
keyController.up = true;
System.out.println("YoIghtL/Kkjkjas");
}
});*/
scene.addEventHandler(KeyEvent.KEY_RELEASED, (key) -> {
if(key.getCode() == KeyCode.W || key.getCode() == KeyCode.UP || key.getCode() == KeyCode.SPACE) {
keyController.up = false;
upTyped = true;
}
if(key.getCode() == KeyCode.A || key.getCode() == KeyCode.LEFT) {
keyController.left = false;
}
if(key.getCode() == KeyCode.S || key.getCode() == KeyCode.DOWN) {
keyController.down = false;
}
if(key.getCode() == KeyCode.D || key.getCode() == KeyCode.RIGHT) {
keyController.right = false;
}
if(key.getCode() == KeyCode.Z || key.getCode() == KeyCode.O || key.getCode() == KeyCode.ENTER) {
keyController.select = false;
}
if(key.getCode() == KeyCode.P || key.getCode() == KeyCode.X) {
keyController.action = false;
} });
timer.start();
}
public void tick() {
currentWorld.tick();
keyController.tick();
}
public void render() {
g.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
currentWorld.render(g);
}
public static void main(String[] args){
launch();
}
public static KeyboardController getKeyController(){
return keyController;
}
public static World getCurrentWorld() {
return currentWorld;
}
}