我目前正在开发(自上而下)游戏,该游戏需要代码才能使弹丸从圆形表面弹起。
我想要的工作方式是当弹丸击中表面
从圆的中心画一条假想的线
然后将其用作法线来计算新轨迹的反射角。
物理(例如重力)是完全没有必要的。是否有或多或少的简单方法?
最佳答案
将线段从圆上反射。
这将使折弯的线段脱离一个圆。圆弧截距的反射线段和入射线段的长度将等于原始线段的长度。如果您只想反射光线,请在计算出反射向量后停止计算。这也假定输入线段从圆的外部开始。如果行在行内开始,则失败。您可以通过获取从圆心到直线起点的距离(如果该距离小于圆弧半径)来检查直线是否在圆弧内,然后直线在圆弧内开始。
这是伪代码,因为我不使用PHP。
sqrt()是获取数字的sqrt的函数。
入射光线作为线段。其中line.x1,line.y1是开始,x2,y2是结束
line x1,y1,x2,y2
具有x,y位置和r半径的圆
circle x,y,r
首先,您需要获取线段圆的截距(如果有)。因此,找到直线上最接近圆心的点,然后查看该点到圆心的距离是否小于圆半径,如果是,则线段可能会截取。如果距离大于,则没有拦截。
将线段转换为矢量
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”,然后从该点到截点的距离为length circle.r,然后返回到最接近点的距离未知,但是我们知道这三个长度构成的三角形是直角三角形,缺少的一面是
lenToIntercept = sqrt(circle.r * circle.r - dist * dist);
这给了我们从直线上最近的点到圆心的距离,然后沿着直线向起点开始返回到截点。为方便起见,我将通过除以线段的长度将该距离转换为单位换算的距离(标准化)
lenToIntercept = lenToIntercept / sqrt(len2)
从输入线的起点到直线上最近的点到圆心的标准化距离减去该标准化长度。
unitDist = unitDist - lenToIntercept;
如果到截距点的新unitDist为> = 0和
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;
减去输入线向量,得到输出线向量
reflectedX = tx - vx;
reflectedY = ty - vy;
通过获取向量的长度对其进行归一化
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;