WedX - журнал о программировании и компьютерных науках

Рисование и подбор изометрической плитки - JAVA

Я пытаюсь нарисовать изометрические плитки на Java и реализовать систему выбора плитки с помощью курсора мыши. Я рисую плитки, используя эти математические формулы, которые я нашел и адаптировал к своим текстурам плитки, которые вы можете найти ниже. Плитки имеют размер 64x64px, но плоские плитки имеют высоту всего 32px, даже если я рисую их с помощью спрайта 64x64.

Лист плитки

Карта представляет собой простой 2-мерный массив, в котором мои плитки представлены своим идентификатором.

Вот класс, который я использую для преобразования координат карты в координаты экрана с помощью функции toIso (). Я передаю свои экранные координаты, которые представляют положение курсора на экране, функции toGrid (), чтобы преобразовать их в координаты карты.

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};
}}

В настоящее время я визуализирую свои плитки с помощью двух циклов for и конвертирую координаты карты в координаты экрана с помощью функции toIso ().

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);
            }
        }
    }
}

Я получаю ромбовидную форму, которую хотел отобразить на экране.

Наконец, я обновляю каждый тик, который является фактическими координатами мыши на экране.

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

Выбранная плитка окончательно отрисована:

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.

Наконец, мое обнаружение плитки работает не так, как ожидалось, оно не идеально подходит для плитки, однако, похоже, это связано с прямоугольником, который я рисую. Я не могу придумать решение этой проблемы, заранее благодарю вас за чтение или за любой совет, который вы могли мне дать. Если вам нужна дополнительная точность, я буду рад предоставить вам дополнительную информацию.

Сбор плитки

Вот видео, показывающее, что на самом деле происходит: youtu.be/baCVIfJz2Wo


РЕДАКТИРОВАТЬ:

Вот часть моего кода, который вы могли бы использовать для запуска такого приложения, как мое. Извините за очень запутанный код, но я постарался сделать его как можно короче, не нарушая поведения игры.

Вам нужно будет поместить предоставленный ранее лист в папку текстур, созданную в папке ресурсов проекта.

Пакет gfx:

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);
    }
}

В остальном по проекту:

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
    
    }
}

Если вам это нужно, вы можете найти здесь мою архитектуру проекта, чтобы вы могли правильно организовать все файлы.

Архитектура проекта

Опять же, извините за этот очень, очень запутанный код, но мне пришлось разделить все полезные части моей игры, чтобы уменьшить ее размер. Также не забудьте скачать и правильно разместить файл листа. Надеюсь, это поможет.

128 * 64 плитки


  • Если вам нужно больше точности, я был бы рад предоставить вам больше информации. Самая высокая точность, которую вы можете принести, - это минимальный воспроизводимый пример, опубликуйте его. Кроме того, я не могу полностью понять ваш вопрос, чего именно вы пытаетесь достичь? Кстати, вы используете Swing? 07.09.2017
  • Ну, я пытаюсь определить, над какой плиткой наведена моя мышь, но это работает неправильно, как вы можете видеть на последнем снимке экрана. Спасибо за ваш комментарий, а также извините за мой плохой английский :) Изменить: я использую Swing, когда визуализирую свои плитки на холсте JFrame. 07.09.2017
  • Где ваша мышь зависла? Что должно произойти, когда вы их наводите? Что происходит сейчас? Если бы вы могли предоставить MCVE, было бы легче понять 07.09.2017
  • Я сделал видео, чтобы попытаться объяснить, в чем моя проблема. Когда я наводил курсор на плитки, текстура, на которой наведена моя мышь, должна измениться, как на видео, но обнаруженная плитка не является подходящей. Спасибо за ваш ответ. youtu.be/baCVIfJz2Wo 07.09.2017
  • Хорошо, видео прояснило мне проблему, но нам все еще нужен минимальный воспроизводимый пример, чтобы мы могли скопировать- вставьте и сами увидите ошибку и попробуйте ее решить :) Не могли бы вы попробовать и сделать одну? Это не весь ваш рабочий код, это новый короткий образец (не фрагменты кода, как указано выше), который мы можем скопировать и вставить, не нужно ничего импортировать (т.е. включать импорт в ваш MCVE), таким образом мы сможем предоставить больше информации / ответов и более высокого качества 07.09.2017
  • Должен ли я загружать исходный код и активы моего проекта? (Первое сообщение на этом форуме, извините за то, что я плохо понимаю, что мне нужно сделать) 08.09.2017
  • Что такое фрагмент кода? Это части кода, которые показывают определенную часть программы и обычно короткие. Что такое целая программа? Он включает в себя все классы, которые необходимо запустить программе, но он действительно большой. Что такое MCVE? Это середина между ними, это целая программа с минимальным кодом, необходимым для репликации вашей проблемы, который мы можем легко скопировать и вставить в наши IDE и действительно увидеть проблему. Вы можете прочитать ссылку Minimal, Complete ... Я дважды писал выше и Краткий, самодостаточный, правильный пример (SSCCE) к пониманию того, что я говорю 08.09.2017
  • Вот мой проект: mediafire.com/file/7jqkzv24tzzqh9o/project.rar Хорошо, извините, теперь я думаю, что понял, я собираюсь отредактировать свой проект. 08.09.2017
  • Другими словами, нам не нужен весь ваш проект, ресурсы могут быть в порядке для целей тестирования, но вам нужно опубликовать код здесь так же, как вы разместили фрагменты выше, без внешних ссылок, пожалуйста, переполнение стека хочет Чтобы эти знания были доступны большему количеству людей в будущем, что, если mediafire решит закрыть или удалить ваш файл? Тогда этот пост может стать бесполезным ... 08.09.2017
  • Хорошо, я понимаю, конечно, спасибо за вашу помощь, я сделаю это. 08.09.2017
  • Прохладный! Сообщите мне, когда он у вас будет, если кто-то еще оставит комментарий, вы можете уведомить меня, написав @Frakcool в комментарии ^^ Я буду рад проверить это, так как это кажется мне интересным проектом :) 08.09.2017
  • Большое спасибо за помощь @Frakcool, я постараюсь упростить свой код, чтобы он был коротким и легко исполняемым! Я сообщу вам, когда это будет сделано! Спасибо ! :) 08.09.2017
  • @Frakcool, я думаю, что сделал это, когда у вас будет время потратить на это, пожалуйста, взгляните на мой проект. Если вы меня не об этом спрашивали, дайте мне знать, я исправлю как можно скорее. Спасибо большое за помощь. 08.09.2017
  • Хороший! Кажется, вы были почти у цели, сейчас я не могу это проверить, но через пару часов проведу ... Tilesheet Это первое изображение в посте? 08.09.2017
  • Нет проблем, я пойду спать, не торопитесь! ;) Да, действительно, если у вас будут еще вопросы, я увижу их, когда проснусь. Спасибо за твою помощь ! 08.09.2017
  • Извините, мне не удалось проверить это раньше, постараюсь помочь днем ​​в свободное время на работе 08.09.2017
  • Ох уж нет проблем, не торопитесь, я уже вам огромное спасибо! 08.09.2017
  • Извините, что раздражаю вас @Frakcool, но у меня до сих пор нет ответов на свою проблему. Я хотел бы знать, начали ли вы смотреть на мой проект. Еще раз извините за всех, и хорошего дня. 11.09.2017
  • Меня это не раздражает, я проверил проект в эти дни, однако мне все еще не повезло с решением, я обнаружил, что проблема заключается в toGrid методе, или, по крайней мере, в вашей логике в целом ... пытался понять это в свое свободное время (которое у меня почти не было из-за моей собственной работы), то, что я пытаюсь сделать прямо сейчас, - это создать новый проект ... кстати, есть ли какая-то особая причина, по которой вы используете BufferStrategy в вашем проекте вместо того, чтобы позволить Swing рисовать за вас? 11.09.2017
  • Спасибо за помощь мне! Да, я тоже это обнаружил, но не похоже, что мои математические уравнения ошибочны, это то, чего я не понимаю, так что ваша идея создания нового проекта кажется хорошей. Единственная причина, по которой я использую BufferStrategy вместо того, чтобы позволить Swing рисовать, заключается в том, что это было первое, чему я научился, но, конечно, этот способ не должен быть самым простым. Если у вас есть какие-то исправления, я буду рад узнать, как вы их внедрили. 11.09.2017
  • Хорошо, это позволяет мне делать еще кое-что, поскольку я никогда не использовал BufferStrategy, я мог бы попробовать выполнить пассивное рисование вместо активного (BufferStrategy). Я дам им шанс позже, сейчас я немного занят 11.09.2017
  • Нет проблем, большое спасибо! :) 11.09.2017
  • Эту вашу проблему решить непросто, хе-хе! Я смотрю на это уже давно 13.09.2017
  • Да знаю, уже 2 недели пытаюсь решить. Мне очень жаль, что я вас этим раздражаю, и я очень благодарен вам за ваше время. Надеюсь, мы добьемся успеха как можно скорее. 13.09.2017
  • Не волнуйся, меня не напрягай :) 13.09.2017
  • Я действительно не знаю, как это решить: / 13.09.2017
  • Мой лучший совет: перестаньте думать об этом в течение дня, идите, начните новый проект, ответьте на несколько вопросов о переполнении стека, поиграйте в баскетбол / бегите / упражняйтесь, делайте все, что хотите, полностью забудьте об этом на день. В конечном итоге у вас появится свежий взгляд, лучшие идеи и т. Д. Вы также можете попробовать начать все с нуля (в другом проекте). Делая что-то из вышеперечисленного, ваше подсознание наполняет вас, продолжайте думать об этом, я пришел с решением трудных проблем, пока вы это делаете или когда писаете ... просто оставьте свой разум пустым. Не принимайте близко к сердцу :) 13.09.2017
  • Попробую, спасибо за подсказку! Надеюсь, это поможет, спасибо большое :) 13.09.2017
  • Что ж, спустя несколько дней, не думая об этом, я все еще не могу найти решение этой проблемы. Может быть, проблема в моем спрайт-листе и высоте моих плиток. 18.09.2017
  • Извините, был очень занят на работе, вы пробовали менять высоту плитки? 19.09.2017
  • Без проблем! :) Да, но, похоже, это не решает проблему. 19.09.2017
  • Как вы пришли к этим уравнениям в своих toIso и toGrid методах? 19.09.2017
  • Я взял уравнения toIso с некоторых форумов и попытался отменить их, так что я получил уравнения toGrid. 19.09.2017
  • Хорошо, это упрощает задачу, позвольте мне проверить уравнения и, если возможно, разместить ссылку на эти форумы 19.09.2017
  • Вот статья, которую я нашел, которая очень хорошо объясняет этот метод. clintbellanger.net/articles/isometric_math Спасибо за вашу помощь. 20.09.2017
  • Интересная статья, теперь мне легче понять логику уравнений ... Я думаю, что теперь я ближе, но у меня есть сомнения ... на моем Mac это выглядит «сдвинутым» вправо, вот как вы разработали графический интерфейс? 20.09.2017
  • Да, конечно, я должен был отдать его тебе раньше. Приятно, ну не уверен, что понял, ты про зачет? 20.09.2017
  • Да, на моем компьютере это выглядит так: Изображение 20.09.2017
  • Хм, странно, я думаю, это из-за смещения, которое я применяю к координатам экрана, но оно должно быть по центру экрана. 20.09.2017
  • Что ж, это кое-что, чтобы проверить позже ... 20.09.2017
  • Да, действительно, но это то, что я добавил перед публикацией, так что в нем могут быть ошибки. ^^ 20.09.2017
  • Если я удалю i += 800, j += 100 и т. Д., Он уйдет полностью влево, усекая карту примерно на 1/4 ее части ... 20.09.2017
  • Ух ты, возможно, у тебя старая версия. Я сделал небольшое исправление: this.xOffset = frame.getWidth () / 2; this.yOffset = 0; 20.09.2017
  • Можете ли вы отредактировать сообщение с этим кодом? Чтобы я мог узнать, в каком файле он находится? 20.09.2017
  • Да точно. :) 20.09.2017
  • Вы можете в основном заменить значение 800 в смещении и заменить его этим выражением, чтобы центрировать сетку на экране. 20.09.2017
  • Можете ли вы использовать плитки размером 128 x 64? Вы можете загрузить картинку? Я собираюсь попробовать с теми же размерами, которые указаны по ссылке, которую вы предоставили ... Или какие размеры у вашей плитки? 64 х 32? 20.09.2017
  • На данный момент у меня нет таблицы спрайтов с тайлами 128 * 64, так как я скачал ее довольно давно. Я не совсем понимаю, о какой картине вы говорите. : / Да вроде конечно хорошая идея. 20.09.2017
  • Не беспокойтесь, я имею в виду, если бы вы могли загрузить таблицу спрайтов (изображение) с размером 128 x 64 ... Насколько я понимаю, плитки должны быть в 2 раза шире, чем выше, в сообщении, которое вы связали, они используют изометрические плитки размером 128 x 64 пикселей, поэтому, ваши плитки 64 x 64, не так ли? У вас есть, например, спрайт-лист с 64 x 32? Или они 32 x 16? Я думаю, проблема в этом ... Поскольку уравнения составлены для таких значений, не в логике, а в самом файле ... Вот что мне приходит в голову в данный момент 20.09.2017
  • Спасибо. Да, мои плитки сейчас 64 * 64, но половина высоты не используется для плоских плиток. Я добавил в сообщение лист размером 128 * 64. 20.09.2017

Ответы:


1

просто хотел сказать, что наконец решил ее. Это было просто преобразование в проблему int. Это последние методы, которые я использую. Надеюсь, это поможет людям, которые пытаются работать с изометрической плиткой. Спасибо !

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};
}
13.10.2017

2

После замены таблицы спрайтов на новую с плитками 128x64 пикселей я смог частично добиться желаемого результата ...

Почему я говорю «частично»? Потому что мне удалось получить желаемый результат только из правой половины карты.

введите описание изображения здесь

Я считаю, что это может иметь какое-то отношение к рисованию карты, я не являюсь носителем английского языка, поэтому могу неправильно понять, что говорится в разделе «Примечания» в OP ссылка:

Обратите внимание, что «начало» изометрической плитки - это верхний угол. Но обычно, когда мы рисуем спрайт, он находится в верхнем левом углу.

Я вызвал методы toGrid() и toIso() в начале программы следующим образом:

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]);

И получили следующие результаты (которые действительно соответствуют нашим ожиданиям), поэтому мы знаем, что методы работают правильно:

64-96
2-1

Обязательно доработал Assets файл:

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

Я также изменил имена переменных в соответствии с соглашениями об именах Java (ALL_WORDS_UPPER_CASE_CONSTANTS ) и сделал public вместо private

Я также изменил Game файл:

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;

Чтобы использовать эти константы в файле Assets и вычислить HALF и QUARTER вместо его жесткого кодирования.

Я также считаю, что xOffset не должно быть public, а private, а также некоторые другие переменные в программе ...

Метод tick() не требует постоянного вычисления xOffset, поэтому мы можем избавиться от этой строки внутри него:

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

Я также изменил способ рисования выбранной плитки:

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

А для уравнений Толсо я изменил их на:

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 };
}

Ниже я скорректировал расположение скобок:

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 };
}
21.09.2017
  • О, спасибо за этот ответ! Вы меняли функции toIso и toGrid? Потому что, когда я запускаю программу, плитки отображаются с половиной своей нормальной высоты (я помещаю снимок экрана в сообщение), и если я изменю уравнения и заменю Tile_HEIGHT_QUARTER на TILE_HEIGHT_HALF, карта будет отображаться правильно, но обнаружение плитки по-прежнему полностью не работает поэтому мне интересно, как вы достигли такого результата: / Извините за то, что не смог решить эту проблему. : / 21.09.2017
  • Я только что поправил круглые скобки, я тоже добавлю этот код ... Да, и я изменил размер плитки, где вы тоже рисуете его в одиночку ... 21.09.2017
  • Спасибо большое за помощь! Я постараюсь исправить левую часть карты благодаря предоставленному вами коду! 21.09.2017
  • Не беспокойтесь, если у вас все еще есть сомнения, попробуйте задать новый вопрос с улучшенным кодом и постарайтесь его минимизировать (файл Assets можно удалить, то же самое для MouseManager, Launcher и Game могут быть в одном файле и т. Д.) 21.09.2017
  • Спасибо за все @Frakcool! Думаю, я попробую, да, это может быть хорошей идеей :) 21.09.2017
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]