弹丸弹回曲面游戏,Python 3

2024-04-20 03:39:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在做一个(自上而下)的游戏,需要一个代码来弹离一个圆形的表面。在

我想让它工作的方式是当炮弹击中表面enter image description here

从圆心enter image description here画一条假想线

然后作为法线来计算新轨迹的反射角enter image description here

物理学(如重力)是完全没有必要的。有没有一种或多或少简单的方法?在


Tags: 方法代码游戏轨迹方式圆形表面重力
2条回答

从圆上反射线段。

这将使反折线段离开圆。反射线段和引入线段到圆截距的长度等于原始线段的长度。如果你只需要反射光线,只要在计算出反射矢量后停止计算。这也假定引入线段从圆外部开始。如果线从线内开始,那么它就失败了。你可以通过获取圆心到直线起点的距离来检查直线是否从圆内开始。如果这小于圆半径,则直线从圆内开始。在

这是伪代码,因为我不做PHP。 sqrt()是一个函数,用于获取数字的sqrt。在

作为线段的入射光线。其中,line.x1,line.y1是开始,x2,y2是结束

line x1,y1,x2,y2

具有x,y位置和r半径的圆

^{pr2}$

首先你需要得到线段圆截距(如果有的话)。所以在这条线上找到离圆心最近的点,看看这个点到圆心的距离是否小于圆半径。如果然后线段可能会截获。如果距离大于没有截获。在

将线段转换为矢量

vx = line.x2 - line.x1;
vy = line.y2 - line.y1;

得到线段长度的平方

len2 = (vx * vx + vy * vy);

获取从直线起点到最接近圆心的点的标准化距离

unitDist =  ((circle.x - x1) * vx + (circle.y - y1) * vy) / len2;

然后使用标准化的距离,在绝对位置上获得最接近圆的点。在

x = x1 + vx * unitDist;
y = y1 + vy * unitDist;

现在求出从那个点到圆心的距离

dist =  sqrt((x - circle.x)*(x - circle.x)+ (y - circle.y)*(y - circle.y));    

如果距离小于圆半径,则存在截获的可能性。如果没有,那么就没有截获,所以退出,因为没有反射。在

if( dist > circle.r) exit;

现在我们知道直线会截住圆,我们需要检查直线段是否截获,所以我们找到了朝向直线起点的截距点,看看这个点是否在线段上。在

因此,从直线上最近的点到圆心的距离是长度'dist',我们刚刚计算出,从那里到截距点是长度圆,然后回到最近点的距离是未知的,但是我们知道三个长度组成的三角形是一个直角三角形,缺边是

lenToIntercept = sqrt(circle.r * circle.r - dist * dist);

这给了我们从直线上最近的点到圆心的距离,沿着直线回到起点,到达截距点。为了方便起见,我将通过除以线段的长度将该距离转换为单位比例的距离(标准化)

lenToIntercept = lenToIntercept / sqrt(len2)

从引入线起点到直线上距圆心最近点的标准化距离减去该标准化长度。在

unitDist = unitDist - lenToIntercept;

如果到截距点的新单位距离为>;=0且<;=1,则我们知道线段已截获圆,否则线段未截获圆,我们可以退出。在

if(unitDist < 0 or unitDist > 1) exit; // no intercept

现在我们可以计算截距点的绝对位置,方法是将向量乘以从引入线起点到截获点的标准化距离

x = line.x1 + unitDist * vx;
y = line.y1 + unitDist * vy;

现在我们可以计算出反射。在

从圆心到截距点的矢量

cx = x - circle.x;
cy = y - circle.y;

我们需要切线使计算更容易,所以通过顺时针旋转90度来获得切线

tx = -cy;
ty = cx;

使切线向量法线化。我们知道它的长度和圆半径一样,因为它只是从圆心到截距点的旋转线,所以我们可以用圆半径使切线向量正规化

tx = tx / circle.r;
ty = ty / circle.r;

我们还需要使输入线矢量正常化,因此将其除以其长度

vx = vx / sqrt(len2);
vy = vy / sqrt(len2);

现在去拿切线与直线段的点积。它是从输入向量端到切线的距离,平方

dot = vx * tx + vy * ty;

加倍,因为我们想得到切线另一边的反射。在

dot = dot * 2;

现在,将法线化的切线向量延长一点

tx = tx * dot;
ty = ty * dot;

再减去进线向量,得到出线向量

^{pr21}$

通过获取向量的长度使其正规化

lengR = sqrt(reflectedX * reflectedX + reflectedY * reflectedY);

把反射线除以这个长度

reflectedX = reflectedX / lengR;
reflectedY = reflectedY / lengR;

现在计算直线的反射部分,即从圆截距点到引入线末端的距离。我们已经得到了沿直线到截距点的标准化距离,所以剩余的距离是

remainDist = 1-unitDist;

将标准化距离乘以输入线长度

remainDist = remainDist * sqrt(len2);

现在将反射的法线化向量乘以这个长度

reflectedX = reflectedX * remainDist;
reflectedY = reflectedY * remainDist;

最后,创建新的反射线段,即从截距点到该点的直线加上反射矢量

reflectedLine.x1 = x;
reflectedLine.y1 = y;
reflectedLine.x2 = x + reflectedX;
reflectedLine.y2 = y + reflectedY;

假设你知道圆的原点(x0,y0),碰撞点(x1,y1),以及直线的方程,你所要做的就是计算直线和半径之间的角度差:

  • 直线方程:y = a*x+B(你知道这个)
    ->;线的角度=theta0 = arctg(a)
  • {cd5>半径^
  • 第二行的角度=theta2 = 2*theta0 - theta1
  • {cd7>

虽然您可能需要一个数学库,但这应该是可行的

相关问题 更多 >