2017-01-05 3 views
1

Столкновение между двумя элементами с вращающимися

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

 
\t \t 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) { 
 
\t \t \t 
 
\t \t \t console.log("now"); 
 
\t \t } 
 
\t \t 
 
\t \t if(direction == "left") 
 
\t \t { 
 
\t \t \t if(offset.left - 50 > 0) 
 
\t \t \t { 
 
\t \t \t \t $("#circle").css("left", ($("#circle").position().left - 2) + "px"); 
 
\t \t \t } 
 
\t \t } 
 
\t \t if(direction == "up") 
 
\t \t { 
 
\t \t \t if(offset.top - 50 > 0) 
 
\t \t \t { 
 
\t \t \t \t $("#circle").css("top", ($("#circle").position().top - 2) + "px"); 
 
\t \t \t } 
 
\t \t } 
 
\t \t if(direction == "right") 
 
\t \t { 
 
\t \t \t if((offset.left + 50) < $(window).width()) 
 
\t \t \t { 
 
\t \t \t \t $("#circle").css("left", ($("#circle").position().left + 2) + "px"); 
 
\t \t \t } 
 
\t \t } 
 
\t \t if(direction == "down") 
 
\t \t { 
 
\t \t \t if((offset.top + 50) < $(window).height()) 
 
\t \t \t { 
 
\t \t \t \t $("#circle").css("top", ($("#circle").position().top + 2) + "px"); 
 
\t \t \t } 
 
\t \t } 
 
\t \t 
 
\t \t 
 
\t \t 
 
\t \t ID=window.setTimeout("looper();", 1); 
 
\t } 
 

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

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

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

Я запрограммированный игру. В этой игре моя функция проверяет, есть ли столкновение между div1 и div2. Или если они перекрываются или так ... как вы хотите записать это. Без вращения все в порядке.

Но теперь у меня есть проблема. Я хочу, чтобы повернуть div2 с transform:rotate(Xdeg);

, но если я делаю это мой расчет для столкновения dosen't работы.

Я использую это:

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

у вас есть какие-либо идеи, чтобы решить эту проблему?

Спасибо за помощь :-)

+0

FWIW, это, скорее всего, получится у в 10 раз сложнее, чем у вас в настоящее время. Вам нужно будет вычислить (x, y) координаты всех четырех ребер повернутого div, а затем проверить, пересекается ли какой-либо из этих сегментов (или полностью содержится внутри) другого div. – Alnitak

+0

Большое спасибо – WilliWespe

+0

ИМХО, у вас теперь слишком много кода в этом вопросе, так что вы даже менее склонны получить ответ. В любом случае, вероятно, будут решения для общих (без осевой выровненности) тестов пересечения ящиков и ящиков в Интернете. – Alnitak

ответ

2

Есть несколько способов сделать это. Этот пример просто подскажет вам, как это можно сделать с помощью прямоугольников.

Эти шаги, которые сделаны здесь:

  • Вы должны вычислить положение всех повернуты углов всех прямоугольников, которые вы хотите проверить, являются ли они столкнулись. Чтобы получить эти поворотные углы, вы можете использовать несколько методов. В этом примере используется 2d-векторы и 2d-вращения-матрицы:

    • вектор, который имеет свое начало в центре прямоугольника и направляет в верхнем левом углу (х, у) прямоугольник:

      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 -метода и это изображение показывает этот процесс частично:

enter image description here


  • Для обнаружения столкновения есть тонны алгоритмов. В этом примере алгоритм Point in polygon используется для проверки каждого повернутого угла прямоугольника, находится ли угол с границей или внутри другого прямоугольника, если это так, то метод isCollided возвращает true. Алгоритм точки в многоугольнике используется в pointInPoly и также может быть найден here.

Сочетание всех описанных выше шагов было сложным, но оно работает со всеми прямоугольниками всех размеров и, самое лучшее, вы можете протестировать его прямо здесь без библиотеки, нажав «Выполнить фрагмент кода».

(протестированные браузеры: FF 50.1.0, IE: 10-EDGE, Chrome: 55.0.2883.87 м):

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>

+0

PS: Не стесняйтесь спрашивать меня, что вы хотите здесь. – Blauharley

+0

Мне очень жаль, что я только сейчас отвечаю. Я действительно впечатлен этим кодом. Большое спасибо за вашу помощь. И снова я прошу прощения за мой поздний ответ. – WilliWespe

+0

Абсолютный без проблем, добро пожаловать! – Blauharley

Смежные вопросы