其实这篇博客算是备忘,权当以后要用的时候再看看,同时也希望有更好的方法来解决,万分感谢!
起因
做了一个关卡界面,然后每个关卡之间有一根连线。因为关卡图标不是预先使用NGUI摆放好的,而是用代码动态生成的,并且关卡图标生成的位置没有规律,所以连线也需要动态添加,于是就需要实现一个两点之间连一条直线的小算法。
如图片所示,关卡图标在 X Y 轴上的位置是随机的,是使用代码动态生成的,而不是预先在Unity上使用NGUI摆放好的。
当动态生成关卡后,就需要在两个关卡之间添加那条蓝色的连线了,需要达到的效果如下图示:
P.S.示意图是随便摆放的,请不要在意 ->_->
要动态添加连线,其实实现的功能就是两点之间画线,如果可以的话还可以把连线当做一个三角形的斜边。为了摆放连线需要计算的几个参数。
- 两个关卡连线的长度,即两点之间的距离 Distance
- 两个关卡连线的中点位置,即两点之间的中心位置 Center
- 两个关卡之间的夹角 Angle
有了上面的三个参数我们就可以摆放连线图片了,先拉伸连线图片的宽度(width)到Distance,再把连线图片放到 Center 位置,最后以 Angle 角度旋转连线即可。
计算所需参数
1.计算两点之间的距离
可以使用 Vector3 自带的 Distance 方法
float distance = Vector3.Distance(fromPos, toPos);
使用 Vector3 自带的 Lerp 方法,总感觉应该还有更好的方法
Vector3 centerPos = Vector3.Lerp(fromPos, toPos, 0.5f);
关于夹角这个,开始的时候是使用的 Vector3 中的 Angle 方法,但是算出来始终是错误的,不得其解,最后没办法就使用了三角函数来算夹角了。
如图所示,可以这样构造一个三角形来计算边2和斜边的夹角,然后连线旋转就使用这个夹角,计算方法如下
float TanAngle(Vector2 from, Vector2 to)
{
float xdis = to.x - from.x;//计算临边长度
float ydis = to.y - from.y;//计算对边长度
float tanValue = Mathf.Atan2(ydis, xdis);//反正切得到弧度
float nnangle = tanValue * Mathf.Rad2Deg;//弧度转换为角度
return nnangle;
}
纯数学计算了,也没有技巧性可言了。先计算边2长度,再计算边1长度,然后调用 Mathf 的 Atan2 反正切方法得到一个弧度值,再把弧度值转换为角度。
有更好方法的可以推荐给我用啊。
好了,有了上面的三个参数,就可以动态生成连线,并添加到关卡界面上了。核心代码如下,最后旋转时调用的是 Quaternion的 AngleAxis
//fromPos 是起始点的 localPosition toPos 是终点的localPosition
float distance = Vector3.Distance(fromPos, toPos);//计算两个关卡之间的距离
Vector3 centerPos = Vector3.Lerp(fromPos, toPos, 0.5f);//计算两个关卡之间的中心点位置
float angle = TanAngle(fromPos, toPos);//计算夹角
GameObject lineGo = NGUITools.AddChild(lineParent, linego);//生成新的连线
UISprite lineSp = lineGo.GetComponent<UISprite>();//获取连线的 UISprite 脚本
lineSp.width = (int)distance;//将连线图片的宽度设置为上面计算的距离
lineGo.transform.localPosition = centerPos;//设置连线图片的坐标
lineGo.transform.localRotation = Quaternion.AngleAxis(angle, Vector3.forward);//旋转连线图片