主要思路是计算获取弹板平面与圆形碰撞体的切点,切点与圆心相连获取正确的发射方向
通过下面的函数获取切点位置元组
public static (Vector2 point1,Vector2 point2) GetPointOfTangency(Vector2 pointOutOfCircle, Vector2 center, float radius)
{
Vector2 point1 = new Vector2(0, 0);
Vector2 point2 = new Vector2(0, 0);
var pointOfTangency = (point1:point1,point2:point2);
//求出点到圆心的距离
float distance = Mathf.Sqrt(Mathf.Pow(pointOutOfCircle.x - center.x, 2) + Mathf.Pow(pointOutOfCircle.y - center.y, 2));
//判断是否符合要求 distance <= r 不符合则返回
if(distance <= radius)
{
Debug.Log("error:数值不在范围内");
return pointOfTangency;
}
//点p到切点的距离
float length = Mathf.Sqrt(Mathf.Pow(distance, 2) - Mathf.Pow(radius, 2));
//点到圆心的单位向量
Vector2 pointToCenter = new Vector2(center.x - pointOutOfCircle.x, center.y - pointOutOfCircle.y).normalized;
//test
BoardRaycast.pointToCenter = pointToCenter;
//计算切线与点心连线的夹角
float angle = Mathf.Asin(radius / distance);
//向正反两个方向旋转单位向量
pointOfTangency.point1.x = pointToCenter.x * Mathf.Cos(angle) - pointToCenter.y * Mathf.Sin(angle);
pointOfTangency.point1.y = pointToCenter.x * Mathf.Sin(angle) + pointToCenter.y * Mathf.Cos(angle);
pointOfTangency.point2.x = pointToCenter.x * Mathf.Cos(-angle) - pointToCenter.y * Mathf.Sin(-angle);
pointOfTangency.point2.y = pointToCenter.x * Mathf.Sin(-angle) + pointToCenter.y * Mathf.Cos(-angle);
//test
BoardRaycast.tanDir1 = pointOfTangency.point1;
BoardRaycast.tanDir2 = pointOfTangency.point2;
//得到新坐标
pointOfTangency.point1.x = pointOfTangency.point1.x * length + pointOutOfCircle.x;
pointOfTangency.point1.y = pointOfTangency.point1.y * length + pointOutOfCircle.y;
pointOfTangency.point2.x = pointOfTangency.point2.x * length + pointOutOfCircle.x;
pointOfTangency.point2.y = pointOfTangency.point2.y * length + pointOutOfCircle.y;
return pointOfTangency;
}
}
该方法参考自(9条消息) 求圆外一点做圆切线的切点坐标(算法)_计算圆外一点的切点_zdpBuilder的博客-CSDN博客但原文代码中的公式存在一些错误,笔者发布在此的函数是已修正后的版本。
public Vector2 GetFlipVector(Area area)
{
Vector2 flipDir = new Vector2();
Vector2 center = ballCollider.transform.position;
var pointOfTangency = Operator.GetPointOfTangency(raySourcePos,center,ballCollider.radius);
if(area == Area.right)
{
flipDir = new Vector2(center.x - pointOfTangency.point1.x, center.y - pointOfTangency.point1.y).normalized;
}
else
{
flipDir = new Vector2(center.x - pointOfTangency.point2.x, center.y - pointOfTangency.point2.y).normalized;
}
//test();
return flipDir;
}
在获取了切点坐标后,更加弹珠所在屏幕位置选取正确的切点位置并与弹珠圆心做计算即可获取正确的弹射方向。