Collision detection and Thread.sleep()

I\m trying to create a simple platformer and trying to do collision detection with platforms. Also using the following gameloop “run()”. Unfortunately when I try to match player (x, y) coordinates with platforms (x, y) coordinates, because of Thread.sleep(10) (I think, but not sure.), the character skips it like 9/10 times and no collision happens.

If I remove Thread.sleep(), collision happens accurately, but when I move my character, he starts moving with immense speed. Could anyone please advise how to account for this?


public void run(){
        long previous = 0, start = 0;
        double delta = 1;
        
         while(true){
            start = System.nanoTime(); 
            
            if(previous != 0){
                delta = start - previous;
            }  
            
            doGameUpdates(delta); 
            
            
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            
            previous = start;
            repaint();
        }        
    }

private void doGameUpdates(double delta){
        
        
        for(Platform p : plats){
            if(player.collidesWithPlatform(p)==true){
               //Do something
            }
        }
        player.Move(delta);
        
    }

That’s not how you should do interpolation (delta time).

Please, do yourself a favor and read this article from beginning to end. It also goes over how to correctly do delta time.

http://www.java-gaming.org/index.php?topic=24220.0

Delta is a relational value (In other words a decimal value that you multiply). In an ideal game the delta value would be 1.0 all the time. Anyway, the article explains it much better!

It looks like you’re doing movement updates based on a time delta, which kicks over every hundredth of a second.
And as you pointed out, running the loop without a sleep timer goes much faster. This also means you’ll be running a lot more collision checks in a short span of time. It also means your delta time would be significantly less.

What you’re seeing is a hopping issue, though it’s likely not as noticeable. Your character is moving a much larger distance in between checking the collision, because a lot more time has elapsed between collision checks.

A Simplified Example:
Your point of collision is at 0,0
Your character is falling from a position of 0,10

In the non-sleep version of the game loop, your character falls at -0.1y every cycle.
In the sleep version, the character falls at -1.5y every cycle.

If we were to check when chracter.y == 0, we would never encounter it in the second version.

Solution
It’s possible your bounds for collision may be too small, or you may need to calculate the penetration value of a collision and adjust for that.
Think like a character encountering a border. Instead of letting them transition beyond the border, we move them back to a place where they’re within the border.

edit: Also what JonJava said.

I did look at that and tried to implement the variable step, but simplified it, since I thought that it would’ve been good enough for my simple game. I guess I will try again. Thanks for the tip!

So, I’ve updated my code and it seems to be working, eg. character is now always hitting the platforms when on his way down (except for a minor glitch). Could someone please comment whether this is any better/good?

The minor glitch is that I see my character warp a few pixels up/down, depending on which way he is jumping, every few seconds.

Game class:


public void run(){
        long lastLoopTime = System.nanoTime();
        final int TARGET_FPS = 60;
        final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;      
        
        while (gameRunning)
        {
            long now = System.nanoTime();
            long updateLength = now - lastLoopTime;
            lastLoopTime = now;
            double delta = updateLength / ((double)OPTIMAL_TIME);
            doGameUpdates(delta, OPTIMAL_TIME);
            repaint();

            try{
                Thread.sleep( Math.abs(lastLoopTime-System.nanoTime() + OPTIMAL_TIME)/1000000 );
              } catch (InterruptedException e) {
                      e.printStackTrace();
              }
        }
}


private void doGameUpdates(double delta, long OPTIMAL_TIME){
        
        for(Platform p : plats){
            if(player.collidesWithPlatform(p)== true && !player.getIfJumping()){
                player.setFloor(p.getY()-player.getHeight());
                break;
            } 
            else {
                player.setFloor(500);
            } 
        }
        
        player.Move(delta, OPTIMAL_TIME);
}  
    

Excerpt of Player class:


public void Move(double delta, long time) {
...

if(y >= floor){
            jumping = true;
            yVelocity = yVelocity * (-1);
            y -= yVelocity * delta * time/1000000000;
        } else{
            yVelocity += gravity;
            y -= yVelocity * delta * time/1000000000;
            
            if(yVelocity <= 0){
                jumping = false;
            }
        }
...
}

public boolean collidesWithPlatform(Platform platform){
        
        if( ((int)this.getY() + this.getHeight()) <= (platform.getY() + 10)
                && (int)this.getX() + this.getWidth() >= platform.getX() 
                && (int)this.getX() <= (platform.getX() + platform.getWidth()) ){
            return true;
        }
        return false;
}

First of all, why are you passing in OPTIMAL_TIME into our update method and using it as a second delta value?

y -= yVelocity * delta * time/1000000000;

Don’t do that. Also, you should multiply delta with ALL values that you use. That’s one of the things you need to remember and be careful with when you’re using variable time steps. In other words, you should multiply with delta when you’re adding the gravity to your ySpeed:


if(y >= floor){
            jumping = true;
            yVelocity = yVelocity * (-1); /* This line looks odd. */
--          y -= yVelocity * delta * time/1000000000;
++          y -= yVelocity * delta;
        } else{
--            yVelocity += gravity;
++            yVelocity += gravity * delta;
--            y -= yVelocity * delta * time/1000000000;
++            y -= yVelocity * delta;
            
            if(yVelocity <= 0){
                jumping = false;
            }
        }

*Line 3 looks a bit odd. Why is it there?

Well, I figured that I need the time of the update/frame, so I used optimal time for each frame. If I remove that piece “time/100000000”, and try your solution, the character starts jumping super super fast and also jumps through platforms. So I don’t really know how to fix that if I remove “time/100000000”.

Line 3 means that when the character comes down from a jump, he jumps back up with same velocity as he came down, eg. character is constantly jumping. Velocity only gradually slows down and gets near zero towards the peak of the jump.

What’s the value of your gravity constant?

gravity = -9.81

If I make the changes that you proposed and decrease/increase gravity, the character still jumps faster than I need and most of the time through the platforms.

Well, the issue here seems like your gravity constant is way too high! Look at your code that changes yPosition:

y -= yVelocity * delta;

If, ideally, delta 1.0 it won’t have any effect (usually delta is pretty close to 1,0). You’re essentially adding HUGE amounts of pixels changes to your y position since the you are adding the gravity of almost 10 to your yVelocity. In just two steps of your game loop yVelocity would be about 20 and you’d be going up or down in y position 20 pixels at a time. in 3 steps you’d be going 30 pixels. Each step is just 1/60th of a second.

Change gravity to

gravity = -0.0981;

and play around with it until you get it right. It doesn’t need to be similar to the g we have here on earth. I usually go with around 0.2 for gravity.

When I lower my gravity, the height of the jump increases. with a gravity less than 1 the character jumps out of the screen :frowning:

Yeah you just need to lower your jump speed. Possible also make the bounce come to a stop with something like:

//bounce
jumping = true;
yVelocity = -(yVelocity * 0.7);

Yea, you’re exactly right, I just needed to lower the yVelocity that was set in the constructor. Now it works, except for the minor warping glitch I mentioned. Thanks a lot for your help, and also the Bounce tip!!!

I suspect the warp glitching has something to do with how you’re rendering the sprite. If you’re rendering exactly based on the x and y values and your x and y values happen to be double’s then you’d probably want to cast them as int’s before you render. Something like this:

draw(myImage, (int) x, (int) y);

Casting them as int’s basically just gets rid of all the numbers after the decimal.

e.g: 5.623 becomes 5 and 3.002133 becomes 3 and 54.91283 becomes 54. If you don’t do that you would be trying to render sort of in between pixels and 3.54356 would be rounded up to 4 and 3.4566 would be rounded down to 3. When you cast them as int’s you are always consistently rounding them down (same effect as calling Math.floor(double value)).

I am actually casting them as int, because the function that I draw with doesn’t take anything else as parameters:


graphics.drawImage(img, (int)x, (int)y, null);

Can’t really say what’s going wrong without seeing it or the code really. Perhaps your delta value is fluctuating erratically because of inconsistent Thread.sleep() times so that you get jerky movement? Just guessing here.

Yea, you are right again. if I change this:


Thread.sleep( Math.abs(lastLoopTime-System.nanoTime() + OPTIMAL_TIME)/1000000 );

To for example:


Thread.sleep( 10 );

then there is no warping, at least as far as I can see. Is it then better to use just a constant value instead of the first example of code?

Possibly. That Thread.sleep() method looks very wonky and I wouldn’t use it :V

But that’s the beauty of variable time steps. Running at consistent speed regardless of how much FPS you have. In other words, if you change that to Thread.sleep(5) the game will run just as fast except it will be less jerky. Or if you change it to Thread.sleep(20) it will still be just as fast but more jerky.

That said though, I’ve almost never used variable time step for anything. Fixed time step is all one mostly ever needs in my opinion. That doesn’t mean one is better than the other - they’re just different.

Ok, I understand. Thank you very much for all your help and explanations! I have learned a lot in these two days :slight_smile: I will have to look into fixed time step next then. Thanks again!!!