Как правильно написать алгоритм вычисления соприкосновения луча со стеной (raycasting)?

Ради интереса пишу 2.5D движок на Java по технологии raycasting. Основная его часть почти готова, но никак не могу написать алоритм вычисления соприкосновения луча со стеной. Код всех классов:

    import java.awt.*;
    import javax.swing.*;
    import java.util.*;
    public class Main extends JFrame implements Runnable{
        public Thread thread;
        public Main(){
            super("2.5DEngine");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(Settings.WIDTH,Settings.HEIGHT);
            setBackground(Color.BLACK);
            setResizable(false);
            add(new Drawing());
            addKeyListener(new Player());
            setVisible(true);
            thread = new Thread(this);
            thread.start();
        }
        public void run(){
            while(true){
                Player.update();
                repaint();
                try{
                    thread.sleep(33);
                }catch(InterruptedException e){
                }
            }
        }
        public static void main (String[] args) {
            Main main = new Main();
        }
    }


import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
public class Drawing extends JPanel{
    public static ArrayList<Integer> mapY = Map.getMapY();
    public static ArrayList<Integer> mapX = Map.getMapX();
    public Drawing(){
        super();
    }
    public void paint(Graphics g){
        Graphics2D g2 = (Graphics2D)g;
        Ray_casting.raycasting(g2);
        g2.setPaint(Color.GREEN);
        Ellipse2D.Double player = new Ellipse2D.Double(Settings.xPos,Settings.yPos,8,8);
        g2.fill(player);
        g2.draw(player);
        for(int i = 0;i<mapY.size();i++){
            g2.draw(new Rectangle2D.Double(mapX.get(i),mapY.get(i),32.0,32.0));
        }
    }
}


import java.util.*;
public class Map{
    public static int[][] map={
        {1,1,1,1,1,1,1,1,1,1,1},
        {1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,1,0,0,1,0,1,0,1},
        {1,0,0,1,1,1,1,1,1,0,1},
        {1,0,0,1,0,0,0,1,1,0,1},
        {1,0,0,1,1,1,0,0,1,0,1},
        {1,0,0,0,0,1,0,0,1,0,1},
        {1,0,0,1,1,1,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,1},
        {1,1,1,1,1,1,1,1,1,1,1}
    };
    public static ArrayList<Integer> getMapY(){
        ArrayList<Integer> i = new ArrayList<Integer>();
        for(int y = 0;y<11;y++){
            for(int x = 0;x<11;x++){
                if(map[y][x] == 1){
                    i.add(y*32);
                }
            }
        }
        return i;
    }
    public static ArrayList<Integer> getMapX(){
        ArrayList<Integer> i = new ArrayList<Integer>();
        for(int y = 0;y<11;y++){
            for(int x = 0;x<11;x++){
                if(map[y][x] == 1){
                    i.add(x*32);
                }
            }
        }
        return i;
    }
}


import java.awt.event.*;
public class Player implements KeyListener{
    public static boolean left,right,forward,back;
    public static void update(){
        if(left)Settings.a-= 0.04;
        if(right)Settings.a+=0.04;
        if(forward){
            Settings.xPos = Settings.xPos+Settings.SPEED*Math.cos(Settings.a);
            Settings.yPos = Settings.yPos+Settings.SPEED*Math.sin(Settings.a);
            };
        if(back){
            Settings.xPos = Settings.xPos-Settings.SPEED*Math.cos(Settings.a);
            Settings.yPos = Settings.yPos-Settings.SPEED*Math.sin(Settings.a);
            };
    }
    public void keyTyped(KeyEvent key){
        
    }
    public void keyPressed (KeyEvent key){
        if(key.getKeyCode() == KeyEvent.VK_LEFT) left = true;
        if(key.getKeyCode() == KeyEvent.VK_RIGHT) right = true;
        if(key.getKeyCode() == KeyEvent.VK_UP) forward = true;
        if(key.getKeyCode() == KeyEvent.VK_DOWN) back = true;
    }
    public void keyReleased (KeyEvent key){
        if(key.getKeyCode() == KeyEvent.VK_LEFT) left = false;
        if(key.getKeyCode() == KeyEvent.VK_RIGHT) right = false;
        if(key.getKeyCode() == KeyEvent.VK_UP) forward = false;
        if(key.getKeyCode() == KeyEvent.VK_DOWN) back = false;
    }
}


public class Settings{
    public static int WIDTH = 640;
    public static int HEIGHT = 480;
    public static double xPos = 33;
    public static double yPos = 33;
    public static int SPEED = 2;
    public static double a = 0;
    public static double FOV = Math.PI/3;
    public static double HALF_FOV = FOV/2;
    public static int NUM_RAYS = 320;
    public static double DELTA_ANGLE = FOV/NUM_RAYS;
    public static int MAX_DEPTH = 100;
}


import java.util.*;
import java.awt.geom.*;
import java.awt.*;
public class Ray_casting{
    public static void raycasting(Graphics2D g2){
        g2.setPaint(Color.WHITE);
        double cur_a = Settings.a - Settings.HALF_FOV;
        double xo = Settings.xPos+4;
        double yo = Settings.yPos+4;
        double x = 0,y = 0;
        for(int i = 1; i<=Settings.NUM_RAYS;i++){
            double sin_a = Math.sin(cur_a);
            double cos_a = Math.cos(cur_a);
            for(int j = 1;j<=Settings.MAX_DEPTH;j++){
                x = xo + j*cos_a;
                y = yo + j*sin_a;
                g2.draw(new Line2D.Double(xo,yo,x,y));
                if(er(Map.getMapX(),x) & er(Map.getMapX(),x)) break;
            }
            cur_a+=Settings.DELTA_ANGLE;
        }
    }
}

За отрисовку лучей отвечает класс Ray_casting. Управление стрелочками.


Ответы (1 шт):

Автор решения: TAndrey

Ура, получилось. Надо было просто одновременно проверять x и y луча с координатами стен.

public static boolean check(double x, double y){
        ArrayList<Integer> zmapY = Map.getMapY();
        ArrayList<Integer> zmapX = Map.getMapX();
        int x1 = ((int) x)/32*32; 
        int y1 = ((int) y)/32*32;
        for(int i = 0; i<zmapY.size();i++){
            if(x1 == zmapX.get(i) & y1 == zmapY.get(i))return true;
        }
        return false;
    }
→ Ссылка