两个旋转元素之间的碰撞

Collision between two elements with rotating

var keys = new Array();
 var direction;
 var direction;
 var iNr = 0;
 
 $(document).ready(function(){
  looper();
  $("#demo1").css("margin-top", 400 + "px");
  $("#demo2").css("margin-left", 380 + "px");
  myFunction();
 });
 
 function myFunction()
 {
  iNr = iNr + 0.5;
  $("#main").css("transition","all 0.1s");
  $("#main").css("transform","rotate(" + iNr + "deg)");
  
  
  setTimeout(function()
  {
   myFunction();
  }, 50);
 
 }
 
 function looper()
 { 
  var p =$("#circle");
  var offset = p.offset();
  var t =$(".red");
  var roffset = t.offset();
  
  var rect1 = {x: offset.left, y: offset.top, width: p.width(), height: p.height()}
  var rect2 = {x: roffset.left, y: roffset.top, width: t.width(), height: t.height()}

  if (rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.height + rect1.y > rect2.y) {
   
   console.log("now");
  }
  
  if(direction == "left")
  {
   if(offset.left - 50 > 0)
   {
    $("#circle").css("left", ($("#circle").position().left - 2) + "px");
   }
  }
  if(direction == "up")
  {
   if(offset.top - 50 > 0)
   {
    $("#circle").css("top", ($("#circle").position().top - 2) + "px");
   }
  }
  if(direction == "right")
  {
   if((offset.left + 50) < $(window).width())
   {
    $("#circle").css("left", ($("#circle").position().left + 2) + "px");
   }
  }
  if(direction == "down")
  {
   if((offset.top + 50) < $(window).height())
   {
    $("#circle").css("top", ($("#circle").position().top + 2) + "px");
   }
  }
  
  
  
  ID=window.setTimeout("looper();", 1);
 }

 
 $(document).keyup(function(event) {
  
  if (event.keyCode == 37)
  {
   var index = keys.indexOf("37");
   keys.splice(index, 1);
   direction = "";
  }
  if (event.keyCode == 38)
  {
   var index = keys.indexOf("38");
   keys.splice(index, 1);
   direction = "";
  }
  if (event.keyCode == 39)
  {
   var index = keys.indexOf("39");
   keys.splice(index, 1);
   direction = "";
  }
  if (event.keyCode == 40)
  {
   var index = keys.indexOf("40");
   keys.splice(index, 1);
   direction = "";
  }
 });
 
 $(document).keydown(function(event) {
  
  if (event.keyCode == 37)
  {
   keys.push("37");
   direction = "left";
  }
  if (event.keyCode == 38)
  {
   keys.push("38");
   direction = "up";
  }
  if (event.keyCode == 39)
  {
   keys.push("39");
   direction = "right";
  }
  if (event.keyCode == 40)
  {
   keys.push("40");
   direction = "down";
  }
 });
<!doctype html>
<html lang="en">

 <head>
  <meta charset="utf-8">
  <title>test</title>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  
 </head>
 
 
 <body style="background-color:black; overflow-y:scroll;">
 
  <div style="width:400px; margin-left:500px; height:400px;" id="main">
   <div id="demo1" style="width:400px; height:20px; background-color:red; position:absolute;" class="red test all"></div>
   <div id="demo2" style="width:20px; height:400px; background-color:yellow; position:absolute;" class="test all"></div>
   <div id="demo3" style="width:400px; height:20px; background-color:blue; position:absolute;" class="test all"></div>
   <div id="demo4" style="width:20px; height:400px; background-color:green; position:absolute;" class="test all"></div>
  </div>
  
  <div style="width:25px; height:25px; background-color:white; position:absolute; border-radius:50%;" id="circle"></div>
 
 </body>
</html>

我编写了一个游戏。 在这个游戏中,我的函数检查 div1div2 之间是否存在碰撞。 或者如果它们是重叠的……你想怎么拼写。 没有轮换一切正常

但现在我遇到了一个问题。 我想用 transform:rotate(Xdeg);

旋转 div2

但是如果我这样做,我的碰撞计算就不起作用了。

我用这个:

var rect1 = {x: 5, y: 5, width: 50, height: 50}
var rect2 = {x: 20, y: 10, width: 10, height: 10}

if (rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.height + rect1.y > rect2.y) {
    // collision detected!
}

你有解决这个问题的想法吗?

感谢您的帮助:-)

有几种方法可以做到这一点。这个例子只是指导你如何用矩形来完成它。

这些是在此处完成的步骤:

  • 您必须计算要检查它们是否发生碰撞的所有矩形的所有旋转角的位置。要获得这些旋转的角,您可以使用多种方法。在此示例中,使用了 2d 向量和 2d 旋转矩阵:

    • 原点在矩形中心并指向矩形左上角(x,y)的向量:

      var center = {
          x: x + width / 2,
          y: y + height / 2
      };
      
      var vector = {
          x: (x - center.x),
          y: (y - center.y)
      };
      
    • 将此向量与旋转矩阵相乘以旋转此向量:

      // modified sin function to calulcate sin in the unit degrees instead of radians
      function sin(x) {
         return Math.sin(x / 180 * Math.PI);
      }
      
      // modified cos function 
      function cos(x) {
         return Math.cos(x / 180 * Math.PI);
      }
      
      var rotationMatrix = [[cos(angle), -sin(angle)],[sin(angle), cos(angle)]];
      
      var rotatedVector = {
          x: vector.x * rotationMatrix[0][0] + vector.y * rotationMatrix[0][1],
          y: vector.x * rotationMatrix[1][0] + vector.y * rotationMatrix[1][1]
      };
      
    • 最后得到旋转后的左上角,可以从矩形的中心开始,到旋转后的向量指向的地方。这是旋转后左上角所在的位置:

      {
          x: (center.x + rotatedVector.x),
          y: (center.y + rotatedVector.y)
      }
      
    • 上述所有步骤都由 getRotatedTopLeftCornerOfRect 完成,并且必须对所有其他角完成。前下位置 可以计算角点(右上角) 必须计算指向该角点的下一个向量。为了获得指向右上角的下一个向量,计算第一个向量(左上)和第二个向量(右上)之间的角度。当第三向量的角度增加第一角度和第二角度时,第三向量指向右下角,第四向量旋转第一、第二和第三角度之和的角度。所有这些都是在 setCorners 方法中完成的,这张图片部分显示了这个过程:


  • 要检测碰撞,有大量的算法。在这个例子中 Point in polygon algorithm is used to check each rotated corner of a rectangle whether a corner is with the border or within another rectangle, if so, then the method isCollided returns true. The Point in polygon algorithm is used in pointInPoly and can also be found here.

组合上述所有步骤很棘手,但它适用于各种尺寸的所有矩形,最重要的是您可以在没有库的情况下通过单击 "Run code snippet" 在这里测试它。

(测试浏览器:FF 50.1.0, IE:10-EDGE, Chrome:55.0.2883.87 m):

    var Rectangle = (function () {

        function sin(x) {
            return Math.sin(x / 180 * Math.PI);
        }

        function cos(x) {
            return Math.cos(x / 180 * Math.PI);
        }

        function getVectorLength(x, y, width, height){
            var center = {
                x: x + width / 2,
                y: y + height / 2
            };
            //console.log('center: ',center);
            var vector = {
                x: (x - center.x),
                y: (y - center.y)
            };
            return Math.sqrt(vector.x*vector.x+vector.y*vector.y);
        }

        function getRotatedTopLeftCornerOfRect(x, y, width, height, angle) {
            var center = {
                x: x + width / 2,
                y: y + height / 2
            };
            //console.log('center: ',center);
            var vector = {
                x: (x - center.x),
                y: (y - center.y)
            };
            //console.log('vector: ',vector);
            var rotationMatrix = [[cos(angle), -sin(angle)],[sin(angle), cos(angle)]];
            //console.log('rotationMatrix: ',rotationMatrix);
            var rotatedVector = {
                x: vector.x * rotationMatrix[0][0] + vector.y * rotationMatrix[0][1],
                y: vector.x * rotationMatrix[1][0] + vector.y * rotationMatrix[1][1]
            };
            //console.log('rotatedVector: ',rotatedVector);
            return {
                x: (center.x + rotatedVector.x),
                y: (center.y + rotatedVector.y)
            };
        }

        function getOffset(el) {
            var _x = 0;
            var _y = 0;
            while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
                _x += el.offsetLeft - el.scrollLeft;
                _y += el.offsetTop - el.scrollTop;
                el = el.offsetParent;
            }
            return {
                top: _y,
                left: _x
            };
        }

        function pointInPoly(verties, testx, testy) {
            var i,
                    j,
                    c = 0
            nvert = verties.length;
            for (i = 0, j = nvert - 1; i < nvert; j = i++) {
                if (((verties[i].y > testy) != (verties[j].y > testy)) && (testx < (verties[j].x - verties[i].x) * (testy - verties[i].y) / (verties[j].y - verties[i].y) + verties[i].x))
                    c = !c;
            }
            return c;
        }

        function Rectangle(htmlElement, width, height, angle) {
            this.htmlElement = htmlElement;
            this.width = width;
            this.height = height;
            this.setCorners(angle);
        }

        function testCollision(rectangle) {
            var collision = false;
            this.getCorners().forEach(function (corner) {
                var isCollided = pointInPoly(rectangle.getCorners(), corner.x, corner.y);
                if (isCollided) collision = true;
            });
            return collision;
        }

        function checkRectangleCollision(rect, rect2) {
            if (testCollision.call(rect, rect2)) return true;
            else if (testCollision.call(rect2, rect)) return true;
            return false;
        }

        function getAngleForNextCorner(anc,vectorLength) {
            var alpha = Math.acos(anc/vectorLength)*(180 / Math.PI);
            return 180 - alpha*2;
        }

        Rectangle.prototype.setCorners = function (angle) {
            this.originalPos = getOffset(this.htmlElement);
            this.leftTopCorner = getRotatedTopLeftCornerOfRect(this.originalPos.left, this.originalPos.top, this.width, this.height, angle);

            var vecLength = getVectorLength(this.originalPos.left, this.originalPos.top, this.width, this.height);
            //console.log('vecLength: ',vecLength);

            angle = angle+getAngleForNextCorner(this.width/2, vecLength);
            //console.log('angle: ',angle);
            this.rightTopCorner = getRotatedTopLeftCornerOfRect(this.originalPos.left, this.originalPos.top, this.width, this.height, angle);

            angle = angle+getAngleForNextCorner(this.height/2, vecLength);
            //console.log('angle: ',angle);
            this.rightBottomCorner = getRotatedTopLeftCornerOfRect(this.originalPos.left, this.originalPos.top, this.width, this.height, angle);

            angle = angle+getAngleForNextCorner(this.width/2, vecLength);
            //console.log('angle: ',angle);
            this.leftBottomCorner = getRotatedTopLeftCornerOfRect(this.originalPos.left, this.originalPos.top, this.width, this.height, angle);

            //console.log(this);
        };

        Rectangle.prototype.getCorners = function () {
            return [this.leftTopCorner,
                this.rightTopCorner,
                this.rightBottomCorner,
                this.leftBottomCorner];
        };

        Rectangle.prototype.isCollided = function (rectangle) {
            return checkRectangleCollision(this, rectangle);
        };

        return Rectangle;

    }) ();


    var rotA = 16;
    var widthA = 150;
    var heightA = 75;
    var htmlRectA = document.getElementById('rectA');

    var rotB = 28.9;
    var widthB = 50;
    var heightB = 130;
    var htmlRectB = document.getElementById('rectB');

    var msgDiv = document.getElementById('msg');

    var rectA = new Rectangle(htmlRectA, widthA, heightA, rotA);
    var rectB = new Rectangle(htmlRectB, widthB, heightB, rotB);

    window.requestAnimFrame = function(){
        return  window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                window.oRequestAnimationFrame      ||
                window.msRequestAnimationFrame;
    }();

    function draw(){

        rotA+=1.2;
        htmlRectA.setAttribute('style','-ms-transform: rotate('+rotA+'deg);-webkit-transform: rotate('+rotA+'deg);transform: rotate('+rotA+'deg)');

        rotB+=5.5;
        htmlRectB.setAttribute('style','-ms-transform: rotate('+rotB+'deg);-webkit-transform: rotate('+rotB+'deg);transform: rotate('+rotB+'deg)');

        rectA.setCorners(rotA);
        rectB.setCorners(rotB);

        if(rectA.isCollided(rectB)){
            msgDiv.innerHTML = 'Collision detected!';
            msgDiv.setAttribute('style','color: #FF0000');
        }
        else {
            msgDiv.innerHTML = 'No Collision!';
            msgDiv.setAttribute('style','color: #000000');
        }

        setTimeout(function(){
            window.requestAnimFrame(draw);
        },50);
    }

    window.requestAnimFrame(draw);
#rectA{
        background-color: #0000FF;
        width:150px;
        height:75px;
        position:absolute;

        top:60px;
        left:180px;

        -ms-transform: rotate(16deg);
        -webkit-transform: rotate(16deg);
        transform: rotate(16deg);
}

#rectB{
        background-color: #FF0000;
        width:50px;
        height:130px;
        position:absolute;

        top:140px;
        left:250px;

        -ms-transform: rotate(28.9deg);
        -webkit-transform: rotate(28.9deg);
        transform: rotate(28.9deg);

}
<div id="rectA">A</div>
<div id="rectB">B</div>

<div id="msg"></div>