9

I'm trying to draw isometric tiles in Java and implement a tile picking system using the mouse cursor. I draw the tiles using these math formulas I found and adapted to my tile textures which you can find below. Tiles are 64x64px but flat tiles are only 32px height even if I draw them using the 64x64 sprite.

Tile sheet

The map is a simple 2d array where my tiles are represented by their id.

Here is the class I use to convert map coordinates to screen coordinates using the toIso() function. I pass my screen coordinates which represent the cursor position on the screen to the toGrid() function to convert them to map coordinates.

public class Utils {

private static int TILE_WIDTH = Tile.TILE_WIDTH;
private static int TILE_HEIGHT = Tile.TILE_HEIGHT;

private static int TILE_WIDTH_HALF = TILE_WIDTH/2;
private static int TILE_HEIGHT_HALF = TILE_HEIGHT/2;

private static int TILE_WIDTH_QUARTER = TILE_WIDTH_HALF/2;
private static int TILE_HEIGHT_QUARTER = TILE_HEIGHT_HALF/2;

public static int[] toIso(int x, int y){

    int i = (x - y) * TILE_WIDTH_HALF;
    int j = (x + y) * TILE_HEIGHT_QUARTER;

    //800 and 100 are temporary offsets I apply to center the map.
    i+=800;
    j+=100;
    
    return new int[]{i,j};
}

public static int[] toGrid(int x, int y){

    //800 and 100 are temporary offsets I apply to center the map.
    x-=800;
    y-=100;
    int i = ( x / ( TILE_WIDTH_HALF ) + y / ( TILE_HEIGHT_QUARTER )) / 2;
    int j = ( y / ( TILE_HEIGHT_QUARTER ) - ( x / ( TILE_WIDTH_HALF ))) / 2;
    
    return new int[]{i,j};
}}

I currently render my tiles by using two for loops and converting the map coordinates to screen coordinates using the toIso() function.

public void render(Graphics g){
    for(int x = 0;x<width;x++){
        for(int y = 0;y<height;y++){
            int[] isoCoords = Utils.toIso(x, y);
            int fx = isoCoords[0];//
            int fy = isoCoords[1];//
            if(world[x][y] == 0){
                Tile grass = new GrassTile(0);
                grass.render(g, grass.getId(), fx, fy);
            }else if(world[x][y] == 1){
                Tile water = new WaterTile(1);
                water.render(g, water.getId(), fx, fy);
            }
        }
    }
}

I get a diamond shape as I wanted rendered on the screen.

I finally update each tick which are the actual mouse coordinates on screen.

int[] coords = Utils.toGrid(mouseManager.getMouseX(), mouseManager.getMouseY());
tileX = coords[0];
tileY = coords[1];

The selected tile is finally rendered:

BufferedImage selectedTexture = Assets.selected;
int[] coordsIsoSelected = Utils.toIso(this.tileX, this.tileY);
g.drawImage(selectedTexture, coordsIsoSelected[0], coordsIsoSelected[1], Tile.TILE_WIDTH, Tile.TILE_HEIGHT, null);
    
g.drawRect(Utils.toIso(tileX, tileY)[0], Utils.toIso(tileX, tileY)[1]+Tile.TILE_HEIGHT/2, Tile.TILE_WIDTH, Tile.TILE_HEIGHT/2);//I draw a rectangle to visualize what's happening.

Finally, my tile detection isn't working as expected, it isn't fitting the tiles perfectly, however it seems to be in relation with the rectangle I draw. I can't figure out the solution to this problem, I thank you in advance for reading or any advice you could give to me. If you need more precisions, I would be glad to give you more informations.

Tile picking

Here is a video showing what is actually happening: youtu.be/baCVIfJz2Wo


EDIT:

Here is some of my code you could use to run an application like mine. Sorry for this very messy code, but I tried to make it as short as possible without disturbing the behavior of the "game".

You will need to put the sheet provided before into a "textures" folder created into the ressource folder of the project.

The gfx package:

package fr.romainimberti.isometric.gfx;

import java.awt.image.BufferedImage;


public class Assets {

    private static final int width = 64, height = 64;

    public static BufferedImage grass, water, selected;
    
    public static void init(){
        //Temp
        SpriteSheet tileSheet = new SpriteSheet(ImageLoader.loadImage("/textures/sheet.png"));
    
        grass = tileSheet.crop(width*2, 0, width, height);
        water = tileSheet.crop(width*9, height*5, width, height);
        selected = tileSheet.crop(0, height*5, width, height);
        //
    }
}

package fr.romainimberti.isometric.gfx;

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

import javax.imageio.ImageIO;


public class ImageLoader {

    public static BufferedImage loadImage(String path){
        try {
            return ImageIO.read(ImageLoader.class.getResource(path));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        return null;
    }
}

package fr.romainimberti.isometric.gfx;

import java.awt.image.BufferedImage;

public class SpriteSheet {

    private BufferedImage sheet;

    public SpriteSheet(BufferedImage sheet){
        this.sheet = sheet;
    }

    public BufferedImage crop(int x, int y, int width, int height){
        return sheet.getSubimage(x, y, width, height);
    }
}

The rest of the project:

package fr.romainimberti.isometric;

public class Launcher {

    public static void main(String args[]){
        System.setProperty("sun.awt.noerasebackground", "true");
        Game game = new Game("Isometric", 1280, 720);
        game.start();
    }
}

package fr.romainimberti.isometric;

import java.awt.Canvas;
import java.awt.Dimension;

import javax.swing.JFrame;

public class Display {

    private JFrame frame;
    private Canvas canvas;

    private String title;
    private int width, height;

    public Display(String title, int width, int height){
        this.title = title;
        this.width = width;
        this.height = height;
    
        createDisplay();
    }

    private void createDisplay(){
        frame = new JFrame(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    
        canvas = new Canvas();
        canvas.setPreferredSize(new Dimension(width, height));
        canvas.setMaximumSize(new Dimension(width, height));
        canvas.setMinimumSize(new Dimension(width, height));
        canvas.setFocusable(true);
        
        frame.add(canvas);
        frame.pack();
    }

    public Canvas getCanvas(){
        return canvas;
    }

    public JFrame getFrame(){
        return frame;
    }
}

package fr.romainimberti.isometric;

import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JFrame;
import fr.romainimberti.isometric.gfx.Assets;

public class Game implements Runnable {

    private Display display;
    private int width, height;

    public JFrame frame;

    private boolean running = false;
    private Thread thread;
    public String title;

    private BufferStrategy bs;
    private Graphics g;

    public int x, y;

    public int[][] world;

    public static final int TILE_WIDTH = 64;
    public static final int TILE_HEIGHT = 64;
    public static final int TILE_WIDTH_HALF = 32;
    public static final int TILE_HEIGHT_HALF = 32;
    public static final int TILE_WIDTH_QUARTER = 16;
    public static final int TILE_HEIGHT_QUARTER = 16;

    public int xOffset;

    //Input
    private MouseManager mouseManager;

    public Game(String title, int width, int height){
        this.width = width;
        this.height = height;
        this.mouseManager = new MouseManager(this);
        this.world = new int[10][10];
    }

    private void init(){
        display = new Display(title, width, height);
        display.getFrame().addMouseListener(mouseManager);
        display.getFrame().addMouseMotionListener(mouseManager);
        display.getCanvas().addMouseListener(mouseManager);
        display.getCanvas().addMouseMotionListener(mouseManager);
        this.frame = display.getFrame();
        Assets.init();
        xOffset = frame.getWidth()/2;
        //Fill the world
        for(int i = 0;i<world.length;i++){
            for(int j=0;j<world[0].length;j++){
                int r = ThreadLocalRandom.current().nextInt(0,1+1);
                if(r == 0)
                    world[i][j] = 0;
                else 
                    world[i][j] = 1;
            }
        }
    }

    private void tick(){
        mouseManager.tick();
        xOffset = frame.getWidth()/2;
    }

    private void render(){
        bs = display.getCanvas().getBufferStrategy();
        if(bs == null){
            display.getCanvas().createBufferStrategy(3);
            return;
        }
        g = bs.getDrawGraphics();
        //Clear Screen
        g.clearRect(0, 0, frame.getWidth(), frame.getHeight());
        //Draw Here

        //World render
        for(int x = 0;x<world.length;x++){
            for(int y = 0;y<world[0].length;y++){
                int[] isoCoords = toIso(x, y);
                int fx = isoCoords[0];//
                int fy = isoCoords[1];//
                if(world[x][y] == 0){
                    g.drawImage(Assets.grass, fx, fy, null);
                }else if(world[x][y] == 1){
                    g.drawImage(Assets.water, fx, fy, null);
                }
            }
        }
    
        //Selected tile render
        int[] coordsIsoSelected = toIso(x, y);
        g.drawImage(Assets.selected, coordsIsoSelected[0], coordsIsoSelected[1], TILE_WIDTH, TILE_HEIGHT, null);
    
        //End Drawing
        bs.show();
        g.dispose();
    }

    public void run(){
        init();
        int fps = 120;
        double timePerTick = 1000000000 / fps;
        double delta = 0;
        long now;
        long lastTime = System.nanoTime();
        while(running){
            now = System.nanoTime();
            delta += (now - lastTime) / timePerTick;
            lastTime = now;
            if(delta >= 1){
                tick();
                render();
                delta--;
            }
        }
        stop();
    }

    public MouseManager getMouseManager(){
        return mouseManager;
    }

    public int getWidth(){
        return width;
    }

    public int getHeight(){
        return height;
    }

    public synchronized void start(){
        if(running)
            return;
        running = true;
        thread = new Thread(this);
        thread.start();
    }

    public synchronized void stop(){
        if(!running)
            return;
        running = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static int[] toIso(int x, int y){

        int i = (x - y) * TILE_WIDTH_HALF;
        int j = (x + y) * TILE_HEIGHT_QUARTER;
        i+=xOffset;
    
        return new int[]{i,j};
    }

    public static int[] toGrid(int x, int y){
    
        x-=xOffset;
        int i = ( x / ( TILE_WIDTH_HALF ) + y / ( TILE_HEIGHT_QUARTER )) / 2;
        int j = ( y / ( TILE_HEIGHT_QUARTER ) - ( x / ( TILE_WIDTH_HALF ))) / 2;
    
        return new int[]{i,j};
    }
}

package fr.romainimberti.isometric;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;


public class MouseManager implements MouseListener, MouseMotionListener {

    private boolean leftPressed, rightPressed;
    private int mouseX, mouseY;
    private Game game;
    public MouseManager(Game game){
        this.game = game;
    }

    public void tick(){
        game.x = game.toGrid(mouseX, mouseY)[0];
        game.y = game.toGrid(mouseX, mouseY)[1];
    }

    // Getters

    public boolean isLeftPressed(){
        return leftPressed;
    }

    public boolean isRightPressed(){
        return rightPressed;
    }

    public int getMouseX(){
        return mouseX;
    }

    public int getMouseY(){
        return mouseY;
    }

    // Implemented methods

    @Override
    public void mousePressed(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1)
            leftPressed = true;
        else if(e.getButton() == MouseEvent.BUTTON3)
            rightPressed = true;
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1)
            leftPressed = false;
        else if(e.getButton() == MouseEvent.BUTTON3)
            rightPressed = false;
    
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        mouseX = e.getX();
        mouseY = e.getY();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
    
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub
    
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
    
    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub
    
    }
}

If you need it, you can find here my project architecture so you can organize all the files correctly.

Project architecture

Again, sorry for this very, very messy code but I had to split all the usefull parts of my game to reduce it's size. Also don't forget to download and place correctly the sheet file. Hope this will help.

128*64 tiles

Community
  • 1
  • 1
RomainImberti
  • 121
  • 1
  • 11
  • 2
    *"If you need more precisions, I would be glad to give you more informations."* The highest precision thing you could bring is a [mcve], please post one. Also, I can't completely understand your question, what are you trying to achieve exactly? Btw, are you using Swing? – Frakcool Sep 07 '17 at 20:39
  • Well, i'm trying to detect which tile my mouse is hovering over, but that isn't working correctly, like you can see in the last screenshot. Thank you for your comment, and also, sorry for my bad english :) Edit: I am using Swing as I render my tiles in a JFrame canvas. – RomainImberti Sep 07 '17 at 20:40
  • 1
    Where is your mouse hovering over? What should happen when you hover them? What is happening now? If you could provide a MCVE it would be easier to understand – Frakcool Sep 07 '17 at 20:49
  • I made a video to try to explain what is my problem.When I hover my tiles, the texture my mouse is hovering should change, like in the video but the tile detected is not the good one. Thank you for your reply. https://youtu.be/baCVIfJz2Wo – RomainImberti Sep 07 '17 at 20:55
  • 2
    Alright, the video made the problem clear to me, but we still need a [mcve] so we can copy-paste and see the error ourselves and try to solve it too :) Could you try and make one? This isn't your whole working code, it's a new short sample (not code snippets as above) that we can copy-paste, need to import nothing (i.e. include imports in your MCVE), this way we'll be able to provide more information / answers and of more quality – Frakcool Sep 07 '17 at 20:59
  • Should I upload the source code and the assets of my project? (First post on this forum sorry for my bad comprehension of what I need to proivide) – RomainImberti Sep 07 '17 at 21:00
  • 1
    What is a code snippet? They are parts of code that show an specific part of the program and generally are short. What is a whole program? It includes all the classes the program needs to be run but it's really big. What is a MCVE? It is a middle point between the two, it's a whole program with the minimal code needed to replicate your problem, one that we can easily copy-paste in our IDEs and actually see the problem. You may read the link of Minimal, Complete... I posted twice above and [Short, Self Contained, Correct Example (SSCCE)](http://sscce.org/) to understanding what I'm saying – Frakcool Sep 07 '17 at 21:05
  • Here is my project: http://www.mediafire.com/file/7jqkzv24tzzqh9o/project.rar Ok sorry, I think I understand now, I'm going to edit my project. – RomainImberti Sep 07 '17 at 21:07
  • 1
    In other words, we don't want your whole project, the assets might be okay for the purpose of testing, but you need to post the code here in the same way you posted the snippets above, no external links please, Stack Overflow wants to have this knowledge available for more people in the future, what if mediafire decided to close or delete your file? Then this post might become useless... – Frakcool Sep 07 '17 at 21:08
  • Ok I understand of course, thanks for your help, I'm going to make this. – RomainImberti Sep 07 '17 at 21:10
  • Cool! Let me know whenever you have it, if someone else posts a comment, you can notify me by writing `@Frakcool` in the comment ^^ I'll be glad to check this out as it seems an interesting project for me :) – Frakcool Sep 07 '17 at 21:11
  • 2
    Thank you very much for your help @Frakcool , I will try to simplify my code to make it short and executable easely ! I'll notify you when that will be done ! thank you ! :) – RomainImberti Sep 07 '17 at 21:19
  • @Frakcool, I think I did it, when you have some time to spend on this, please take a look at my project. If this isn't what you asked me, feel free to let me know it, I'll correct it as soon as possible. Thank you very much for your help. – RomainImberti Sep 07 '17 at 22:13
  • Nice! It seems you were almost there, I can't test this at the moment, but I will in a couple of hours... Is the `Tilesheet` the 1st image on the post? – Frakcool Sep 07 '17 at 22:17
  • No problem, I'm going to sleep now, take your time ! ;) Yes indeed, if you have more questions I will see them when I wake up. Thank you for all your help ! – RomainImberti Sep 07 '17 at 22:21
  • Sorry, I wasn't able to check this earlier, I'll try to help through the day in my free time at work – Frakcool Sep 08 '17 at 13:56
  • Oh really no problem, take your time, I already thank you a lot ! – RomainImberti Sep 08 '17 at 14:00
  • Sorry for annoying you @Frakcool, but I still have no answers to my problem. I'd like to know if you started looking at my project. Again sorry for all, and have a nice day. – RomainImberti Sep 11 '17 at 10:53
  • Not annoying me, I checked the project these days, however I still have no luck in coming with a solution, what I've found is that the problem lies `toGrid` method, or at least in your logic in general... I've tried to understand it in my free time (which I barely have, because of my own work), what I'm trying to do right now is creating a new project... btw, is there any special reason you're using `BufferStrategy` in your project instead of letting Swing do the painting for you? – Frakcool Sep 11 '17 at 13:25
  • Thank you for helping me! Yes that's what I found too, but it doesn't seem like my math equations are wrong, that's what I don't understand, so your idea of making a new project seems to be good. The only reason why I am using BufferStrategy instead of letting Swing do the painting is that it was the first thing I learnt, but of course this way must not be the simplest. If you have some corrections to apply, I would be happy to learn how you implemented them. – RomainImberti Sep 11 '17 at 13:47
  • Ok, that allows me to do some more things, since I've never used BufferStrategy, I could try doing some passive-painting instead of active-painting (BufferStrategy). I'll give them a shot later on, right now I'm a little bit busy – Frakcool Sep 11 '17 at 13:59
  • No problem, thank you very much! :) – RomainImberti Sep 11 '17 at 14:02
  • This problem of yours isn't easy to solve heh! I've been looking at it for long time now – Frakcool Sep 13 '17 at 13:40
  • Yes I know, I'm trying to solve it for 2 weeks already. I'm really sorry if annoying you with it, and I thank you very much for your time. I hope we will success asap. – RomainImberti Sep 13 '17 at 14:09
  • No worries, not annoying me :) – Frakcool Sep 13 '17 at 14:09
  • I really don't know how to solve it anymore :/ – RomainImberti Sep 13 '17 at 14:14
  • My best tip is: Stop thinking about it for a day, go, start a new project, answer some Stack Overflow questions, play some basketball / run / exercise, do whatever you want, forget this completely for a day. You'll eventually come with a fresh mind, better ideas, etc. You could also try starting it from scratch (in another project). While doing some of the above, your subconscious mind fill keep thinking about it, I've came with the solution to hard problems while doing so, or while peeing... just leave your mind in blank. Take it easy :) – Frakcool Sep 13 '17 at 14:18
  • I'll try it, thanks for the tip! I hope it will help, thank you vert much :) – RomainImberti Sep 13 '17 at 14:22
  • Well, after a few days without thinking about this, I still can't figure out the solution to this problem. Maybe the problem comes from my spritesheet and the height of my tiles. – RomainImberti Sep 18 '17 at 16:17
  • I'm sorry, been really busy at work, have you tried changing your tiles' heights? – Frakcool Sep 19 '17 at 13:59
  • No problem! :) I did, but it doesn't seem to solve the problem. – RomainImberti Sep 19 '17 at 16:37
  • How did you got to those equations on your `toIso` and `toGrid` methods? – Frakcool Sep 19 '17 at 16:39
  • I took the toIso equations from some forums, and I tried to reverse it, so I obtained the toGrid equations. – RomainImberti Sep 19 '17 at 19:50
  • Alright that makes it easier, let me check the equations and if possible post a link to those forums – Frakcool Sep 19 '17 at 20:58
  • Here is an article I found which explains this method really well. http://clintbellanger.net/articles/isometric_math/ Thanks for your help. – RomainImberti Sep 20 '17 at 04:21
  • Interesting article, now it’s easier for me to understand the logic of the equations... I think I’m closer now, however I have a doubt... in my Mac it looks “pushed” to the right, is this how you’ve designed the GUI? – Frakcool Sep 20 '17 at 17:15
  • Yes of course, I should have given it to you earlier. Nice, well I'm not sure to understand, are you talking about the offset? – RomainImberti Sep 20 '17 at 17:27
  • Yeah, it looks like this in my pc: [Image](https://i.stack.imgur.com/lELiV.png) – Frakcool Sep 20 '17 at 17:33
  • Hm weird, I think it's due to the offset I apply to the screen coordinates, but it should be centered on the screen. – RomainImberti Sep 20 '17 at 17:37
  • Well, that's something to check for later... – Frakcool Sep 20 '17 at 17:38
  • Yes indeed, but that's something I added just before posting it so it might be buggy. ^^ – RomainImberti Sep 20 '17 at 17:39
  • If I remove `i += 800` and `j += 100`, etc, it goes completely to the left, truncating the map at about 1/4 part of it... – Frakcool Sep 20 '17 at 17:41
  • Oh my bad, you may have an old version. I made this little fix: this.xOffset = frame.getWidth()/2;this.yOffset = 0; – RomainImberti Sep 20 '17 at 17:43
  • Can you edit your post with that code in it? So I can know which file it has it? – Frakcool Sep 20 '17 at 17:44
  • Yes for sure. :) – RomainImberti Sep 20 '17 at 17:45
  • You can basically replace the 800 value in the offset and replace it with this expression to center the grid on the screen. – RomainImberti Sep 20 '17 at 17:56
  • Can you use 128 x 64 tiles? Can you upload the picture? I'm going to try with the same dimensions they say on the link you provided... Or what sizes are your tiles? 64 x 32? – Frakcool Sep 20 '17 at 18:47
  • I don't have any spritesheet with 128*64 tiles at the moment, as I downloaded this spritesheet a long time ago. I'm not sure to understand what picture you're talking about. :/ Yes it seems to be a good idea of course. – RomainImberti Sep 20 '17 at 18:51
  • No worries, I mean if you could upload the spritesheet (picture) with 128 x 64... As I understand, tiles should be 2X wider than taller, in the post you linked they're using isometric tiles of `128 x 64` pixels, so, your tiles are `64 x 64`, aren't they? Do you have any spritesheet with `64 x 32` for example? Or are they `32 x 16`? I think, the problem lies there... As the equations are made for those kind of values, not in the logic but the file itself... That's what comes to my mind at this moment – Frakcool Sep 20 '17 at 18:54
  • Thanks. Yes my tiles ae currently 64*64 but half of the height is not used for flat tiles. I added a 128*64 tilesheet in the post. – RomainImberti Sep 20 '17 at 19:52

2 Answers2

3

just wanted to say that I finally solved it. It was just a conversion to int issue. These are the final methods that I use. Hope it will help people who are trying to work with isometric tiles. Thank you !

public static int[] toIso(int x, int y){

    int i = (x - y) * TILE_WIDTH_HALF;
    int j = (x + y) * TILE_HEIGHT_QUARTER;

    i += xOffset-TILE_WIDTH_HALF;
    j+=yOffset;

    return new int[]{i,j};
}

public static int[] toGrid(double i, double j){

    i-=xOffset;
    j-=yOffset;

    double tx = Math.ceil(((i / TILE_WIDTH_HALF) + (j / TILE_HEIGHT_QUARTER))/2);
    double ty = Math.ceil(((j / TILE_HEIGHT_QUARTER) - (i / TILE_WIDTH_HALF))/2);

    int x = (int) Math.ceil(tx)-1;
    int y = (int) Math.ceil(ty)-1;

    return new int[]{x, y};
}
RomainImberti
  • 121
  • 1
  • 11
1

After replacing the spritesheet with the new one with 128x64 pixels' tiles, I've been able to achieve the desired output partially...

Why I say "partially"? Because I've managed to get the desired result only from the half right part of the map.

enter image description here

I believe it could have something to do with how the map is being painted, I'm not a native English speaker so I might be misunderstanding what the "Notes" section says in OP's link:

Notice that the "origin" of the isometric tile is the top corner. But usually when we draw a sprite it's from the top-left corner

I've called the methods toGrid() and toIso() at the beginning of the program as follows:

int[] coordinates = Game.toIso(2, 1);
System.out.println(coordinates[0] + "-" + coordinates[1]);

int[] coordinates2 = Game.toGrid(coordinates[0], coordinates[1]);
System.out.println(coordinates2[0] + "-" + coordinates2[1]);

And got the following results, (Which indeed are what we were expecting), so we know the methods work correctly:

64-96
2-1

I was sure to modify the Assets file:

public static final int WIDTH = 128, HEIGHT = 64;

Where I also changed the variable names following the Java naming conventions (ALL_WORDS_UPPER_CASE_CONSTANTS) and made it public instead of private

I also changed the Game file:

public static final int TILE_WIDTH = Assets.WIDTH;
public static final int TILE_HEIGHT = Assets.HEIGHT;
public static final int TILE_WIDTH_HALF = TILE_WIDTH / 2;
public static final int TILE_HEIGHT_HALF = TILE_HEIGHT / 2;
public static final int TILE_WIDTH_QUARTER = TILE_WIDTH / 4;
public static final int TILE_HEIGHT_QUARTER = TILE_HEIGHT / 4;

To use those constants on the Assets file and calculate the HALF and QUARTER instead of hardcoding it.

I also believe xOffset shouldn't be public but private as well as some other variables on the program...

The tick() method, doesn't need to calculate the xOffset everytime, so we can get rid of this line inside it:

xOffset = frame.getWidth() / 2 - 65;

I also changed the way you paint the tile you're selecting as:

// Selected tile render
int[] coordsIsoSelected = toIso(x, y);
g.drawImage(Assets.selected, coordsIsoSelected[0], coordsIsoSelected[1], TILE_WIDTH, TILE_HEIGHT, null);

And for the Tolso equations, I changed them to:

public static int[] toIso(int x, int y) {
    int i = (x - y) * TILE_WIDTH_HALF;
    int j = (x + y) * TILE_HEIGHT_HALF;

    i += xOffset;

    return new int[] { i, j };
}

Below I adjusted the parenthesis locations:

public static int[] toGrid(int x, int y) {
    x -= xOffset;

    int i = ((x / TILE_WIDTH_HALF) + (y / TILE_HEIGHT_HALF)) / 2;
    int j = ((y / TILE_HEIGHT_HALF) - (x / TILE_WIDTH_HALF)) / 2;

    return new int[] { i, j };
}
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Oh thanks for this answer! Did you change the toIso and toGrid functions? Because when I launch the program, tiles are rendered with half of their normal height (I put a screenshot in the post), and if I change the equations and replace Tile_HEIGHT_QUARTER with TILE_HEIGHT_HALF, the map is rendered correctly but tile detection is still completly broken so I wonder how you achieved such a result :/ Sorry for not being able to solve this. :/ – RomainImberti Sep 21 '17 at 15:31
  • I just adjusted the parenthesis, I'll add that code too... Oh and I changed the Tile size where you paint it alone too... – Frakcool Sep 21 '17 at 15:33
  • Thank you very much for your help! I'll try to fix the left part of the map thanks to the code you provided! – RomainImberti Sep 21 '17 at 15:42
  • No worries, if you still have doubts, try asking a new question with improved code and try to minimize it (Assets file can be removed, same for MouseManager, Launcher and Game can be on the same file as well, etc) – Frakcool Sep 21 '17 at 15:48
  • Thank you for everything @Frakcool ! I think I'll try that yes, that may be a good idea :) – RomainImberti Sep 21 '17 at 15:55