【问题标题】:Collision between two elements with rotating旋转的两个元素之间的碰撞
【发布时间】:2017-05-20 06:25:06
【问题描述】:

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

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

感谢您的帮助:-)

【问题讨论】:

  • FWIW,这可能会比你目前的难度至少高出 10 倍。您必须计算旋转 div 的所有四个边的 (x, y) 坐标,然后测试这些线段是否与另一个 div 相交(或完全包含在其中)。
  • 非常感谢
  • 恕我直言,您现在在这个问题中的代码太多了,因此您获得答案的可能性更小。无论哪种方式,都可能有在线通用(非轴对齐)框/框相交测试的解决方案。

标签: javascript hover collision overlap onmouseover


【解决方案1】:

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

这些是在这里完成的步骤:

  • 您必须计算要检查它们是否被碰撞的所有矩形的所有旋转角的位置。要获得这些旋转角,您可以使用多种方法。在此示例中,使用了 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 算法用于检查矩形的每个旋转角是否与边框或在另一个矩形内,如果是,则方法 isCollided 返回 true。 pointInPoly中使用了Point in polygon算法,也可以在here找到。

结合上面描述的所有步骤很棘手,但它适用于所有大小的所有矩形,最好的是,您可以通过单击“运行代码 sn-p”在此处进行测试而无需库。

测试浏览器: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>

【讨论】:

  • PS:这里有什么想问的都可以问我。
  • 很抱歉,我现在才回答。我对这段代码印象深刻。非常感谢您的帮助。再次,我为我迟到的回复道歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多