LibGDX Android: Lag with 25+ sprites despite use of TimeKeeping - java

The Problem I have ArrayList of "pellets". I'm pushing around 25 of them and they all bounce. However, for some reason they seem to go faster while render() is slower / takes more time (wut?) Please help me make it so that the 25 sprites smoothly glide about at a constant speed. It also jerks when only 5 sprites are onScreen.
Tried this stuff:
Reading around SO. They recommended getDeltaTime
Gdx.graphics.getDeltaTime() multiplying by pelletSpeed (no Change)
In the current code the pellets hop, jerk, and inconsistently sputter about almost unpredictably. I am assuming that it's going constant speed underneath the hood but honestly it's hard to tell
For Loop in Render:
String currentDir = pelletList.get(i).getDir();
String currentColor = pelletList.get(i).getColor6();
pelletSpeedElapsedTime = TimeUtils.nanoTime();
if(currentDir.equals("Up")) {
pelletList.get(i).y -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y < 0 ) {
pelletList.get(i).setDir("Down");
}
} else if (currentDir.equals("Down")) {
pelletList.get(i).y += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y > screenHeight) {
pelletList.get(i).setDir("Up");
}
} else if (currentDir.equals("Left")) {
pelletList.get(i).x -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x < 0) {
pelletList.get(i).setDir("Right");
}
} else if (currentDir.equals("Right")) {
pelletList.get(i).x += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x > screenWidth) {
pelletList.get(i).setDir("Left");
}
}
Thanks

The pelletSpeedElapsedTime = TimeUtils.nanoTime(); looks suspicious to me - you're getting this time, and then calculating elapsed time for bullets immediately afterward. Almost no time will have elapsed by then, and you won't be accounting at all for whatever time passes before the next call to whatever method this is.
I think (guessing at what the rest of your code is like) that you want to move that pelletSpeedElapsedTime assignment to the end of this method. The idea here is that you want to capture the time where you finished this update, so that the next time you update you know how much time has passed between updates (e.g. time spent rendering, sleeping, whatever.)
Doing this would mean that you'd have to handle the case where pelletSpeedElapsedTime hasn't been initialized, as well (maybe initialize it in the constructor? again, not sure of the broader context.) Also, I don't think all those TimeUtils.timeSinceNanos calls or necessary - I would call that once at the start of this section of code and use the value (to make sure the moving entities all get a consistent time delta, and to avoid the redundant call/calculation.)

Related

Physics update lag

I ran into a problem, where doing everything on a single thread may lead to some lags. The problem is, when I start to create loads of new objects (like 300 per second), my physics rate drops.
I sort all rendering objects each frame, so I would know which one to draw in which order, this might be the reason why it can handle only so little, but even if that was removed, there still would be like max operations per update, otherwise physics will lag.
Any ideas on how to achieve the correct zOrder, or remove possible physics lags?
Or detach physics from rendering ... ?
My game loop:
while (isRunning) {
currentFrameTime = System.nanoTime();
passedTime = currentFrameTime - lastFrameTime;
lastFrameTime = currentFrameTime;
physicsPassedTime += passedTime;
updatePassedTime += passedTime;
if (physicsPassedTime >= (double) 1_000_000_000 / physicsRate) {
physicsPassedTime = 0;
PhysicsUpdate();
}
if (updatePassedTime >= (double) 1_000_000_000 / refreshRate) {
updatePassedTime = 0;
Update();
Render();
LateUpdate();
}
}
Looks like the best solution (as suggested in comments) will be to run a second loop on a second thread with just physics update, and everything else on the other thread.
That way frame drops should not intervene with the physic updates.
Edit: Implemented this, and works like charm. I'll mark the answer when I'll be able to.

How to delay a method's repeated execution?

I'm new to java and I'm trying to constantly add "zombie" entity to my game after a delay, and then shortening the delay as time goes on.
In my PlayState class I've got the code to spawn the entities in a position when my update(); method is run (which houses getInput(); and such. Not shown for clarity.)
public void update(long elapsed) {
this.entities.add(new Zombie(-535));
}
How would i make a delay that shortens? I'm guessing I would make the delay and then use a multiplier which i have getting smaller every 10 seconds or so, but how would I do this?
Now, I don't know much about the finer workings of your class, but this might give you a general idea of what I mean:
int counter = 50;
for(int i = 100; i >= 0; i--)
{
if(i == counter)
{
counter = counter / 2;
this.entities.add(new Zombie(-535));
}
}
Suppose i is the the total run-time of the game, and counter represents a percent of the game when you want to add a zombie.
If you want to add a zombie after 50% of the run-time (here, 100 seconds), then as the time reduces, you check if the time has come to add a zombie (Here, 50 seconds).
What I've done here is reduce the delay to half, and continue checking if the time has come to add a zombie.
Maybe you could call sleep on your thread of execution:
int sleepInMs = 5000
Thread.sleep(sleepInMs);
sleepInMs+=1000; //Then of course handle the case when sleepInMs == 0
Really need more information about your implementation.
For a simple delay, use "delay ms;"
Edit ms for the number of milliseconds you want. 1000 milliseconds is one second

Use of parallels in java shows no increase in performance

I recently embarked on a project to simulate a collection of stellar bodies with the use of LWJGL. The solution required many loop iterations per frame to accomplish. The program calculates the forces exerted on each body by every other body. I did not wish to implement any form of limitations, such as tree algorithms. The program itself is able to simulate 800 bodies of random mass (between 1 and 50) at around 15 fps. Here is the original code for calculating, then updating the position of each body.
public void updateAllBodies() {
for (Body b : bodies) {
for (Body c : bodies) {
if (b != c) {
double[] force = b.getForceFromBody(c, G);
b.velocity[0] += force[0];
b.velocity[1] += force[1];
b.velocity[2] += force[2];
b.updatePosition();
}
}
}
}
Recently I came across the subject of parallels and streams. Seeing that my original code used only one thread, I thought I might be able to improve the performance by converting the array to a stream, and executing it with the use of
.parallelStream()
I don't know much about multi-threading and parallelism, but here is the resulting code that I came up with.
public void updateAllBodies() {
Arrays.asList(bodies).parallelStream().forEach(i -> {
for(Body b: bodies){
if (i != b){
double[] force = i.getForceFromBody(b, G);
i.velocity[0] += force[0];
i.velocity[1] += force[1];
i.velocity[2] += force[2];
i.updatePosition();
}
}
});
}
Unfortunately, when executed, this new code resulted in the same 15 fps as the old one. I was able to confirm that there were 3 concurrent threads running with
Thread.currentThread().getName();
At this point, I have no idea as to what the cause could be. lowering the number of bodies does show a drastic increase in frame rate. Any help will be greatly appreciated.
I cant seem to find a way to mark a comment as the answer to a post, so I will state that the best answer was given by softwarenwebie7331.

Java - add time delay to a cycle flow

I need to add time delay between cycle flow like this:
public boolean timeDelay(int seconds) {
// 1000000000 ns = 1 s
if (/* some system method to start calculate time in seconds*/ == seconds) {
return true;
} else {
return false;
}
}
public void renderEnemies() {
for (int w = 0; w < wave.size(); w++) {
while(timeDelay(2)){
(wave.get(w)).render();
}
}
}
Maybe my thinking isn't good, but I need to do like this...
wave --> ArrayList of enemies in my game
Render enemies is in game loop after pressing button "NextWave" and I need to spawn them with delay between them like a --> 2s * 2s * 2s * 2s * 2s *
where * is enemy...
Can you help me?
Try:
Thread.sleep(1000);
and use a try-catch.
You should probably thread it and use sleep as #curiosu mentions.
However, if you don't want to use sleeps/multiple threads but do want it to be pseudo real time (not turn based) you'll need a driving loop at the top of your game like so:
boolean keepPlaying = true;
while(keepPlaying) {
doNpcStep()
doPlayerStep()
keepPlaying = !isGameOver()
}
Each of these steps needs to run in a very small time slice, then in the doNpcStep function you get the current time, find the offset from a start time and run any action that should happen by now.
You could, for example, do this by keeping a min priority queue where priority is equal to the time they should execute by (in ms since start of java epoch). Then take all elements off the queue that are less than or equal to current time and run them, placing new occurrences onto the queue as necessary.
In essence this is a simulation of running a player and npc thread, where you are in charge of how much time each gets to run for.
try putting an infinite while loop
while(1)
{
if(/*method to calc time*/ == seconds)
return true;
}
return false;
I'm assuming that you want to start spawning enemies after 'seconds' time, so always a 'true' should be returned after 'seconds' time has passed. Your method should keep track from what time it has to start counting the seconds. You can call that function when 'NextWave' button is pressed where a variable can increment itself in multiples of 'seconds' so that you can keep track of elapsed time.
Hope this helps.

How to check if a body has almost stopped moving in libgdx + box2d

So, I have a player body + fixture etc, it is essentially a ball that bounces around.
I want to detect when it is 'pretty much' finished moving.
At the moment I do this:
public Boolean isStopped() {
return body.getLinearVelocity().x <= 0.3f && body.getLinearVelocity().y <= 0.3f;
}
This mostly works, the problem being when the player hits something, there's a split second where its velocity is 0, so this returns true. What I really wanted is to just return true when it is basically finished. Preferably within a range that I can set to whatever I like as I tweak the physics of my game world.
I can't use a check on whether it is sleeping or not as that comes too late, it doesn't sleep until after it has stopped having forces act upon it, I need just before.
I could just store how long it has been stopped/a count of stopped steps, but I was hoping there would be a nice pre existing method that I missed.
Any ideas?
You can keep track of recent movement and update it by mixing in a little of the current speed each time step:
float speedNow = body.getLinearVelocity().len();
recentSpeed = 0.1 * speedNow + 0.9 * recentSpeed;
if ( recentSpeed < someThreshold )
... do something ...
You would need to set recentSpeed to a suitably high value to begin with, otherwise it might be below the threshold in the first time step.
Seeing how you've determined that your false positives are caused by the body making contact with another, why not add a couple of lines in your ContactListener's beginContact method, storing the body's current speed in its user data? Then you can check that speed in your isStopped method. If there is a stored speed and the current speed isn't greater, this means the body is in the process of bouncing off whatever it hit: ignore. If there is a stored speed and the current speed is greater, the ball has bounced and is proceeding in some new direction: clear the stored speed. If there is no stored speed and the current speed is below your threshold, you've detected the sought situation.
In your ContactListener:
public void beginContact(Contact contact) {
Body a = contact.getFixtureA().getBody();
Body b = contact.getFixtureB().getBody();
if (a == mBall) {
a.setUserData(a.getLinearVelocity().len());
} else if (b == mBall) {
b.setUserData(b.getLinearVelocity().len());
}
}
And in your isStopped check:
public Boolean isStopped() {
float storedSpd = (Float) body.getUserData();
float currentSpd = body.getLinearVelocity().len();
if ((storedSpd > Float.MIN_VALUE) && (currentSpd > storedSpd)) {
body.setUserData(Float.MIN_VALUE);
return false;
} else {
return (currentSpd < THRESHOLD);
}
}
This is untested, but you get the idea. Also, remember to initially set the user data to Float.MIN_VALUE.
In the end I have simply passed the delta from each render call to the isStopped() method.
public Boolean isStopped(float delta) {
boolean isMoving = (
Math.abs(body.getLinearVelocity().x) >= 0.25f || Math.abs(body.getLinearVelocity().y) >= 0.25f);
if(isMoving) {
timeStopped = 0f;
return false;
} else {
timeStopped += delta;
return timeStopped >= 0.3f;
}
}
timeStopped is just a class property that starts off as zero. This does return true for the beginning of the game (before the user has made a move) but in my application that is absolutely fine. Besides which, it is true to say it has stopped in that circumstance.
I'd still love to see a way to do this without storing extra crap, since I'm guessing box2d must have this information somewhere in order to figure out if a body with zero velocity has no force acting upon or if it is just changing direction after an impact.

Categories