Blackberry stopwatch implementation - java

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.

Related

What is the proper way to implement multi threading while using a gameLoop

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.

Tracking elapsed time with real-time counter

I've created a javafx application which includes a time-tracking function that tracks the amount of time the application has been open(run) for. I know about System.currentTimeMillis(), but I was wondering if it was possible to create a button (that serves no function as a button - I just needed to use a JFX button which looks nice) that shows(prints) the amount of time spent in the app. Something like a real-time counter where the time increases by itself.
Something similar to this: https://www.youtube.com/watch?v=f8LOflGG8g8
Except, however, instead of using animations, using text instead.
Just use an AnimationTimer to update the text:
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
long startTime = System.currentTimeMillis();
Label timerLabel = new Label();
new AnimationTimer() {
#Override
public void handle(long now) {
long elapsedMillis = System.currentTimeMillis() - startTime ;
timerLabel.setText(Long.toString(elapsedMillis / 1000));
}
}.start();
// lay out UI etc etc
}
}
Create a Thread class
Start it whenever you like, and pass the current time as an argument to the above class (System.currentTimeMillis())
Inside the thread, have a loop, and a Thread.sleep(1000); at the end. Every time the loop goes, have it subtract the time you passed along in step 2 from the current time like this: System.currentTimeMillis() - startTime
Use the proper async GUI update methods to update the button you want. You can divide your calculated time by 1000 to get the seconds, another 60 to get the minutes, and another 60 to get the hours.

LibGDX stop time counter on pause

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;

Nesting of timers

This post is related to my last post.The block of code changes the text to desired color after desired time.
however, now I want to change the color of a perticular word such that each letter gets the equal time.EG if "hello" have been given a time of 1000 milliseconds (have 5 letters) then 'h''e''l''l''o' each letter should get 1000/5 milliseconds i.e 200 milliseconds each.
I implemented swing timer for this :
public Reminder() {
a[0]=2000;
a[1]=1000;
a[2]=3000;
a[3]=5000;
a[4]=3000;
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
point =point +arr[i].length();
i++;
doc.setCharacterAttributes(0,point+1, textpane.getStyle("Red"), true);
timer.setDelay(a[i]);
}
};
timer = new Timer(a[i], actionListener);
timer.setInitialDelay(0);
timer.start();
For this to happen, shoud I use another Timer inside the actionListener to give further timings to a perticular letter?Or should I first break the time by .length()
and then use the timer?I cannot decide a better way.Any ideas?
You should never need more than one timer. Since you know ahead of time exactly when everything should happen, just calculate those times, put them in a list (sorted by time) and execute each one.
public colorize(int offset, int length) {
long triggerTime[] = new long[length];
long startTime = System.currentTimeMillis();
for (int i=0; i<length; i++) {
triggerTime[i] = startTime + (1000*i)/length;
}
for (int i=0; i<length; i++) {
//just wait for the next time to occur
Thread.sleep(triggerTime[i]-System.currentTimeMillis());
doc.setCharacterAttributes(offset, i+1, textpane.getStyle("Red"), true);
}
}
This may strike you as very pedestrian because it does not use a TimerTask object, but it is effective, efficient, and easy to debug. You simplty call this method on whatever thread you want, and it occupies the entire thread, and the word will be colorized at a rate such it is completed in 1 second.
You could, if you don't have a thread handy, make a timer that calls this, but the only reason for that is to access a thread. The real point is: don't set up multiple timers, just make an array of time values. After one event is satisfied, set to delay until the next time. You never need multiple timers.
It would be a little cleaner if you made an object that represented the coloring of a character (or whatever action you want) and you put together a collection of these actions. Then sort the entire collection by time they are to go off. The loop above would walk through the collection, waiting until the time for the action arrives, and then executing it. Another advantage of this approach is that you could clear the collection and that would terminate the loop.
See the discussion of the overuse of timers on my website to understand why this is bad.

I want to add timer in my applet

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.

Categories

Resources