检测和响应任何多边形内的球壁碰撞

Detection and response ball-to-wall collision inside any polygon(检测和响应任何多边形内的球壁碰撞)
本文介绍了检测和响应任何多边形内的球壁碰撞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要编写好的方法来检测和响应任何多边形内的球与墙碰撞.

例如,我有一个方法可以绘制一个在矩形内飞行的球.

ctx.beginPath();ctx.arc(x, y, ballRadius, 0, Math.PI*2);ctx.fillStyle = "#0095DD";ctx.fill();ctx.closePath();

检测和响应碰撞非常简单.

if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {dx = -dx;}if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {dy = -dy;}

但我有一个多边形:变量,每个点的位置(x 和 y).

var polygonPoints = [{×:240,是:30},{×:140,是:100},{×:180,y: 250},{×:320,y: 280},{×:400,是:50}

];

绘制我的多边形的函数:

ctx.beginPath();ctx.strokeStyle = '#333';ctx.moveTo(polygonPoints[0].x, polygonPoints[0].y);for (var i = 1, n = polygonPoints.length; i < n; i++) {ctx.lineTo(polygonPoints[i].x, polygonPoints[i].y);}ctx.lineTo(polygonPoints[0].x, polygonPoints[0].y);ctx.stroke();ctx.closePath();

如何检测和响应多边形内的碰撞?

下面是一些伪代码,展示了如何进行计算:

var wallNormalAngle = wallAngle-PI/2;//假设顺时针角度计算var 差异角度 = 入射角度 - wallNormalAngle;var 反射角度 = 入射角度 + 2 * 差异角度

Need to code good method for detection and response ball-to-wall collision inside any polygon.

For example, I have a method which draw a ball which fly inside a rectangle.

ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();

Detect and response that collision very simple.

if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
}

if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
    dy = -dy;
}

But I have a polygon: variable with positions (x and y) of each point.

var polygonPoints = [
{
    x: 240,
    y: 30
},
{
    x: 140,
    y: 100
},
{
    x: 180,
    y: 250
},
{
    x: 320,
    y: 280
},
{
    x: 400,
    y: 50
}

];

And function wich draw my polygon:

ctx.beginPath();
ctx.strokeStyle = '#333';
ctx.moveTo(polygonPoints[0].x, polygonPoints[0].y);
for (var i = 1, n = polygonPoints.length; i < n; i++) {
    ctx.lineTo(polygonPoints[i].x, polygonPoints[i].y);
}
ctx.lineTo(polygonPoints[0].x, polygonPoints[0].y);
ctx.stroke();
ctx.closePath();

How I can detect and response collisions inside a polygon?

Demo on jsfiddle.

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
var polygonPoints = [
	{
    	x: 240,
        y: 30
    },
    {
    	x: 140,
        y: 100
    },
    {
    	x: 180,
        y: 250
    },
    {
    	x: 320,
        y: 280
    },
    {
    	x: 400,
        y: 50
    }
];

function drawBall() {
    ctx.beginPath();
    ctx.arc(x, y, ballRadius, 0, Math.PI*2);
    ctx.fillStyle = "#0095DD";
    ctx.fill();
    ctx.closePath();
}

function drawPolygon() {
    ctx.beginPath();
    ctx.strokeStyle = '#333';
    ctx.moveTo(polygonPoints[0].x, polygonPoints[0].y);
	for (var i = 1, n = polygonPoints.length; i < n; i++) {
    	ctx.lineTo(polygonPoints[i].x, polygonPoints[i].y);
    }
    ctx.lineTo(polygonPoints[0].x, polygonPoints[0].y);
    ctx.stroke();
    ctx.closePath();
}

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBall();
    drawPolygon();
    
    if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
        dx = -dx;
    }
    if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
        dy = -dy;
    }
    
    x += dx;
    y += dy;
    window.requestAnimationFrame(draw);
}

draw();

canvas {
    border: 1px solid #333;
}

<canvas id="myCanvas" width="480" height="320"></canvas>

解决方案

Here's how to test for circle (ball) collisions) versus any line in your polygon.

First, calculate the closes point on a line relative to your ball:

function calcClosestPtOnSegment(x0,y0,x1,y1,cx,cy){

    // calc delta distance: source point to line start
    var dx=cx-x0;
    var dy=cy-y0;

    // calc delta distance: line start to end
    var dxx=x1-x0;
    var dyy=y1-y0;

    // Calc position on line normalized between 0.00 & 1.00
    // == dot product divided by delta line distances squared
    var t=(dx*dxx+dy*dyy)/(dxx*dxx+dyy*dyy);

    // calc nearest pt on line
    var x=x0+dxx*t;
    var y=y0+dyy*t;

    // clamp results to being on the segment
    if(t<0){x=x0;y=y0;}
    if(t>1){x=x1;y=y1;}

    return({ x:x, y:y, isOnSegment:(t>=0 && t<=1) });
}

Second, test if the ball is close enough to collide with that line like this:

var dx=ballX-nearestX;
var dy=ballY-nearestY
var isColliding=(dx*dx+dy*dy<ballRadius*ballRadius);

Finally, if the ball collided with that side, calculate the ball's reflection angle (== its outgoing angle):

Here's an illustration of the angles involved in the calculation:

  • The red line indicates the ball's incoming angle.
  • The gold line indicates the ball's outgoing angle.
  • The outgoing angle equals the incoming angle plus twice the diff-angle.

And here's some pseudo-code showing how to do the calculation:

var wallNormalAngle = wallAngle-PI/2; // assuming clockwise angle calculations
var differenceAngle = incidenceAngle - wallNormalAngle;
var reflectionAngle = incidenceAngle + 2 * differenceAngle

这篇关于检测和响应任何多边形内的球壁碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Update another component when Formik form changes(当Formik表单更改时更新另一个组件)
Formik validation isSubmitting / isValidating not getting set to true(Formik验证正在提交/isValiating未设置为True)
React Validation Max Range Using Formik(使用Formik的Reaction验证最大范围)
Validation using Yup to check string or number length(使用YUP检查字符串或数字长度的验证)
Updating initialValues prop on Formik Form does not update input value(更新Formik表单上的初始值属性不会更新输入值)
password validation with yup and formik(使用YUP和Formick进行密码验证)