首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >弹丸在曲面上弹跳- Python 3

问弹丸在曲面上弹跳- Python 3
EN

Stack Overflow用户
提问于 2016-01-07 19:57:56
回答 2查看 1.1K关注 0票数 1

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

我希望这样做的方式是,当弹丸击中表面

​

从圆心画出一条假想的线。

​

然后作为法线来计算新轨道的反射角。

​

物理学(如引力)是完全没有必要的。这样做有多少简单的方法吗?

EN

回答 2

Stack Overflow用户

发布于 2016-01-09 02:09:07

反映了一个圆圈的线段。

这将使反射线段脱离一个圆。圆周截距的反射线段和传入线段的长度将等于原始线段的长度。如果你只想要反射射线,当反射矢量被计算出来时,就停止计算。这还假设传入线段开始于圆圈之外。如果行在行内开始,那么它就失败了。你可以通过获得从圆心到直线的距离来检查这条线是否从圆内部开始,如果它小于圆半径,那么这条线就从圆圈内部开始。

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

以线段形式传入的射线。line.x1,line.y1是开始,x2,y2是终点

代码语言:javascript
复制
line x1,y1,x2,y2

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

代码语言:javascript
复制
circle x,y,r

首先,你需要得到线段圆截距,如果有的话。找出直线上与圆心最近的点,看看从这个点到圆心的距离是否小于圆radius.If,那么线段可能会被截取。如果距离大于没有拦截。

将线段转换为向量

代码语言:javascript
复制
vx = line.x2 - line.x1;
vy = line.y2 - line.y1;

求出线段平方的长度

代码语言:javascript
复制
len2 = (vx * vx + vy * vy);

获取从直线起点到离圆心最近的点的归一化距离。

代码语言:javascript
复制
unitDist =  ((circle.x - x1) * vx + (circle.y - y1) * vy) / len2;

然后利用归一化距离求出绝对位置上最接近圆的点。

代码语言:javascript
复制
x = x1 + vx * unitDist;
y = y1 + vy * unitDist;

从那个点到圆心的距离

代码语言:javascript
复制
dist =  sqrt((x - circle.x)*(x - circle.x)+ (y - circle.y)*(y - circle.y));    

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

代码语言:javascript
复制
if( dist > circle.r) exit;

现在我们知道这条线会截取圆圈,我们需要检查线段是否截取,所以我们找到了直线开始处的截取点,看看这个点是否在线段上。

因此,从线上的最近点到圆中心是长度‘`dist’,我们刚刚计算出,从那里到截取点是长度圆圈。r,然后返回最近点的距离未知,但我们知道,三长的三角形是一个直角三角形,缺失的边是一个三角形。

代码语言:javascript
复制
lenToIntercept = sqrt(circle.r * circle.r - dist * dist);

这给了我们从线上最近的点到圆心的距离,沿着这条线向开始的方向返回到截取点。为了方便起见,我将通过除以线段的长度将该距离转换为单位缩放距离(标准化)。

代码语言:javascript
复制
lenToIntercept = lenToIntercept / sqrt(len2)

减去从入线开始到线上最接近圆中心的距离的归一化长度。

代码语言:javascript
复制
unitDist = unitDist - lenToIntercept;

如果到截取点的新unitDist是>= 0和<= 1,那么我们知道线段已经拦截了圆,否则线段没有截获圆圈,我们可以退出。

代码语言:javascript
复制
if(unitDist < 0 or unitDist > 1) exit; // no intercept

现在,我们可以通过将向量乘以从入线开始到截取点的归一化距离来计算截取点的绝对位置。

代码语言:javascript
复制
x = line.x1 + unitDist * vx;
y = line.y1 + unitDist * vy;

现在我们可以算出倒影了。

获取从圆心到截取点的矢量

代码语言:javascript
复制
cx = x - circle.x;
cy = y - circle.y;

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

代码语言:javascript
复制
tx = -cy;
ty = cx;

将切线向量归一化。我们知道它和圆半径是一样长的,因为它只是从圆心到截取点的旋转线,所以我们可以用圆半径对切线向量进行归一化。

代码语言:javascript
复制
tx = tx / circle.r;
ty = ty / circle.r;

我们还需要对传入的直线向量进行规范化,以便将其除以其长度。

代码语言:javascript
复制
vx = vx / sqrt(len2);
vy = vy / sqrt(len2);

现在得到切线和直线的点乘积。它是从传入矢量端到切线的距离,平方。

代码语言:javascript
复制
dot = vx * tx + vy * ty;

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

代码语言:javascript
复制
dot = dot * 2;

现在将正规化的切线矢量加长为点量。

代码语言:javascript
复制
tx = tx * dot;
ty = ty * dot;

并减去传入线向量,给出出线的向量。

代码语言:javascript
复制
reflectedX = tx - vx;
reflectedY = ty - vy;

通过求出向量的长度来规范该向量

代码语言:javascript
复制
lengR = sqrt(reflectedX * reflectedX + reflectedY * reflectedY);

然后把反射线除以这个长度

代码语言:javascript
复制
reflectedX = reflectedX / lengR;
reflectedY = reflectedY / lengR;

现在,要计算直线的反射部分,即从圆圈截取点到传入线末端的距离。我们已经有了到截取点的归一化距离,所以剩下的距离是

代码语言:javascript
复制
remainDist = 1-unitDist;

将归一化距离乘以传入线路长度。

代码语言:javascript
复制
remainDist = remainDist * sqrt(len2);

现在,将反射的规范化向量乘以这个长度。

代码语言:javascript
复制
reflectedX = reflectedX * remainDist;
reflectedY = reflectedY * remainDist;

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

代码语言:javascript
复制
reflectedLine.x1 = x;
reflectedLine.y1 = y;
reflectedLine.x2 = x + reflectedX;
reflectedLine.y2 = y + reflectedY;
票数 2
EN

Stack Overflow用户

发布于 2016-01-07 20:16:56

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

  • 直线方程:y = a*x+B (你知道这个) 线的->角= theta0 = arctg(a)
  • 半径角:theta1 = arctg((y1-y0)/(x1-x0))
  • 第二条线的角度= theta2 = 2*theta0 - theta1
  • 反弹线方程= y = y1 + tg(theta2)*(x-x1)

虽然您可能需要一个数学库,但这应该可以工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34664048

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档