i am trying to calculate the time passed in my libGDX application like this
float timeSpent= 0;
public void render(){
timeSpent = timeSpent + Gdx.graphics.getDeltaTime();
}
by the above code i feel like the time is almost passing double the normal rate
but if i get delta time directly from java's nano time method like this
float prevTime;
float timeSpent = 0;
public void show(){
prevTime = System.nanoTime();
}
public void render(){
float p = System.nanoTime();
timeSpent += (p-prevTime)/1000000000f;
prevTime = p;
}
it seems to work fine, i know that libgdx also get delta time from subtracting
nano time method.
i am not able to figure out what am i doing wrong in the first method.
thank you
You can calculate the passed time from the start of your application by simply saving a date when it starts, and just subtract it from the current date. No need to accumulate the deltas in each frame.
You can further simplify the code by using TimeUtils:
// save at start
long start = TimeUtils.millis();
// query whenever you want
long diffInMillis = TimeUtils.timeSinceMillis(startTime);
Related
I'm new at Java and I'm trying to develop a non-linear idle game for Android.
I'm a bit stuck on how to manage the "time" in my game.
In linear idle game, I would have used System.currentTimeMillis() to update my model during game (application opened), and at game restart (as model is linear, simple formula to update model based on elapse time is sufficient).
But in non-linear idle game, my model must be time discrete, and a loop must be done at game restart. Then, at game restart, my models can't use System.currentTimeMillis().
My idea was to use a specific timer to calculate model when game is opened. But with my current knowledge, I don't know how to access a given timer from all my classes.
For example, in a class representing a Ship there is a method to travel. For this example, model is linear:
public class Ship {
double travelStartTime, travelEndTime;
double positionX, positionY;
double maxSpeed = 10;
public Ship(double buildPostionX, double buildPositionY) {
positionX = buildPositionY;
positionY = buildPostionX;
maxSpeed = 10;
travelStartTime = 0;
travelEndTime = 0;
}
public void startTravel(double destX, double destY){
travelStartTime = System.currentTimeMillis();
travelEndTime = System.currentTimeMillis() + travelTime(destX, destY);
}
public double travelTime(double destinationX, double destinationY) {
double currentX = this.getPositionX();
double currentY = this.getPositionY();
//calculate distance in km
double distance = Math.pow(Math.pow(currentX-destinationX, 2) + Math.pow(currentY-destinationY, 2), 0.5);
double time = distance/maxSpeed; //time in seconds
return time;
}
My questions are:
1. I would like to replace System.currentTimeMillis() by my own timer (started each time application starts), but how can I do that ? Knowing that any class of my model need to access the same timer ? Or is there any other to manage this issue ?
2. At the end of the travel, I would like to send a new "event", for example to display a new pop-up (or alertDialog) or to start a metho. How can I do that ?
Hope I was clear enough in my explanations.
Thank you in advance for any answer.
You could add a currentTime field on your main game class and pass it down to entity instances on each update. You can also use a static long field, but this is discouraged. Example:
class MyGame {
private long currentTime = 0;
private Ship myShip = /* TODO */;
// Called every x ms by an ExecutorService
public void update() {
// Update currentTime however you want
// e.g. currentTime += 1000
myShip.update(currentTime);
}
}
class Ship {
private int x;
private int y;
public void update(long currentTime) {
// TODO e.g. perform lerp with previous position
}
}
This is known as the Update Method pattern.
I'm currently working with Processing. I would like to execute a function 4 seconds after its call. I tried using millis() by taking a value at a certain time and comparing. But when I write:
final int m = millis();
The value of m changes at the same time millis() changes.
How can I capture a constant value of millis()?
PS. I've tried using final and static.
You need to scope the variable at the sketch level, outside of the draw() function so that you aren't recreating it every time. You also need to compare the variable to the current time. Something like this:
int startTime;
void setup(){
startTime = millis();
}
void draw(){
int currentTime = millis();
if(currentTime > startTime + 5000){
background(255, 0, 0);
}
}
I'd also recommend doing a search on Stack Overflow for the millis() function.
I'm trying to create a countdown. I don't see how exactly I can make a countdown. Can anyone help?
The code does what you tell it. You say in onStart:
end.add(Calendar.MINUTE, 4);
end.add(Calendar.SECOND, 5);
which tells the system you want a countdown starting at 4 minutes and 4 seconds. Instead, do:
end.add(Calendar.SECOND, 45);
EDIT
Took a while to understand what you meant. First, go to github and copy TickTockView into your own project. Remove the dependency to the original project. Open the file and in onDraw, change:
if (mCircleDuration == DURATION_TOTAL && mStartTime != null) {
long totalTime = mEndTime.getTimeInMillis() - mStartTime.getTimeInMillis();
float percentage = (((float) mTimeRemaining) / ((float) totalTime));
angle = 360f * percentage;
}
to:
if (mCircleDuration == DURATION_TOTAL && mStartTime != null) {
long totalTime = mEndTime.getTimeInMillis() - mStartTime.getTimeInMillis();
float percentage = (((float) mTimeRemaining) / ((float) 45000));//45000(ms) = 45 seconds
angle = 360f * percentage;
}
In your xml file where the circle is defined, add:
app:tickCircleDuration="total_time"
And by doing that, you only need to change totalTime in onDraw in the TickTockView. Remember to update the package name in the XML file to point to the place you saved the file, not the original project.
For reference, this is the file you should copy
The good way is to use CountDownTimer class provided by Android for downward counting in time. I have recently used it in my game and is simple in use. First you
CountDownTimer timer = new CountDownTimer(45000, 1000) {
// 45000 milliseconds countdown and 1000 milliseconds decrement at each tick.
public void onTick(long millisUntilFinished) {
//you can change your UI here based on time
}
public void onFinish() {
// you can define something to happen when timer ends.
}
};
timer.start();
Change the below code into
Calendar end = Calendar.getInstance();
end.add(Calendar.MINUTE, 4);
end.add(Calendar.SECOND, 5);
into
Calendar end = Calendar.getInstance();
end.add(Calendar.MINUTE, 0);//O minute
end.add(Calendar.SECOND, 45);//45 second
I'm getting weird results trying to use the method I usually use to get the duration:
float start = System.nanoTime();
//Do stuff
float duration = System.nanoTime() - start;
float durationInSeconds = duration / 1000000000.0f;
So I tried that in this flashlight app I'm making to create a strobe:
public void onClick(DialogInterface dialog, int id) {
isFlashOn = true;
isStrobeActive = true;
// Perform actual strobe
strobeHandler.post(new Runnable() {
float currDuration = 0;
final float deltaTime = 1/60f;
final float deltaTimeInMil = deltaTime * 1000;
#Override
public void run() {
float strobePerSecond = 1 / currentStrobeValue;
if (!isStrobeLightOn) {
if (currDuration > strobePerSecond) {
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
currDuration -= strobePerSecond;
isStrobeLightOn = true;
}
} else {
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
isStrobeLightOn = false;
}
currDuration += deltaTime;
strobeHandler.postDelayed(this, (long) deltaTimeInMil);
}
});
}
The logs, however, return either 0.0 or 3.052E-5. I'm not exactly sure what I'm doing wrong, but I thing I need some help to figure it out. As always thanks.
Edit: I'm assuming that the start and end times are so similar, when they are subtracted and rounded, they are 0.
I'm guessing because float is not accurate enough if numbers get too big. Why not use long like you're supposed to?
long start = System.nanoTime();
//Do stuff
long duration = System.nanoTime() - start;
double durationInSeconds = duration / 1000000000.0d;
Take a look at the byte code. Maybe the compiler is just stripping away the call. If that's the case just create a public volatile field and assign it inside the method or as a return value.
It is call dead-code elimination. It is not the only optimisation that might be performed.
Dissasemble the class file and take a look just in case. You can do that with javap.
Take a look at [1] and [2] for micro benchmarking advice.
[1] http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#benchmarking_simple
[2] http://shipilev.net/talks/devoxx-Nov2013-benchmarking.pdf
Three parts to the answer.
You should never subtract floating point numbers that are very close in value. You will get severe loss of precision, to the point of being useless. In this case, subtract the integers and convert to double only for displaying the result.
From what I can see of the code, it looks instantaneous -- in the microsecond range or below -- and the time function does not provide that level of resolution. You cannot get useful results this way.
Benchmark timing is subtle, complicated and confusing (even when it's behaving correctly!). Please read the reference provided and plan carefully. What are you trying to measure? How can you do it? What will you do with the results.
Reference: How do I write a correct micro-benchmark in Java?
I'm writing a fairly simple 2D multiplayer-over-network game. Right now, I find it nearly impossible for myself to create a stable loop. By stable I mean such kind of loop inside which certain calculations are done and which is repeated over strict periods of time (let's say, every 25 ms, that's what I'm fighting for right now). I haven't faced many severe hindrances this far except for this one.
In this game, several threads are running, both in server and client applications, assigned to various tasks. Let's take for example engine thread in my server application. In this thread, I try to create game loop using Thread.sleep, trying to take in account time taken by game calculations. Here's my loop, placed within run() method. Tick() function is payload of the loop. It simply contains ordered calls to other methods doing constant game updating.
long engFPS = 40;
long frameDur = 1000 / engFPS;
long lastFrameTime;
long nextFrame;
<...>
while(true)
{
lastFrameTime = System.currentTimeMillis();
nextFrame = lastFrameTime + frameDur;
Tick();
if(nextFrame - System.currentTimeMillis() > 0)
{
try
{
Thread.sleep(nextFrame - System.currentTimeMillis());
}
catch(Exception e)
{
System.err.println("TSEngine :: run :: " + e);
}
}
}
The major problem is that Thread.sleep just loves to betray your expectations about how much it will sleep. It can easily put thread to rest for much longer or much shorter time, especially on some machines with Windows XP (I've tested it myself, WinXP gives really nasty results compared to Win7 and other OS). I've poked around internets quite a lot, and result was disappointing. It seems to be fault of the thread scheduler of the OS we're running on, and its so-called granularity. As far as I understood, this scheduler constantly, over certain amount of time, checks demands of every thread in system, in particular, puts/awakes them from sleep. When re-checking time is low, like 1ms, things may seem smooth. Although, it is said that WinXP has granularity as high as 10 or 15 ms. I've also read that not only Java programmers, but those using other languages face this problem as well.
Knowing this, it seems almost impossible to make a stable, sturdy, reliable game engine. Nevertheless, they're everywhere.
I'm highly wondering by which means this problem can be fought or circumvented. Could someone more experienced give me a hint on this?
Don't rely on the OS or any timer mechanism to wake your thread or invoke some callback at a precise point in time or after a precise delay. It's just not going to happen.
The way to deal with this is instead of setting a sleep/callback/poll interval and then assuming that the interval is kept with a high degree of precision, keep track of the amount of time that has elapsed since the previous iteration and use that to determine what the current state should be. Pass this amount through to anything that updates state based upon the current "frame" (really you should design your engine in a way that the internal components don't know or care about anything as concrete as a frame; so that instead there is just state that moves fluidly through time, and when a new frame needs to be sent for rendering a snapshot of this state is used).
So for example, you might do:
long maxWorkingTimePerFrame = 1000 / FRAMES_PER_SECOND; //this is optional
lastStartTime = System.currentTimeMillis();
while(true)
{
long elapsedTime = System.currentTimeMillis() - lastStartTime;
lastStartTime = System.currentTimeMillis();
Tick(elapsedTime);
//enforcing a maximum framerate here is optional...you don't need to sleep the thread
long processingTimeForCurrentFrame = System.currentTimeMillis() - lastStartTime;
if(processingTimeForCurrentFrame < maxWorkingTimePerFrame)
{
try
{
Thread.sleep(maxWorkingTimePerFrame - processingTimeForCurrentFrame);
}
catch(Exception e)
{
System.err.println("TSEngine :: run :: " + e);
}
}
}
Also note that you can get greater timer granularity by using System.nanoTime() in place of System.currentTimeMillis().
You may getter better results with
LockSupport.parkNanos(long nanos)
altho it complicates the code a bit compared to sleep()
maybe this helps you.
its from david brackeen's bock developing games in java
and calculates average granularity to fake a more fluent framerate:
link
public class TimeSmoothie {
/**
How often to recalc the frame rate
*/
protected static final long FRAME_RATE_RECALC_PERIOD = 500;
/**
Don't allow the elapsed time between frames to be more than 100 ms
*/
protected static final long MAX_ELAPSED_TIME = 100;
/**
Take the average of the last few samples during the last 100ms
*/
protected static final long AVERAGE_PERIOD = 100;
protected static final int NUM_SAMPLES_BITS = 6; // 64 samples
protected static final int NUM_SAMPLES = 1 << NUM_SAMPLES_BITS;
protected static final int NUM_SAMPLES_MASK = NUM_SAMPLES - 1;
protected long[] samples;
protected int numSamples = 0;
protected int firstIndex = 0;
// for calculating frame rate
protected int numFrames = 0;
protected long startTime;
protected float frameRate;
public TimeSmoothie() {
samples = new long[NUM_SAMPLES];
}
/**
Adds the specified time sample and returns the average
of all the recorded time samples.
*/
public long getTime(long elapsedTime) {
addSample(elapsedTime);
return getAverage();
}
/**
Adds a time sample.
*/
public void addSample(long elapsedTime) {
numFrames++;
// cap the time
elapsedTime = Math.min(elapsedTime, MAX_ELAPSED_TIME);
// add the sample to the list
samples[(firstIndex + numSamples) & NUM_SAMPLES_MASK] =
elapsedTime;
if (numSamples == samples.length) {
firstIndex = (firstIndex + 1) & NUM_SAMPLES_MASK;
}
else {
numSamples++;
}
}
/**
Gets the average of the recorded time samples.
*/
public long getAverage() {
long sum = 0;
for (int i=numSamples-1; i>=0; i--) {
sum+=samples[(firstIndex + i) & NUM_SAMPLES_MASK];
// if the average period is already reached, go ahead and return
// the average.
if (sum >= AVERAGE_PERIOD) {
Math.round((double)sum / (numSamples-i));
}
}
return Math.round((double)sum / numSamples);
}
/**
Gets the frame rate (number of calls to getTime() or
addSample() in real time). The frame rate is recalculated
every 500ms.
*/
public float getFrameRate() {
long currTime = System.currentTimeMillis();
// calculate the frame rate every 500 milliseconds
if (currTime > startTime + FRAME_RATE_RECALC_PERIOD) {
frameRate = (float)numFrames * 1000 /
(currTime - startTime);
startTime = currTime;
numFrames = 0;
}
return frameRate;
}
}