javascript - 两个旋转元素之间的碰撞

标签 javascript hover collision overlap onmouseover

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

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

感谢您的帮助:-)

最佳答案

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

这些是这里完成的步骤:

  • 您必须计算要检查它们是否发生碰撞的所有矩形的所有旋转 Angular 的位置。要获得这些旋转的 Angular ,您可以使用多种方法。在此示例中,使用了 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 完成,并且还必须对所有其他 Angular 完成。前下位置 可以计算 Angular 点(右上角) 必须计算指向该 Angular 点的下一个向量。为了获得指向右上角的下一个向量,计算第一个向量(左上)和第二个向量(右上)之间的 Angular 。当第三向量的 Angular 增加第一 Angular 和第二 Angular 时,第三向量指向右下角,第四向量旋转第一、第二和第三 Angular 之和的 Angular 。所有这些都是在 setCorners 方法中完成的,这张图片部分显示了这个过程:

enter image description here


  • 要检测碰撞,有大量的算法。在这个例子中 Point in polygon算法用于检查矩形的每个旋转 Angular 是否有边界或在另一个矩形内,如果是,则方法 isCollided 返回 true。 pointInPoly 中使用了 Point in polygon 算法,也可以在 here 中找到.

组合上述所有步骤很棘手,但它适用于各种尺寸的所有矩形,最重要的是您可以在没有库的情况下通过单击“运行代码片段”在此处对其进行测试。

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

关于javascript - 两个旋转元素之间的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41489627/

相关文章:

javascript - JQuery 创建按钮但不可点击

javascript - Angular 2/4 @Input 只移动内在函数——不移动列表或对象

css - Firefox:将鼠标悬停在元素上时如何停止并检查添加的新样式?

java - Java 使用 .intersection 进行矩形和圆形碰撞

java - Box2d碰撞问题

javascript - 如何在 d3.layout.pack 图中使根节点圆居中?

javascript - promise -如何处理已知错误

javascript - Jquery Hover - 允许悬停在另一个 DIV 上出现在悬停按钮上

html - 将鼠标悬停在带有 CSS 的链接上查看动画

actionscript-3 - ActionScript 冲突 : solving exceptions and strange cases