Really strange bug with collision

Helo,

I’m coding games in java for a while now and for my collision detection,I’ve always use this code to check and it ALWAYS works perfectly.

Recently I changed my computer and after a while of the game running this method stop working. It is driving me crazy becuase I know there’s is nothing actually wrong with the code. I already try to debug it, and if I save my new code to the project while is debuging the collision come back to normal.

Its driving me crazy…
I hope I made myself clear and sorry for my english

Here is the code:

	public static boolean move(int nextx,int nexty)
	{
		
		int w = tiles.length;
		int h = tiles[0].length;
		Rectangle box = new Rectangle(nextx,nexty,32,32);
		int minX = (nextx/32);
		int minY = (nexty/32);
		int maxX = (nextx/32) + 1;
		int maxY = (nexty/32) + 1;
		
		for(int xp = minX; xp <= maxX; xp++)
		{
			for(int yp = minY; yp <= maxY; yp++)
			{
				if(xp < 0 || xp >= w || yp < 0 || yp >= h) continue;

					if(tiles[xp][yp].solid)
					{
						Rectangle box2 = new Rectangle(xp*32,yp*32,32,32);
						if(box.intersects(box2)){
							return false;
						}
					}

				
			}
		}
		
		return true;
	}
		if(right)
		{
			x+=speed;
			if(!World.move(x, y))x-=speed;
		}
		else if(left)
		{
			x-=speed;
			if(!World.move(x, y))x+=speed;
			
		}
		if(up)
		{
			y-=speed;
			if(!World.move(x, y))y+=speed;
			
		}
		else if(down)
		{

			y+=speed;
			if(!World.move(x, y))y-=speed;
			
		}

When I say that if I debug the game and save some content it comes back to normal,it could be anything like

System.out.println(“Hello world”);

Its crazy…

Can you post an MCVE?

Why is that method static?

Im not sure what is a MVC. But by what I read I believe this is the minimal code needed for this case.

As you can see my code is not wrong and the prove for that is it works at least 10-20 seconds and then my player start intersect with the walls for no reason.

It is static because I was testing to see if would make a difference,but it didnt…

I changed the code,but with no results… Im going to show you my 3 class that im using for this simple collision test:

Player.class

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Player implements KeyListener{

	public boolean right,left,up,down;
	
	public int x,y;
	
	private int speed = 2;
	public Player(int x,int y){
		this.x = x;
		this.y = y;
	}
	
	public void tick(){

		if(right)
		{
			if(move(x+speed,y))x+=speed;
		}
		if(left)
		{
			if(move(x-speed,y))x-=speed;
			
		}
		if(up)
		{
			if(move(x,y-speed))y-=speed;
			
		}
		if(down)
		{
			if(move(x,y+speed))y+=speed;
		}

		Camera.x = x - (Game.WIDTH/2);
		Camera.y = y - (Game.HEIGHT/2);

	}
	
	public boolean move(int nextx,int nexty)
	{
		
		int w = World.tiles.length;
		int h = World.tiles[0].length;

		
		for(int xp = (nextx/32); xp <= (nextx/32) + 1; xp++)
		{
			for(int yp = (nexty/32); yp <= (nexty/32) + 1; yp++)
			{
				if(xp < 0 || xp >= w || yp < 0 || yp >= h) continue;

					if(World.tiles[xp][yp] == 1)
					{
						int x1 = xp*32;
						int y1 = yp*32;
						Rectangle player = new Rectangle(nextx,nexty,32,32);
						Rectangle tile = new Rectangle(x1,y1,32,32);
						if(player.intersects(tile)) return false;
					}

				
			}
		}
		
		return true;
	}
	

	
	public void render(Graphics g){
		g.setColor(Color.blue);
		g.fillRect(x - Camera.x, y - Camera.y, 32, 32);
	}

	@Override
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode() == KeyEvent.VK_RIGHT){
			right = true;
		}
		else if(e.getKeyCode() == KeyEvent.VK_LEFT){
			left = true;
		}
		else if(e.getKeyCode() == KeyEvent.VK_UP){
			up = true;
		}
		else if(e.getKeyCode() == KeyEvent.VK_DOWN){
			down = true;
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode() == KeyEvent.VK_RIGHT){
			right = false;
		}
		else if(e.getKeyCode() == KeyEvent.VK_LEFT){
			left = false;
		}
		else if(e.getKeyCode() == KeyEvent.VK_UP){
			up = false;
		}
		else if(e.getKeyCode() == KeyEvent.VK_DOWN){
			down = false;
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {}


	
	
	
	
}


World.class

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class World {

	public static byte[][] tiles;
	
	public World(String path){
		try {
			BufferedImage bitmap = ImageIO.read(getClass().getResource(path));
			int w = bitmap.getWidth();
			int h = bitmap.getHeight();
			tiles = new byte[w][h];
			int pixels[] = new int[w*h];
			bitmap.getRGB(0, 0,w,h,pixels,0,w);
			
			for(int x = 0; x < w; x++)
			{
				for(int y = 0; y < h; y++){
					if(pixels[x+(y*w)] == 0xFFFFFFFF)
					{
						//Grass
						tiles[x][y] = 0;
					}else if(pixels[x+(y*w)] == 0xFFFF0000)
					{
						//Enemy
						tiles[x][y] = 0;
					}else if(pixels[x+(y*w)] == 0xFF0000FF)
					{
						//Player
						tiles[x][y] = 0;
						Game.player.x = x*32;
						Game.player.y = y*32;
					}else
					{
						//Wall
						tiles[x][y] = 1;
					}
				}
			}
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	
		
		
	}
	


	
	public void render(Graphics g){
		
		int minX = Camera.x / 32;
		int minY = Camera.y / 32;
		
		int maxX = (Camera.x / 32) + (Game.WIDTH / 32);
		int maxY = (Camera.y / 32) + (Game.HEIGHT / 32);
		
		for(int x = minX; x <= maxX; x++){
			for(int y = minY; y <= maxY; y++){
				if(x >= 0 && x < tiles.length && y >= 0 && y < tiles[0].length){
				if(tiles[x][y] == 0)
				{
					g.setColor(Color.red);
					g.fillRect(x*32 - Camera.x,y*32 - Camera.y,32,32);
				}else if(tiles[x][y] == 1){
					g.setColor(Color.gray);
					g.fillRect(x*32 - Camera.x,y*32 - Camera.y,32,32);
				}
				}
			}
		}
	}
	

}

Game.class

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;


public class Game extends Canvas implements Runnable{
	
	private static final long serialVersionUID = 1L;
	public static final int WIDTH = 480, HEIGHT = 480;
	public static final String TITLE = "Simple test";
	public static final Dimension DIM = new Dimension(WIDTH, HEIGHT);
	private static boolean running = false;
	private Thread thread;
	
	public static Player player;
	public static World world;
	
	
	public Game(){
		setPreferredSize(DIM);
		setMaximumSize(DIM);
		setMinimumSize(DIM);
	
		new Camera();
		player = new Player(0,0);
		world = new World("/level1.png");

		addKeyListener(player);
		
	}

	public void tick(){
		player.tick();

	}
	
	public void render(){
		BufferStrategy bs = this.getBufferStrategy();
		if(bs == null){
			createBufferStrategy(2);
			requestFocus();
			return;
		}
		Graphics g = bs.getDrawGraphics();
		g.clearRect(0, 0, Game.WIDTH, Game.HEIGHT);
		g.setColor(Color.green);
		g.fillRect(0, 0, WIDTH, HEIGHT);
		world.render(g);
		player.render(g);
		bs.show();
		g.dispose();
	}
	

	public void run(){
	
		long lastTime = System.nanoTime();
		final double amountOfTicks = 60.0;
		double ns = 1000000000 / amountOfTicks;
		double delta = 0;
		int fps = 0,ups = 0;
		double timer = System.currentTimeMillis();
		while(running){
			long now = System.nanoTime();
			delta += (now - lastTime) / ns;
			lastTime = now;
			if(delta >= 1){
				tick();
				delta--;
				ups++;
				render();
				fps++;
			}

			if(System.currentTimeMillis() - timer >= 1000){
				timer+=1000;
				System.out.println("FPS: " + fps + " UPS: " + ups);
				fps = 0;
				ups = 0;
			}
		}
		stop();
	}
	
	public synchronized void start(){
		if(running)
			return;
		running = true;
		thread = new Thread(this);
		thread.start();
	}
	
	public synchronized void stop(){
		if(!running)
			return;
		running = false;
	}
	
	public static void main(String[] args){
		Game game = new Game();
		JFrame frame = new JFrame(TITLE);
		frame.add(game);
		frame.setResizable(false);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

		
		game.start();
	}
	
}

OBS: I know Im using to much static and it is not prety code…

Minimal, Complete, and Verifiable example. It’s in the link he gave you… What you’re giving us is certainly not minimal.

Seriously if you dont know how to help, do not spawn!

When I first open the topic my example was pretty short and had all u need to test the code and try to help me…

Then he sent me the link and I prefer to share with you all my 3 class for you can see the bug by yourself…

If I’m wrong,I honestly dont know how to post a ‘Minimal’ code…

Im sorry

dont worry. maybe you can strip it down so it just contains a very very simple block which creates the issue.

with that much code it’s hard for everybody to figure it out. also when you strip it, you’ll probably solve it by yourself :wink:

Never mind,I fixed… That was the most weird bug I ve seen :slight_smile:

Thank you ALL for the BIG help

Awesome. :slight_smile:

Out of curiosity, what was the bug you had? It’d help to know what type of issues people are running in to.

@guigui768 it is hard for everybody here to help, if you don’t show us the actual problem. You only said, that there is a bug in your collision detection, but it is important to know the result of the bug. Is it tunneling? Then probably your collision detection is non-continuous and your objects are to fast. Or did you get stuck at some corners? Then you may take a look at your collision response.
So please always think, that we don’t have the knowledge of your project, you have. We don’t know your goal, we don’t know the structure and we don’t know the exact bug. So give us as much informations as possible, but try to avoid giving us unnecessary informations.

But well, you solved your problem, so everything is fine now. Maybe you could tell us what the bug was?

Learn to use the debugger in your IDE, it can help a whole bunch. By minimal they mean try and find the bit of code that is causing the problem, if you don’t know the problem then compare the actual result with your expected result. So if something is supposed to return a specific value, or set a specific field, check if those are what you expect.


Yes,I know how to use the debugger and actually helps a lot,you are absolutely right
When I first create the topic I believe the code I’ve posted was minimal…

About the bug,here is what was happening,but a few things first:

  • It is not even a game,I was only testing some codes and implemented a collision to continue my tests.
  • There isn’t entities in the game. It is only the player and walls.
  • I dont have a huge code,it is only the 3 class I’ve posted with basically funcionality.

Correct if I’m wrong but I do believe this is a Java bug.Heres why

When I run my project I don’t intersect with the walls,the collision works perfectly! About 2 minutes or less if I press the keys to fast, the collision with some tiles stop working.What I mean by stop working is that I can go through the walls(solid tiles).

For me it dosn’t make any sense because I dont change my speed,or change the tiles during the game. When I was running in debug mode,if I made some change in the code and save, the collision comes back to normal.This is so weird right?

If Im running in the debug mode and save a simple

System.out.println("hello world");

it comes back to normal.

What I tried during my tests was:

  • Insted of using byte for the tiles I created a specifically class.

  • Stop using rectangle for the collision,and actually create a collision code that was pretty much the same code of Rectangle.class…

  • Change to static…

Of course this dosnt make sense,but this bug also does not!
So after a lot of tests I was almost giving up just for fun I change this:

public boolean move(int nextx,int nexty)
   {
      
      int w = World.tiles.length;
      int h = World.tiles[0].length;

      
      for(int xp = (nextx/32); xp <= (nextx/32) + 1; xp++)
      {
         for(int yp = (nexty/32); yp <= (nexty/32) + 1; yp++)
         {
            if(xp < 0 || xp >= w || yp < 0 || yp >= h) continue;

               if(World.tiles[xp][yp] == 1)
               {
                  int x1 = xp*32;
                  int y1 = yp*32;
                  Rectangle player = new Rectangle(nextx,nexty,32,32);
                  Rectangle tile = new Rectangle(x1,y1,32,32);
                  if(player.intersects(tile)) return false;
               }

            
         }
      }
      
      return true;
   }

for this:

public boolean move(int nextx,int nexty)
   {
      
      int w = World.tiles.length;
      int h = World.tiles[0].length;

      
      for(int yp = (nexty/32); xp <= (nexty/32) + 1; yp++)
      {
         for(int xp = (nextx/32); yp <= (nextx/32) + 1; xp++)
         {
            if(xp < 0 || xp >= w || yp < 0 || yp >= h) continue;

               if(World.tiles[xp][yp] == 1)
               {
                  int x1 = xp*32;
                  int y1 = yp*32;
                  Rectangle player = new Rectangle(nextx,nexty,32,32);
                  Rectangle tile = new Rectangle(x1,y1,32,32);
                  if(player.intersects(tile)) return false;
               }

            
         }
      }
      
      return true;
   }

And it works!
As you can see I only change the order in the loop.
I would really appreciate if some of you test the first collision code I posted and the second one(where I only change the order) and tell me if this actually a JAVA bug or the problem is only here…

Thanks guys

We’re asking for an MCVE (<-- that’s a link, click it) because all you’re asking us to do is debug your code for you. We can’t do that without seeing how your code actually runs- but we also can’t do that if you include a bunch of extra code that has nothing to do with the actual problem.

As a programmer, it’s your job to isolate the problem in as few lines as possible. This is a very important skill to pick up, and you do it by using print statements, or a debugger, or just walking through your code with a piece of paper and a pencil, to figure out when the program’s execution differs from your expectations. You’re asking us to do that for you, when really, you should be learning how to do it yourself.

And that’s not to say you shouldn’t ask questions- in fact, that’s why we’re asking for an MCVE in the first place. Once you’ve isolated the problem you can ask questions like “I was expecting this line to do XYZ, but it did ABC instead, what’s going on?”, and if you post it as an MCVE, you’ll generally get an answer within a couple minutes.

We’re doing this for free, in our spare time. Shouldn’t you make it as easy as possible for us to help you? Instead of telling us “not to spawn” if we don’t know how to help, why not help us help you?

Also, I guarantee it’s not a “Java bug”.

You are absolutely right…
Haven’t you readed the post I made before yours?

Looking at the change you made and how it affected the code working or not, I can tell you for certain that it’s not a java bug.

In fact, it looks like you are sending a y value for nextx and an x value for nexty. Do some System.out.println checks in the method and see if my thoughts are correct.

FYI: The bugs actually in the java programming API are found by professionals using lesser-known parts of java, not someone using trivial things like a for loop.

And actually, your change that ‘worked’ should not even have compiled. You can’t use a variable in the outer for loop that is created in the inner for loop.

in all the years i found just one bug in the java API … and then i found out folks at sun found it before me :o

as CopyableCougar4 says, the last code snip cannot compile. the outer loop tests for [icode]xp <= (nexty/32)[/icode] which is defined in the inner loop. even your IDE should nag about that.

Hahaha I know you are right…

But in my IDE it is not like that…

That error I made here in the forum when I copied the code and made the change here because I didnt want to open my IDE…

But there is correct the loop. And I only change the orders

I did not look at the code, but if it works at the beginning and does not work after a few minutes, then the problem is might be the garbage collector which slows down the game a bit and causes tunneling, cause of non-continuous collision detection.

[quote]as CopyableCougar4 says, the last code snip cannot compile. the outer loop tests for
xp <= (nexty/32)
which is defined in the inner loop. even your IDE should nag about that.
[/quote]
looking at the programming style, i would’nt wonder if it’s also defined as an static instance variable…

Okay,I know the code is really ugly but this dosn’t mean it shouldn’t work,right?

So after a lot of tests yesterday,I simply reinstall Java and guess what?

Works like a charm with my inital code…

That’s probably because you changed something and didn’t run what you thought you were running.

If you truly think you found a “Java bug”, then post an MCVE along with exactly what happens in each version of Java.