In LibGdx, is there a way to pause the delta time when user pause the screen/left apps temporary (such an incoming call)? Take for example, when displaying message is going to take 10 secs for user to read the message, normally, I would get the message displayed start time, do the calculation in render() to get the elapsed time (currentTime - MessageStartedTime), if elapsed time > 10secs, then close message, everything works correctly, right. Imaging this scenario, user is reading the message (let assume elapse time is 2 secs), an incoming call that took 20 secs, when the process is brought back to my apps, the elapsed time > 10 secs, and therefore the message will be removed even though the message is only displayed for 2 secs.
so, my question is, is there a master time counter that I can implement in my application for this kind of purposes? and what is the best way to implement it?
I have two game states, they are:
GAME_RUNNING
GAME_PAUSED
When pause() is called I set the state to GAME_PAUSED and when resume() is called I set the state to GAME_RUNNING.
And then when I run update() on my game I check this state and if it's paused I set delta to 0.
float deltaTime = game.state == GAME_PAUSED ? 0 : Gdx.graphics.getDeltaTime();
This means when all my game objects update, their changes are multipled by 0 and nothing changes. We can also add a condition and only update when deltaTime > 0.
If you have a timer, you'll be updating this timer somehow like:
public void update(World world, float delta) {
frameTimer += delta;
if( frameTimer >= rate / 1000) {
fireAtEnemy(world);
frameTimer = 0;
}
}
Because delta is now 0 the timer will not increase and not increase until the game state it back to GAME_RUNNING after resume().
Additionally, you can add an extra state called something like GAME_RUNNING_FAST and when this state is set you can multiply the deltaTime by 2 for example. If you have all your updates relative to the deltaTime then your entire game will run at double speed. If that's something you'd desire.
private long pauseTime = 0;
private long pauseDelay = 0;
#Override
public void pause() {
pauseTime = System.nanoTime();
}
#Override
public void resume() {
pauseDelay = System.nanoTime() - pauseTime;
pauseTime = 0;
}
And in your render method you just do long displayTime = delta - pauseDelay; pauseDelay = 0;
Related
I am working in Processing, using java. I'm trying to create a cctv type footage experience, where the viewer sees different camera footage flicked through based off of the amount of time that had passed since the program ran.
Currently, the first video plays perfectly fine. But then once that one stops, for some reason the second video never displays.
void draw(){
int timer = getAgeInSeconds();
if(timer <= 20){ // RESPONSIBLE FOR SWITCHING OUT MOVIES
if(movie1.available()){ // Refreshes frame. Can mofify with FrameRate()
//frameRate();
movie1.read();
image(movie1,0,0, width, height);
}
}
if(timer >= 21){
if(movie2.available()){
movie2.read();
image(movie2,0,0,width,height);
}
}
}
public int getAgeInSeconds(){ //FUNCTION FOR CALCULATING SECONDS FROM RUN TIME INSTEAD OF COMPUTER CLOCK
long nowMillis = System.currentTimeMillis();
int timer = (int)((nowMillis - this.createdMillis) /1000);
print("\n" + timer);
return(timer);
}
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.
In my game I have objects that gets spawned regularly on a 0.45s basis. When spawned into the world, they'll get a copy of the nanoTime at that time. That way I can check with the current nanoTime to remove the object after a certain amount of time has passed.
Now the problem is when you pause the game. Because the nanoTime will, of course, keep going which will make the objects disappear directly after you get out of the pause screen (if the pause screen was up longer than the amount of time it takes to remove the object).
Is there a way to freeze the nanoTime or something like that when you enter the pause screen and resume from where it left when you exit so the objects won't disappear directly after you get out of the pause screen?
I would recommend changing the way you store your spawned objects. Rather than storing the time when they are added to the world, you should store how long they have left to live.
On each render frame libGDX provides you with a delta parameter to measure how long has elapsed since the last render time. You would decrement from the timeLeftToLive variable (or some other name) this delta value if the game is not paused.
The code below illustrates my point (just a dummy class):
class ObjectTimer {
private float timeToLive = 0; //How long left in seconds
public ObjectTimer(float timeToLive) {
this.timeToLive = timeToLive;
}
//This method would be called on every render
//if the game isn't currently paused
public void update() {
//Decrease time left by however much time it has lived for
this.timeToLive -= Gdx.graphics.getDeltaTime();
}
//Return if all the time has elapsed yet
//when true you can de-spawn the object
public boolean isFinished() {
return timeToLive <= 0;
}
}
Then you might have a loop in your main game that would do the updating something along the lines of:
//Do this if the game isn't paused
if (!paused) {
//For each of your sprites
for (MySprite sprite: spriteArray) {
//Update the time run for
sprite.getObjectTimer().update();
//Check if the sprite has used all its time
if (sprite.getObjectTimer().isFinished()) {
//Despawning code...
}
}
}
I made CountDown.java file and try to add in my Word-trouble.java file (which is main applet) as CountDown ct = new CountDown();
but it is not showing timer in main applet.
Here is coding:
package pack.urdu;
import java.awt.*; //windows toolkit
import java.applet.*; //applet support
public class CountDown extends Applet implements Runnable{
int counter; Thread cd;
public void start() { // create thread
counter = 60; cd = new Thread(this); cd.start();
}
public void stop() { cd = null;}
public void run() { // executed by Thread
while (counter>0 && cd!=null) {
try{Thread.sleep(1000);} catch (InterruptedException e){}
--counter; repaint(); //update screen
}
}
public void paint(Graphics g) {
g.drawString(String.valueOf(counter),25,75);
}
}
You are making a mistake that I see a lot of programmers make: you are mixing up the calculation of elapsed time, with the calculation of the refresh time. If the duration of sleep takes long than a second because of thread contention, your timer will drift.
Instead of tracking a counter that increments every second, just record the start time:
long startTime = System.currentTimeMillis();
Then later, your paint method becomes:
public void paint(Graphics g) {
int elapsedSeconds = (int)(System.currentTimeMillis()-startTime)/1000
g.drawString(String.valueOf(elapsedSeconds),25,75);
}
This method can be called as often, and as many times as you like, and it will always display the correct elapsed seconds. There is no need to increment anything at any specified time.
The only other thing you have to do is to arrange that the screen gets refreshed. (I like to say that you only have to refresh the screen when the user looks at it :-) but since we don't know that we need to refresh more often). The mechanism for this may depend upon the graphic library. One lazy idea is to refresh ten times a second and the screen will be right most of the time.
If you do want to have a thread that sends repaint events, you should have those events sent just at the time that timer clicks over to a new value, and thereby send only one per second. This is done with:
while (stillRunning) {
long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
Thread.sleep(timeTillNextDisplayChange);
repaint();
}
Note that you do not sleep 1000ms! If your system is performing well, this will be very close to 1000ms, but slightly less than that to account for (1) the thread startup delay, possibly caused by thread contention, and (2) the processing time for this loop (which is quite small). In any case, calculating the sleep in this way will prevent timer drift, and assure that your display updates just as the seconds value changes.
See an extended discussion of Common Misunderstandings of Timers on my website.
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.