Javascript 射线墙交点

Javascript 射线墙交点,javascript,math,line-intersection,Javascript,Math,Line Intersection,我正在写一个简单的2D游戏引擎,因为我想复习我的学校数学知识。 我知道可能很多人已经回答了类似的问题(我读了很多关于这个话题的问题和答案),但我不明白为什么我的方法不起作用。 在图中,我们可以看到一个“房间”,里面有一个摄像头和两条光线,它们根据摄像头的方向改变方向。 这些光线应表示摄影机视野的左右边界,并应与摄影机前面的墙相交。 问题是,当相机移动和旋转(使用“向上”、“向下”、“向左”、“向右”)时,有时光线消失,即相交功能失败。 有人能帮我找到解决办法吗? 以下是代码的相关部分:

我正在写一个简单的2D游戏引擎,因为我想复习我的学校数学知识。 我知道可能很多人已经回答了类似的问题(我读了很多关于这个话题的问题和答案),但我不明白为什么我的方法不起作用。 在图中,我们可以看到一个“房间”,里面有一个摄像头和两条光线,它们根据摄像头的方向改变方向。 这些光线应表示摄影机视野的左右边界,并应与摄影机前面的墙相交。 问题是,当相机移动和旋转(使用“向上”、“向下”、“向左”、“向右”)时,有时光线消失,即相交功能失败。 有人能帮我找到解决办法吗? 以下是代码的相关部分:

    function Player(x,y,angle) {

        this.x = x;
        this.y = y;
        this.z = 30;
        this.fieldOfView = { 
            degrees : 60,
            rads : Game.utils.degree2Rad(60),
            set : function (deg) {
                var self = this;
                self.fieldOfView.degrees = deg;
                self.fieldOfView.rads = Game.utils.degree2Rad(rads);
            }
        };


        this.angleDeg = angle;
        this.angleRads = Game.utils.degree2Rad(angle);
        this.rotate = function () {
            /* Handle rotation and position
               of the camera depending on the button pressed */
        }
        this.draw = function (canvas1,canvas2) {
            var self = this;
            var ctx1 = canvas1.getContext('2d');

            var ctx2 = canvas2.getContext('2d');

            /*Draw a circle on canvas1 at Game.player.x Game.player.y*/
             // CODE
            /*Draw a circle on canvas2 at the center of canvas*/
             // CODE

            /*Angles of the two rays in radians (FOV is 60°).  
              Add 30° to player's angle and find one,
              Substract 30° to player's angle and find the other
            */
            var rad1 = Game.utils.degree2Rad(Game.player.angleDeg+30);
            var rad2 = Game.utils.degree2Rad(Game.player.angleDeg-30);

            /*
               The two Rays, defined with a point (player.x and player.y)                                          
               and a vector
            */
            var _rad1 = new Ray2D(self.x,self.y,new Vector2D(Math.cos(rad1),Math.sin(rad1)));
            var _rad2 = new Ray2D(self.x,self.y,new Vector2D(Math.cos(rad2),Math.sin(rad2)));

            var _w = Game.walls;
            var ps = [];
            for(var i=0;i<_w.length;i++)
            {
                //FIND THE INTERSECTION POINTS
                var j = _w[i];
                var p =_rad1.intersectionWall(j);
                if(p) {
                    ps.push(p);
                }
                var p2 = _rad2.intersectionWall(j);
                if(p2) {
                    ps.push(p2);
                }

            }

            if(ps.length>1)
            {
                // DRAW THE TWO INTERSECTION POINTS
                ctx1.beginPath();
                ctx1.moveTo(self.x,self.y);
                ctx1.lineTo(ps[0].x,ps[0].y);
                ctx1.stroke();

                ctx1.beginPath();
                ctx1.moveTo(self.x,self.y);
                ctx1.lineTo(ps[1].x,ps[1].y);
                ctx1.stroke();

                //CODE 
                }
            else {
                console.log(_rad1,_rad2);
                //console.log('non-p',ps[0]);
            }
            /*ctx1.beginPath();
            ctx1.arc(self.x,self.y,2,0,Game.GLOBAL.CIRCLE);
            ctx1.stroke();
            ctx1.closePath();*/



        },
        this.update = function () {
            this.rotate();

        }
    } 

    function Wall (x1,y1,x2,y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.update = function (context1,context2,player) {

        };
        this.draw = function (context1,context2,player) {
            //CODE
        }
    }

    function Vector2D (x,y) {
        this.x = x;
        this.y = y;
        this.dot = function (v) {
             //Dot product
             return v.x*self.x+v.y*self.y;

        }
        this.cross = function (v) {
            //cross product
            return self.x*v.y-self.y*v.x;
        }
    }

    function StraightLine2D (xo,yo,v) {
        if(!(v instanceof(Vector2D)))
        {
            throw new Error('Invalid Argument supplied for constructor "StraightLine2D"');
        }

        this.xo = xo;
        this.yo = yo;
        this.v = v;

        this.calc = function (t) {
            var self = this;
            return { 
                x : t*self.v.x + self.xo,
                y : t*self.v.y + self.yo
            }
        }

        this.intersectionLine = function (R) {
            var self = this;
            var x1 = R.xo;
            var y1 = R.yo;
            var v1 = R.v;
            var _cross = self.v.cross(v1);
            if(_cross == 0)
            {
                return null;
            }

        switch(true) {
                case self.v.x == 0:
                    var t = (self.xo-x1)/v1.x;
                    return R.calc(t);
                break;
                case self.v.y == 0:
                    var t = (self.yo-y1)/v1.y;
                    return R.calc(t);
                break;
                default:
                    var t =  (self.v.y*(self.xo-x1)+self.v.x*(y1-self.yo))/(-_cross);
                    //var t = (t1*(v1.x)+x1-self.xo)/self.v.x;
                    return R.calc(t);
                break;
            }
        }


    }

    function Ray2D (xo,yo,v) {
        if(!(v instanceof(Vector2D)))
        {
            throw new Error('Invalid Argument supplied for constructor "StraightLine2D"');
        }

        this.xo = xo;
        this.yo = yo;
        this.v = v;

        this.calc = function (t) {
            var self = this;

            if(t<0) {
                return null;
            }
            return { 
                x : t*self.v.x + self.xo,
                y : t*self.v.y + self.yo
            }
        }

        this.intersectionLine = function (R) {
            var self = this;
            var x1 = R.xo;
            var y1 = R.yo;

            var v1 = R.v;
            var _cross = self.v.cross(v1);
            if(_cross == 0.0)
            {
                return null;
            }

            switch(true) {
                case self.v.x == 0:
                    var t = (self.xo-x1)/v1.x;
                    return t > 0 ? R.calc(t) : null;
                break;
                case self.v.y == 0:
                    var t = (self.yo-y1)/v1.y;
                    return t > 0 ? R.calc(t) : null;
                break;
                default:


                    var t1 = ((y1-self.yo)*self.v.x+self.v.y*(self.xo-x1))/(v1.x*self.v.y-v1.y*self.v.x);

                    var t = (t1*R.v.x+R.xo-self.xo)/self.v.x;

                    return t >= 0 ? self.calc(t) : null;
                break;
            }
        }

        this.intersectionWall = function (W) {
            var self = this;
            var R = new StraightLine2D(W.x1,W.y1,new Vector2D(W.x1-W.x2,W.y1-W.y2));
            var point = self.intersectionLine(R);


            if(point && 
               point.x <= Math.max(W.x1,W.x2) && point.x >= Math.min(W.x1,W.x2) &&
               point.y <= Math.max(W.y1,W.y2) && point.y >= Math.min(W.y1,W.y2))
            {
                return point;
            }
            return null;
        }

    }
功能播放器(x、y、角度){
这个.x=x;
这个。y=y;
这个。z=30;
this.fieldOfView={
学位:60,
rads:游戏。utils。等级2 RAD(60),
设置:功能(度){
var self=这个;
self.fieldOfView.degrees=deg;
self.fieldOfView.rads=Game.utils.degree2Rad(rads);
}
};
该角度=角度;
this.angelrads=Game.utils.degree2Rad(角度);
this.rotate=函数(){
/*手柄旋转和位置
取决于按下的按钮,确定摄像头的位置*/
}
this.draw=函数(canvas1,canvas2){
var self=这个;
var ctx1=canvas1.getContext('2d');
var ctx2=canvas2.getContext('2d');
/*在画布1上画一个圆圈,在Game.player.x Game.player.y*/
//代码
/*在画布中心的画布2上画一个圆圈*/
//代码
/*以弧度表示的两条光线的角度(视场为60°)。
将玩家角度增加30°,然后找到一个,
将30°减去球员角度,然后找到另一个角度
*/
var rad1=游戏使用度2 rad(游戏玩家角度度+30);
var rad2=游戏的utils.degree2Rad(游戏的玩家角度DEG-30);
/*
用点(player.x和player.y)定义的两条光线
和一个向量
*/
var_rad1=新的Ray2D(self.x,self.y,新的Vector2D(Math.cos(rad1),Math.sin(rad1));
var_rad2=新的Ray2D(self.x,self.y,新的Vector2D(Math.cos(rad2),Math.sin(rad2));
var_w=游戏墙;
var ps=[];
对于(var i=0;i1)
{
//画两个交点
ctx1.beginPath();
ctx1.moveTo(self.x,self.y);
ctx1.lineTo(ps[0].x,ps[0].y);
ctx1.stroke();
ctx1.beginPath();
ctx1.moveTo(self.x,self.y);
ctx1.lineTo(ps[1].x,ps[1].y);
ctx1.stroke();
//代码
}
否则{
控制台日志(_rad1,_rad2);
//console.log('non-p',ps[0]);
}
/*ctx1.beginPath();
ctx1.arc(self.x,self.y,2,0,Game.GLOBAL.CIRCLE);
ctx1.stroke();
ctx1.closePath()*/
},
this.update=函数(){
这个。旋转();
}
} 
功能墙(x1、y1、x2、y2){
这是1.x1=x1;
这是1.y1=y1;
这是0.x2=x2;
这1.y2=y2;
this.update=函数(context1、context2、player){
};
this.draw=函数(context1、context2、player){
//代码
}
}
函数向量2D(x,y){
这个.x=x;
这个。y=y;
this.dot=函数(v){
//点积
返回v.x*self.x+v.y*self.y;
}
此参数=函数(v){
//叉积
返回self.x*v.y-self.y*v.x;
}
}
函数直线2D(xo、yo、v){
if(!(v instanceof(Vector2D)))
{
抛出新错误('为构造函数“StraightLine2D”提供的参数无效');
}
this.xo=xo;
this.yo=yo;
这个,v=v;
this.calc=函数(t){
var self=这个;
返回{
x:t*self.v.x+self.xo,
y:t*self.v.y+self.yo
}
}
this.intersectionLine=函数(R){
var self=这个;
var x1=R.xo;
var y1=R.yo;
var v1=R.v;
var _cross=自身v.cross(v1);
如果(_cross==0)
{
返回null;
}
开关(真){
大小写self.v.x==0:
var t=(self.xo-x1)/v1.x;
返回R.calc(t);
打破
大小写self.v.y==0:
var t=(self.yo-y1)/v1.y;
返回R.calc(t);
打破
违约:
var t=(self.v.y*(self.xo-x1)+self.v.x*(y1 self.yo))/(-u交叉);
//var t=(t1*(v1.x)+x1 self.xo)/self.v.x;
返回R.calc(t);
打破
}
}
}
函数Ray2D(xo,yo,v){
if(!(v instanceof(Vector2D)))
{
抛出新错误('为构造函数“StraightLine2D”提供的参数无效');
}
this.xo=xo;
this.yo=yo;
这个,v=v;
this.calc=函数(t){
var self=这个;
if(t0?R.calc(t):空;
打破
大小写self.v.y==0:
var t=(self.yo-y1)/v1.y;
返回t>0?R.calc(t):空;
打破
违约:
变量t1=((y1-self.yo)*self.v.x+self.v.y*(self.xo-x1))/(v1.x*self.v.y-v1.y*self.v.x);
var t=(t1*R.v.x+R.xo-self.xo)/self.v.x;