射线墙交叉口

时间:2016-11-18 23:40:01

标签: javascript math line-intersection

我正在编写一个简单的2D游戏引擎,因为我想提高我的学校数学知识。 我知道也许很多人已经回答了类似的问题(我读了很多关于这个主题的问题和答案),但我无法理解为什么我的方法不起作用。 在this example我们可以看到一个"房间"使用相机和两条光线,根据相机的方向改变方向。 这些光线应代表摄像机视场的左右边界,并应与摄像机前方的墙壁相交。 问题是当相机移动和旋转时(使用" UP"," DOWN"," LEFT"," RIGHT")光线消失,即交叉功能失效。 有人可以帮我找到解决方案吗? 这里有相关的代码部分:

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

    }

编辑:我试图删除代码中不相关的部分。综合不是我的特质之一,我希望现在更具可读性。

0 个答案:

没有答案