How should we make fixed timestep in Java? I think there are 2 ways:
Synchronised game loop using while.
Asynchronised game loop using Thread.
The most important thing is performance and accuracy. So what's the best way?
This is synchronised game loop:
double timeStep = world.getSettings().getStepFrequency();
long lastTime = System.nanoTime();
while (true) {
long currentTime = System.nanoTime();
double elapsedTime = (currentTime - lastTime) / 1000000000.0;
if (elapsedTime >= timeStep) {
lastTime = currentTime;
world.update(elapsedTime);
}
}
This is asynchronised game loop:
double timeStep = world.getSettings().getStepFrequency();
long lastTime = System.nanoTime();
Thread loop = new Thread() {
public void run() {
while (true) {
long currentTime = System.nanoTime();
double elapsedTime = (currentTime - lastTime) / 1000000000.0;
lastTime = currentTime;
world.update(elapsedTime);
try {
Thread.sleep((long) Math.floor(timeStep * 1000));
} catch (InterruptedException e) {}
}
}
};
loop.start();
The synchronised game loop uses lots of CPU (I think 1 core? that's ~25% for me).
CPU usage of the asynchronised game loop is almost 0%.
Note: The game I want to do is WebSocket based game. The server is for physics, and HTML5's canvas is for rendering.
What way do you prefer? Why? Is there any better way?
There are classes in the Java API to execute a task periodically. Its better to not try to reinvent the wheel and use the Java API. A ScheduledExecutorService seems to be what you need.
This example execute a Runnable periodically:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(myRunnable, initialDelay, period, TimeUnit.MILLISECONDS);
In your first example, your thread is checking a huge amount of times if elapsedTime >= timeStep is true. It keeps doing the check until it is true, instead of doing this check time after time until it is finally true, the thread could be waiting and the processor could be used for something else.
The second option is better than the first one because the thread waits for the period to the next execution.
Related
I am developing a game using Java Swing and I've been wondering how can I implement multithreading into it. I thought I could move some parts of the game logic to new threads (like weather implementation/lighting effect or some complex in-game events that are running in the background independently of the main thread). I would like to hear possible suggestions and common practices on how to do it as well as possible elements of the game that are best to be implemented in individual threads.
Currently it uses a single thread. Here is the core of the game (game loop, where things are updated (game logic) and rendered) :
#Override
public void run() {
double drawInterval = 1000000000.0/FPS;
double delta = 0;
long lastTime = System.nanoTime();
long currentTime;
while(gameThread != null) {
currentTime = System.nanoTime();
delta += (currentTime - lastTime) / drawInterval;
lastTime = currentTime;
if(delta >= 1) {
// 1 UPDATE: update information such as character position
update();
// 2 DRAW: draw the screen with the updated information
repaint();
delta--;
}
}
}
public void startGameThread() {
gameThread = new Thread(this);
gameThread.start();
}
(And then it is called in the main method...)
I'm working on a game where I move a car image based on keyboard input. Currently I'm using this game loop:
private void runGameLoop() {
window.setVisible();
isRunning = true;
final double FRAMES_PER_SECOND = 60;
double timePerUpdate = 1000000000 / FRAMES_PER_SECOND;
double timeFromLastUpdate = 0;
long now;
long last = System.nanoTime();
while (isRunning) {
now = System.nanoTime();
timeFromLastUpdate += (now - last) / timePerUpdate;
last = now;
if(timeFromLastUpdate >= 1) {
tick();
render();
timeFromLastUpdate--;
}
}
}
The tick method updates the car image location, and the render method will render the image(with the new location) on screen.
I want to have the calculations for the new image location on a separate thread, because at the moment the calculations are taking to long and causing a rendering lag. Is there a way to use multi threading while still implementing a game loop?
Thanks in advance.
Perhpas you can do something similar to what Android does. In Android there is the mainthread which would be like your game loop. It has a Handler for runnables that are posted from background/concurrent threads to the mainthread.
So at every loop cycle the mainthread executes any runnables posted feom background threads.
Note, that the calculations should not be done in the runnables (which are executed in mainthread), only passing the results/updating stuff should be done in the runnables.
This question already has answers here:
Calculating frames per second in a game
(21 answers)
Closed 9 years ago.
Yesterday I wrote a Thread addressing how my game loop ran (in java) and how it works.
My game loop works completely, and I know why, but now I just wan't to know how to calculate FPS (Frames Per Second) and print it out every second.
I got a response yesterday about this, but he/she explained it in words and I couldn't understand it.
If anyone could help me (with a code example? :D) that would be great.
Here is my game loop:
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
Game.logger.log("ERROR! Printing Stacktrace...");
e.printStackTrace();
}
}
ALSO:
In my JFrame when ever I call setName(string) it never works/updates on the Frame - Link me to a thread?
The easiest way to do this is to keep a variable whatTheLastTimeWas stored and doing this where you want to check your frame rate:
double fps = 1000000.0 / (lastTime - (lastTime = System.nanoTime())); //This way, lastTime is assigned and used at the same time.
Alternatively, you can make a FPS counter like so:
class FPSCounter extends Thread{
private long lastTime;
private double fps; //could be int or long for integer values
public void run(){
while (true){//lazy me, add a condition for an finishable thread
lastTime = System.nanoTime();
try{
Thread.sleep(1000); // longer than one frame
}
catch (InterruptedException e){
}
fps = 1000000000.0 / (System.nanoTime() - lastTime); //one second(nano) divided by amount of time it takes for one frame to finish
lastTime = System.nanoTime();
}
}
public double fps(){
return fps;
}
}
Then in your game, have an instance of FPSCounter and call nameOfInstance.interrupt(); when one frame is finished.
You can combine a simple counter and Timer.scheduleAtFixedRate for this.
Disclaimer: I don't know if this is the best method; it's just easy.
int totalFrameCount = 0;
TimerTask updateFPS = new TimerTask() {
public void run() {
// display current totalFrameCount - previous,
// OR
// display current totalFrameCount, then set
totalFrameCount = 0;
}
}
Timer t = new Timer();
t.scheduleAtFixedRate(updateFPS, 1000, 1000);
while (running) {
// your code
totalFrameCount++;
}
I have a game loop here, that calls the tick method. Inside the tick method, other tick methods are called. How would I slow down the call to input.tick() without slowing down the whole program? Putting a Thread.sleep(); anywhere in the tick methods slows down the whole program and that is not what I want.
public void run() {
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
final double ns = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
int ticks = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
ticks++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println(ticks + " tps, " + frames + " fps");
ticks = 0;
frames = 0;
}
}
stop();
}
public void tick(){
input.tick(); // How do I slow down the call to this?
if(gameState){
player.tick();
player.move();
collision();
treeline.move();
obstacleHole.move();
obstacleWolf.move();
coin.move();
coin.tick();
}
}
It seems you are doing a GUI application and the code you are showing runs on the Event Dispatch Thread. The sleeps make the EDT freeze and be unable to update the GUI. What you must do instead is use the javax.swing.Timer class to postpone the execution of the code.
If you want to tick at regular intervals, then just reschedule the same task again in the handler submitted to Timer.
Use a Thread to call tick() in a deferred way, something like this:
private static final Timer TIMER = new Timer();
// ...
public void tick(){
TIMER.schedule(new TimerTask(){
void run() {
input.tick(); // Your tick method
}
}, 1000 /* delay in milliseconds */)
// ... rest of your method
}
If the input.tick() method collects the input of the player (e.g. key presses) it does no seem appropriate to delay it.
Perhaps you might be interested in implementing a Keyboard Input Polling mechanism. (see here for an example).
This is a usual technique in games so you do not respond to the input of the player in the usual way you would with other GUI applications. Instead you collect all the user input e.g. in a queue and then you poll that queue to read input at your own speed (e.g. 30 times per second).
I hope it helps
I'm trying to write a blackberry app that is basically a stopwatch, and displays lap times. First, I'm not sure I'm implementing the stopwatch functionality in the most optimal way. I have a LabelField (_myLabel) that displays the 'clock' - starting at 00:00. Then you hit the start button and every second the _myLabel field gets updated with how many seconds have past since the last update (should only ever increment by 1, but sometimes there is a delay and it will skip a number). I just can't think of a different way to do it - and I am new to GUI development and threads so I guess that's why.
EDIT: Here is what calls the stopwatch:
_timer = new Timer();
_timer.schedule(new MyTimerTask(), 250, 250);
And here is the TimerTask:
class MyTimerTask extends TimerTask {
long currentTime;
long startTime = System.currentTimeMillis();
public void run() {
synchronized (Application.getEventLock()) {
currentTime = System.currentTimeMillis();
long diff = currentTime - startTime;
long min = diff / 60000;
long sec = (diff % 60000) / 1000;
String minStr = new Long(min).toString();
String secStr = new Long(sec).toString();
if (min < 10)
minStr = "0" + minStr;
if (sec < 10)
secStr = "0" + secStr;
_myLabel.setText(minStr + ":" + secStr);
timerDisplay.deleteAll();
timerDisplay.add(_timerLabel);
}
}
}
Anyway when you stop the stopwatch it updates a historical table of lap time data. When this list gets long, the timer starts to degrade. If you try to scroll, then it gets really bad.
Is there a better way to implement my stopwatch?
Here are a few tips:
keep track of the last "sec" value used to update the label, and exit from the run loop immediately if the newly-calculated "sec" value is the same - otherwise you're needlessly refreshing the UI with the same values which slows everything down
remove the synchronization in your run loop and just put the code that modifies the UI (setText call) in a UiApplication.getUiApplication.invokeLater() call (using an anonymous Runnable)
don't delete the re-add the label from the screen or maanger, you just need to call setText() and it should update - if it doesn't update then call invalidate() on the field and it will be redrawn
now that you've optimized your code and minimized the amount of actual UI drawing, it's safe to set the timertask interval to a lower value, such as 50ms, so that you have a smoother timer update
The most important thing to remember in making a fast UI is to only update the UI when you need to, and only update the fields that need to change. If you're calling methods like deleteAll() you're going to end up having the entire screen or manager refresh which is really really slow.