I want to create a start menue for a Pong clone where the ball in the background bounces off the edges. However the game loop updates to fast so the Coordinates of the ball are already out of the JFrame before you can see it and it moves to fast. I found that through sysouts.
I guess it has something to do with threads but I am not sure.
The main class calls this Class as a thread but the important part is in the class BackgroundBallMovement
package main;
public class BackgroundBallMovement implements Runnable{
private boolean running = true;
#Override
public void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60;
double delta = 0;
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
}
//Spiellogik updaten
private synchronized void update() {
Var.ballX += 1;
Var.ballY += 1;
}
//Objekte zeichnen
private synchronized void render() {
Var.drawStartMenue.repaint();
}
}
You're not using Thread.sleep(). Instead you are waiting until System.nanoTime() changed. This means that the CPU is running all the time (not good).
Also this loop:
while(delta >= 1) {
...
delta = 0;
...
}
doesn't make sense because it could be replaced by an if.
Then you are never updating the lastTime variable. So this line:
delta += (now - lastTime) / ns;
will result in a quadratic function because it will result in something like this (each loop execution):
delta += 0.1;
delta += 0.2;
delta += 0.3;
...
Then because you are never updating the lastTime variable after 1s the condition
while(delta >= 1)
will always be met and your ball will move incredibly fast.
Your first approach could be something like this:
#Override
public void run()
{
while(running)
{
update();
render()
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
Thread.sleep(1000L/60L);
}
}
That's because your math sucks ;-)
Yes, (now - lastTime) / ns is the amount of frames that should have been rendered since the engine started. Therefore your code simplifies to:
while (true) {
delta = framesSinceStart();
while (delta >= 1) {
renderFrame();
delta = 0;
}
}
which is equivalent to
while (true) {
if (framesSinceStart() >= 1) {
renderFrame();
}
}
That is, your code correctly waits to render the first frame, but doesn't record that it has rendered that frame, and therefore always thinks it is late, and never waits anymore.
Instead, you might try something like:
while (true) {
if (framesSinceStart() - framesRendered >= 1) {
renderFrame();
framesRendered++;
}
}
Btw, simply staying in an endless loop to spend time is not very power efficient. It would be better to use something like Thread.sleep() to wait - but calculating the time it should be waiting by hand is a little hairy. Fortunately, the Java API comes with nice helper classes to use:
ThreadPoolExecutor executor = Executors.newSingleThreadExecutor();
executor.scheduleAtFixedRate(() -> renderFrame(), 0, 1000 / 60, TimeUnit.ms);
Try Thread.sleep(long millis)
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
try{
Thread.sleep(1000);
} catch(Exception e) { }
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
another thing you can try is reducing the ball speed.
private synchronized void update() {
Var.ballX += 0.01;
Var.ballY += 0.01;
}
Related
I have 2 integer values, let's say int a = 5 and int b = 4.
public static void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60.0;//60 times per second
double delta = 0;
while(running) {
long now = System.nanoTime();
delta = delta + ((now-lastTime) / ns);
lastTime = now;
while (delta >= 1)//Make sure update is only happening 60 times a second
{
delta--;
}
}
What I want to achieve is to be able to change values of the integers within the while (delta >= 1){} every second to a number between 100 and 400. I want to create a paint method that takes the values of the integers and updates the component sizes within my JFrame. I just need an idea to go with, so I can move on.
I'm not sure if I fully understood your question. However, if your intention is to run a bit of code 60 times per second, there is definitely an easier way to accomplish this - via Java's Thread.sleep() mechanism. You can use Java's Random class to actually generate random values for a and b:
public static void run() {
Random random = new Random();
while (running) {
try {
Thread.sleep(16); // 16 millisecond sleep; will run 60 times per second
// Generate random number between 100 and 400
a = (random.nextInt() % 300) + 100;
b = (random.nextInt() % 300) + 100;
} catch (Exception e) {
System.out.println("Exception encountered when trying to sleep! " + e.toString());
}
}
}
Alternatively, you can also use Java's Timer and TimerTask classes to the same effect.
I've been struggling with an app for fall detection for quite some time now. The app runs, but it will freeze up at times, and then resume 10-15 seconds after.
My approach is to do integral calculations (which means I had to import a third party library: Apache Commons). For these integral calculations I need norm values.
I'm calling a method for calculating the norm when the sensor updates:
public void onSensorChanged(SensorEvent event){
acceleration.setText("\n " + event.values[0] + " , " + event.values[1] + " , " + event.values[2] + " \n");
x = event.values[0];
y = event.values[1];
z = event.values[2];
if (!checkFall)
sample(x, y, z);
}
calling the sample function makes the app run slow (visible through setting text on UI).
Sample which is seemingly the root of my problems looks like this:
private void sample(double x, double y, double z)
{
if(xList.size() < 120 && yList.size() < 120 && zList.size() < 120)
{
xList.add(x);
yList.add(y);
zList.add(z);
}
if(xList.size() == 120)
{
for (int j = 0; j < norm.length; j++)
{
norm[j] = sqrt(pow(xList.get(j), 2) + pow(yList.get(j), 2) + pow(zList.get(j), 2));
for(int p = 0; p < norm.length-1; p++)
{
for(int q = 0; q < diff.length; q++)
{
diff[q] = norm[p] - norm[p+1];
}
}
if (norm[j]/9.81 < 0.5)
{
final counterClass timer = new counterClass(4000, 20, norm, diff);
checkFall = true;
timer.start();
// if exceeded three times, save the arrayList and register fall
}
}
(I've tried disabling the timer call when the if statement norm[j]/9.81 < 0.5 has been met, because I thought the error may be in a function that a countdown timer is calling) - but to no help, the app freezes whenever the norm approaches 0.
There are no obvious errors in the logcat, which is why I'm having a hard time narrowing down where the error is. Perhaps I'm accessing the arrays in a terrible way?
If there is any missing information you'd like me to provide or if my questions is too vague, please let me know.
EDIT:
Counter Class
public counterClass(long millisInFuture, long countDownInterval, double[] norm, double[] diff) {
super(millisInFuture, countDownInterval); // Duration & how often onTick should be called
nor = norm;
dif = diff;
}
public void onTick(long millisUntilFinished) {
listFall(); // Adding accelerometer data to fall list array List each time its called
new Thread(new Runnable() {
#Override
public void run() {
vCheck(nor,dif);
}
}).start();
}
I'm following a tutorial and below is the run method to generate logic and frame updates. I understand how the ticks are updated 60 ticks/second but I don't understand how we adjust frame per second here.
Right now with Thread.sleep(2), frame per second is around 460. Without it the numbers go way up, around 10 million updates per second. The code Thread.sleep(2) suspends the thread for only 2 milliseconds right? Why/how does Thread.sleep exactly work here to drop it so low?
Isn't it simpler to create a nsPerFrame = 1000000000D/ (FPS)D to set whatever FPS I want the way he did with ticks?
public void run(){
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
while(delta >= 1){
ticks++;
tick();
delta-= 1;
}
try{
Thread.sleep(2);
} catch(InterruptedException e){
e.printStackTrace();
}
frames++;
render();
if(System.currentTimeMillis() - lastTimer >= 1000){
lastTimer += 1000;
System.out.println(ticks + "," + frames);
frames = 0;
ticks = 0;
}
}
}
Well sleep(2) is called repeatedly in your running-loop so the hard upper limit in this case is 500 cycles per second (1000 ms divided by 2 ms), and your measured 460 fps is pretty close to that.
Sure enough you can adjust the sleep duration according to your needs and if needed stuff it into the somewhat higher-precision method Thread#sleep(long, int) where the second parameter is "nanos" (take a look at the docu for caveats!).
The formula for your case is FPS = 1000 ms / sleep duration in ms. From which follows: sleep duration in ms = 1000 ms / FPS.
i'm having a tremendous difficulty understanding a piece of code that controls a loop of a game... I can't understand the purpose of this while loop "while(unprocessedSeconds > secondsForEachTick)" and why the FPS counter if inside of that if(tickCounter % 60 ==0) like follows on code:
public void run()
{
int frames = 0;
double unprocessedSeconds = 0;
long previousTime = System.nanoTime();
double secondsForEachTick = 1/60.0;
int tickCount = 0; //RENDER COUNTER
boolean ticked = false;
while (running)
{
long currentTime = System.nanoTime();
long passedTime = currentTime - previousTime;
previousTime = currentTime;
unprocessedSeconds = unprocessedSeconds + passedTime / 1000000000.0;
int count = 0;
while(unprocessedSeconds > secondsForEachTick)
{
tick();
count++;
unprocessedSeconds -= secondsForEachTick;
ticked = true;
tickCount++;
if(tickCount % 60 == 0){
System.out.println(frames + " fps");
previousTime += 1000;
frames = 0;
}
}
System.out.println("Iterações do loop: "+count);
if(ticked)
{
render();
frames++;
ticked = false;
}
}
}
That inner while cycle ensures that the game update is based on fixed time, rather than frame time. The unprocessed time is getting collected and as soon as it is greater than the time frame for one tick, it calles tick().
The TickCount is basically counts the ticks (the tick time is 1/60 sec, so 60 tick/sec), and as soon as it 1 sec elapsed it prints the collected frames (so FPS). Also, ticked signals that something may changed in the game, so a new render is required.
This loop is used to have constant time in game. So if for some reason you get lag, you will do several logic update and one render. I assume tick() performs some logic operations.
To be more precise. For example, you have bullet, and bullet position need to be updated at 0.1s to do proper collision test. If for some reason delta time grows to 0.4s your bullet will fly through walls. To deal with it you performs several iterations with smaller time step, this loop doing it.
I'm trying to keep my game at 60fps, but I'm getting strange results from my code like "2-8000 fps" Why isn't this staying at 60?
public static void main(String[] args) {
joglplat m = new joglplat();
while(true){
long startTime = System.nanoTime() / 1000000;
try
{
// 123456: 6 zeros => 16ms
long nsToSleep = 16000000 - (System.nanoTime() - lastFrame);
System.out.println("ns: " + nsToSleep);
lastFrame = System.nanoTime();
if(nsToSleep > 0)
{
System.out.println("ns2: " + (nsToSleep/1000));
System.out.println("ns3: " + (nsToSleep%1000));
Thread.sleep(nsToSleep/16000000, (int)(nsToSleep % 1000));
}
else
{
Thread.yield(); // Only necessary if you want to guarantee that
// the thread yields the CPU between every frame
}
}
catch(Exception e){
e.printStackTrace();
}
m.controls();
m.update();
m.repaint();
System.out.println("framerate: " + (System.nanoTime() / 1000000 - startTime));
}
}
Your output is the number of seconds your program has run for, not framerate. You should be dividing your frame count (which you aren't collecting) by the total time run.
To get the frame count, simply add a new variable outside of your game loop, and increment it each time through...
public static void main(String[] args) {
long frames = 0;
joglplat m = new joglplat();
while(true){
frames++;
// other code here
System.out.println("framerate: " + ((System.nanoTime() / 1000000 - startTime) / frames ) );
}
}
Note, however, that this will give you the average framerate throughout the entire execution of your program. Two other options you have are to get the instantaneous framerate, and the average framerate over the past N frames.
All styles in one (untested/uncompiled, so might have some errors, but should get you started in the right direction):
public static void main(String[] args) {
long startTime = System.nanoTime();
long lastFrameTime = startTime;
long frames = 0;
int framesToAverage = 10;
long[] frameTimes = new long[framesToAverage];
joglplat m = new joglplat();
while(true){
// logic here
long currentFrameDuration = System.nanoTime() - lastFrame;
lastFrameTime = System.nanoTime();
long instantFramerate = currentFrameDuration / 1000000;
int currentFrameIndex = frames % frameTimes.length;
frameTimes[currentFrameIndex] = currentFrameDuration;
frames++;
long averageFramerate = ( ( lastFrameTime - startTime) / frames ) / 1000000;
long instantFramerate = currentFrameDuration / 1000000;
if( frames > frameTimes.length ) { // if it isn't, we don't have enough data yet
int firstFrameIndex = currentFrameIndex + 1;
if( firstFrameIndex > frameTimes.length ) {
firstFrameIndex = 0;
}
long averageFrameratePerN = ( ( frameTimes[currentFrameIndex] - frameTimes[firstFrameindex] ) / frameTimes.length ) / 1000000;
}
// yield/sleep here
}
}
My suspicion is that this is caused by the inaccuracy of Thread.sleep():
Causes the currently executing thread
to sleep (cease execution) for the
specified number of milliseconds plus
the specified number of nanoseconds,
subject to the precision and accuracy
of system timers and schedulers. The
thread does not lose ownership of any
monitors.
Is there any reason why you have to hold the framerate down like this? Perhaps you can explain more fully what you are trying to accomplish?