So I've been trying to figure out what's wrong with my code, but I've had basically no luck when it comes to finding what's wrong. I've seen plenty of folks who had similar issues but none of the fixes that were suggested helped with my problem.
I've made a video showcasing my problem, but I'll give an explanation here too: whenever I move on the screen, the tiles in my game engine don't sync up with each other in terms of positioning, and it seems to be only on the rendering end. When I do any sort of checks to see if the distance between two tiles changes, I don't get any sort of errors. I get these gaps between the tiles specifically when I'm moving up or left, and they instead merge slightly when I move down or right, as if some of the tiles are updating faster than the others.
I don't want to just start dumping my couple thousand lines of code here since that won't really help anyone, but I'm also not well versed in the game development world, so I'm not entirely sure what pieces of code are super relevant here. If there's anything that y'all would like to see, let me know and I'll happily provide it.
The main method and postInit looks like this:
public static void main (String[] args)
{
EventQueue.invokeLater(() ->{
ex = new ShootyGame();
ex.dispose();
ex.setLayout(null);
ex.setUndecorated(Settings.isFullscreen);
ex.setVisible(true);
ex.setCursor(ex.getToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), new Point(), null)); //hides the system cursor
ex.createBufferStrategy(2);
postInit();
});
}
private static void postInit()
{
//add a window listener to the main JFrame
ex.addWindowListener(new WindowAdapter()
{
/**
* Autosaves when the window is closed, then kills the game.
*/
@Override
public void windowClosing(WindowEvent e)
{
//TODO autosaving
kill();
}
});
render.start(); //these are just the two threads being started
run.start();
}
My two threads, which basically just run the step and render methods in my game class:
private static class Running extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("B");
}
game.step();
}
}
}
private static class Render extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("A");
}
game.render();
}
}
}
The run method in my Game class just calls the current character's step method (it'll call more later), which is what's directly used to move the Camera class' x and y position. The character step looks like this:
public void step()
{
this.calculateMove(); //gets info on which keys are being pressed, adds or subtracts an integer from dx and dy (which are also ints) based on which are being pressed
Game.cam.update(-this.dx, -this.dy); //sends the opposite movement to the camera
//change the position of the player character by the appropriate x and y amounts
this.changeX(this.dx);
this.changeY(this.dy);
this.reset(); //just sets dx and dy back to 0 after moving
}
And now to the rendering stuff here's the entire camera class since it's probably the most relevant class:
public class Camera
{
private int x;
private int y;
public Camera(int x, int y)
{
this.x = x;
this.y = y;
}
public void update(int dx, int dy)
{
moveX(dx);
moveY(dy);
}
public void moveX(int dx)
{
this.x += dx;
}
public void moveY(int dy)
{
this.y += dy;
}
/**
* Gets the top left corner of the camera's x position.
* @return The x position of the top left corner of the camera
*/
public int getCamX()
{
return this.x;
}
/**
* Gets the top left corner of the camera's y position.
* @return The y position of the top left corner of the camera
*/
public int getCamY()
{
return this.y;
}
}
And finally, the relevant code for the actual painting of the tiles:
public void render() //this is the part that the render thread calls initially
{
Toolkit.getDefaultToolkit().sync();
repaint();
}
public void paint(Graphics g) //the paint method, mostly handled in doDrawing
{
super.paint(g);
doDrawing(g);
}
private void doDrawing(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
//stuff that happens if the game isn't paused
if(!GameStates.isPaused)
{
currentMap.drawMap(g2d, this);
currentChar.draw(g2d, this);
}
}
public void drawMap(Graphics2D g2d, ImageObserver observer)
{
//for each tile in the map, call its draw method
for(int i = 0; i < this.tileArray.length; i++)
{
for(int j = 0; j < this.tileArray[0].length; j++)
{
this.tileArray[i][j].draw(g2d, observer);
}
}
}
public void draw(Graphics2D g2d, ImageObserver observer, BufferedImage image)
{
g2d.drawImage(image, this.getX() + Game.cam.getCamX(), this.getY() + Game.cam.getCamY() observer);
}
Sorry for the long winded post, I've just tried everything I can think of (and that my Googling abilities can help me think of) and I'm throwing this out as a last-ditch effort before I just move to an actual game engine. I wanted to make my own engine from scratch for the sake of getting more experience in Java, but if I can't figure this out I'd rather just move to a proper engine and actually make a game. Any help is massively appreciated :)
EDIT: capitalization