I keep getting a lot of "Delta: 0.0"s in my console and ever few lines I get something like "Delta: 9.999275207519531E-4", what's happening?
Timer timer = new Timer();
float lastTime = 0.0f;
timer.resume();
while (!Display.isCloseRequested())
{
timer.tick();
System.out.println("Delta: " + (timer.getTime() - lastTime));
lastTime = timer.getTime();
Display.update();
}
Display.destroy();
Don't ever use java's Timer class in your game loops. It isn't precise enough to use reliably. Instead, check out this link to see a couple of reliable game loops written in java.
One little note, just a warning. Your timing mechanism is flawed a bit.
Considering this code runs line by line as it is written, you'll "loose" time. This
System.out.println("Delta: " + (timer.getTime() - lastTime));
lastTime = timer.getTime();
code does the following:
1. Getting current time.
2. Doing some math.
3. Calling String constructor.
4. Performing String concatenation.
5. Writing current time to the lastTime variable.
Note that current time in the 1 and 5 cases are different. That means that this time is "lost" from the "Delay: xx" output.
If you continue to use (timer.getTime() - lastTime) technics in your code for the purpose of getting time passed from the previous iteration, you will surely run into problem where different events thinks that time passed from the previous iteration is different. I recommend you to use the following code for timing:
private double delta;
private long timing;
public void updateTime()
{
long newTime = System.nanoTime();
this.delta = (newTime - this.timing) / 1_000_000_000.0;
this.timing = newTime;
}
public double getDelta() {
return this.delta;
}
where updateTime() is called once per cycle and getDelta() is called every time you want to get time passed from the previous iteration.
Related
I would like to force a method to end after a certain amount of time even if it has not completed its task. How would I go about doing this?
Edit (added clarification and code):
I am programming a robot using Android Studio for the FTC (First Tech Challenge) robotics competition. To control the robot, I am using the FTC SDK (see https://github.com/ftctechnh/ftc_app).
The method works fine for going a particular distance and then stopping but after it stops by setting the power of all the motors to zero, it appears to get hung and no subsequent methods are invoked. Currently, it is only supposed to have the motors be stopped for one second before exiting but it appears to still get stuck on the first invocation of the method that sets the motor power to zero (setPower). For this reason, I would like to be able to terminate setPower after it has been running for a certain amount of time so that my method can exit and subsequent methods can be invoked.
Here is my method:
public void moveLine(DcMotor m1, DcMotor m2, DcMotor m3, DcMotor m4, double distance /* distance to move in meters */, double motorPower /* power to set the motors */) {
final double SPROCKET_CIRCUMFRENCE = Math.PI * 0.0652; //calculates the circumference of the sprocket
final int ENCODER_CPR_NR60 = 1680; //encoder counts for NeveRest 60
//final static int ENCODER_CPR_NR40 = 1120; //encoder counts for NeveRest 40
double amountOfRotationsCalc = distance / SPROCKET_CIRCUMFRENCE; //calculates the amount of rotations to move to reach the target distance
double amountOfEncUnitsCalc = ENCODER_CPR_NR60 * amountOfRotationsCalc; //calculates the amount of encoder units to move
//this gets the sum of the encoder positions of the drive motors
int currentEncPosSum = m1.getCurrentPosition() + m2.getCurrentPosition() + m3.getCurrentPosition() + m4.getCurrentPosition();
//this gets the average encoder position
int currentEncPosAvg = currentEncPosSum / 4;
//if the robot is supposed to be moving forward (positive distance), the motors will be set to positive values
if (distance > 0) {
//it may make sense to make this a while loop. Will this fix the issue?
if (currentEncPosAvg < amountOfEncUnitsCalc) {
m1.setPower(motorPower);
m2.setPower(motorPower);
m3.setPower(motorPower);
m4.setPower(motorPower);
} else {
//these stop the robot. Without them, it continues to move.
long start = System.currentTimeMillis();
long end = start + 1000;
while (System.currentTimeMillis() < end) {
m1.setPower(0);
m2.setPower(0);
m3.setPower(0);
m4.setPower(0);
}
return; //this is supposed to exit this method
}
} else {
//this is essentially the opposite of the code for going forwards
if (currentEncPosAvg > amountOfEncUnitsCalc) {
m1.setPower(-motorPower);
m2.setPower(-motorPower);
m3.setPower(-motorPower);
m4.setPower(-motorPower);
} else {
//these stop the robot. Without them, it continues to move.
long start = System.currentTimeMillis();
long end = start + 1000;
while (System.currentTimeMillis() < end) {
m1.setPower(0);
m2.setPower(0);
m3.setPower(0);
m4.setPower(0);
}
return;
}
}
}
long beginning = System.currentTimeMillis();
long end=beginning + yourTimeInMilliseconds;
while (end > System.currentTimeMillis()){
//your code here
}
I believe this is what you mean.
Some clarification, if you need any:
beginning is the current time in milliseconds.
end is obviously when it ends. (Start time plus delay)
While the time is still less than the set end time, the code keeps going.
I know this question is a bit old, but in the latest ftc_app Android SDKs it is recommended that for time aware methods and procedures that teams use the ElapsedTime class.
The most important thing to consider when pausing an opmode is that you can still shut it down when the stop button is pressed on the driver station app. you can make sure of this by including the opModeIsActive() method in your while condition
On our team we have a method for pausing OpModes that looks something like this. we have this declared in a separate class used for library purposes.
public static void pauseOpMode(LinearOpmode op, ElapsedTime et, double waitTime){
double startTime = et.milliseconds();
while (op.opModeIsActive() && et.milliseconds() < startTime + waitTime){}
}
Now that this method exists, in our OpMode we can create an Elapsed time Object and pass the necessarry parameters to the function required to pause the OpMode
class someOpMode extends LinearOpMode{
ElapsedTime gameTimer = new ElapsedTime();
#Override
public void RunOpMode(){
//pause program for 5 seconds
pauseOpMode(this,gameTimer,5000);
}
}
The following Java method is meant to print the number i by nLoopsPerSecond times per second for seconds seconds:
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
System.out.println(i++);
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
}
}
With the following call:
test(1000,1);
I expect this method to do the System.out.println(i++); 1,000 times, but I only got 63.
When I try to see how many seconds it actually use per loop with this code
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
System.out.println(System.currentTimeMillis() - currentTime);
}
}
I expect it to print 1 milliseconds each loop, but it prints 15 or 16 milliseconds.
Please suggest what is wrong in my code.
Are you running on Windows, perhaps? System.currentTimeMillis() consults the underlying operating system clock, which is only 60Hz on many versions of Windows.
Try System.nanoTime() since you are not measuring time since the epoch. System.currentTimeMillis vs System.nanoTime
That's probably because the processing takes up some time. The processor does not solely dedicate its time to the execution of your program, it performs several other functions in the background. So you might get different results based on the processor load.
Your output console is not fast enough. You do not mention how you run your test and where the output goes. The speed of the terminal and buffers (not) used will limit how fast can the program output data. If running unbuffered, your program will always have to wait, until the new line is printed on screen. If the console waits for screen redraw and screen is redrawn at 60Hz, you've got your 16ms/line and about 60 lines per second.
Running your code without inner loop inside IntelliJ Idea, I get about 140.000 lines per second (and Idea warns me, that it is not displaying every line, as my output is too fast).
With the inner loop, I get about 800-900 lines. That happens because the process may be scheduled out of cpu, or blocked because of something else, like swapping. (If I simplify a lot, usually desktop OSes schedule in 1ms granularity.)
I am looking for a way to interrupt a loop in Java without multithreading.
public class Foo{
public Foo(){
}
public void bar(long timeLimit) {
long endTime = System.currentTimeMillis() + (timeLimit * 1000);
while (System.currentTimeMillis() < endTime) {
// Some really long and complicated computation
}
}
}
At the moment I realized that which various (System.currentTimeMillis() < timeLimit) calls to check during the computation if there is time left but I guess that eats up some time and I am also facing the problem that if a loop starts in time, the computation might not be done in time.
Amending the timeLimit (let's say only using 40 % of the time) accordingly also does not work, because I cannot predict how long some computations take.
Which options are there?
So I have started using System.currentTimeMillis(); I am trying to test the results between two of my methods. I decided to gut my method so that what it does doesn't get in the way. Basically I am not seeing any change in time. I have something like this:
double start= System.currentTimeMillis();
double end=System.currentTimeMillis();
public void displayMethod()
{
System.out.println("The start time is" + start);
for (ITERATIONS AND STUFF)
{
System.out.format(STUFF BEING PRINTED);
}
System.out.println("The end time is" + end);
double difference = start-end;
System.out.println("The difference " + difference);
}
The idea is that I have a start time, the time between every print out of the statement and the time at the end. Then it is subtracted to show the difference. However there is no difference and all the times are the same. Why is this happening?
I am considering using nanotime but I don't really know how to use that and I have heard that it takes performance hits.
Can anyone tell me why my times are the same and suggest a way to
fix it or give me an alternative route that is suitable gets the
answer?
You're capturing all of the times at the beginning with these lines:
double thetime= System.currentTimeMillis();
double start= System.currentTimeMillis();
double end=System.currentTimeMillis();
You're getting the same times because those lines are executed immediately back to back (and are fast calls so likely happen in less than 1ms)
Adjust your code to:
public void displayMethod()
{
long start= System.currentTimeMillis();
System.out.println("The start time is" + start);
for (ITERATIONS AND STUFF)
{
System.out.format(STUFF BEING PRINTED);
System.out.println(System.currentTimeMillis());
}
long end=System.currentTimeMillis();
System.out.println("The end time is" + end);
double difference = end-start;
System.out.println("The difference " + difference);
}
Notice how the declarations of the variables are moved to the places that they are needed. It's important to note that variable assignment happens at declaration time not at usage time, thus it's important to move the calls to System.currentTimeMillis() to the point at which you want to capture the current time.
Side note: I adjusted the variables to long instead of double, as System.currentTimeMillis() returns a long and there's no reason for a double here.
You are getting all the times at the very beginning. You need to call System.currentTimeMillis() in the place that you want to know the time.
you should call currentTimeMillis minus the start time, where you want to find the total time ran.
I'm making a simple breakout game in OpenGL(-es) on Android. Initially I had the updating of the game's state and the drawing calls in the same loop: onDrawFrame. Now I decided to split up the two, only leaving the rendering calls in onDrawFrame, and the gamestate was managed in another Thread:
public void run() {
Log.d("GameLogicThread", "GameLogicThread started");
final long UPDATE_INTERVAL = 1000000000 / 30;
long endingTime;
int timeElapsed;
long startingTime = System.nanoTime();
while (!running) {// wait for it...
}
while (running) {
endingTime = System.nanoTime();
timeElapsed = (int) (endingTime - startingTime);
Log.d("timeElapsed",Integer.toString(timeElapsed));
if (timeElapsed < UPDATE_INTERVAL-timeElapsed){
try {
Thread.sleep(timeElapsed);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
startingTime = System.nanoTime();
Game.updateGame(timeElapsed);
}
EDIT
I now have changed the code like this ^^, but it still doesn't work correctly..
Is it something in the loop itself that's wrong, or should I look outside (Probably not, since it worked great before moving the code). What should I do?
There are a few logical errors which are pointed out/discussed in the comments below:
endingTime = System.currentTimeMillis();
timeElapsed = (int) (endingTime - startingTime);
// Why is the "elapsed" time being waited? Hmm.
// If *any* wait is being done (I'd recommend sleep(0) for starters)
// it should be the MAXIMUM desired cycle time MINUS the
// currently used cycle time (MINUS some fudge factor).
if (timeElapsed < UPDATE_INTERVAL) // I dislike hanging blocks...
try {
Thread.sleep(timeElapsed);
} catch (InterruptedException e) {
e.printStackTrace();
}
startingTime = System.currentTimeMillis();
// The game needs to know the TOTAL time elapsed since
// the last update, not the time "until before the yield".
// This will likely be passed fictitiously small values as
// it is only time the the LAST updateGame took to run.
Game.updateGame(timeElapsed);
I would never expect to see timeElapsed (passed to updateGame) below say 10ms with sleep(...) and the corrected time calculations.
However, it may not have the required precision (increasing the minimum cycle length to say 1/30 sec, which would result from the fixed math, would make this less important): see Cristian Vrabie's answer for a suggestion on a higher-resolution timer. (There may be some better 3rd-party alternatives designed just for this -- there is in "normal" Java -- I don't program Android ;-)
Happy coding.
The loop doesn't look broken to me. The move to separate threads is definitely a good one or you would have serious problems when the rendering of a frame takes too long.
Have you tried to use nanoTime() for more accuracy?