之前在玩福尔摩斯恶魔之女的时候感觉里面的线索组合贼帅,如图
于是就仿他做了一个
用直接用unity旋转应该也能做,但是我想试试用数学来做,于是:
先分析效果:简单来说就是线索会根据鼠标位置围绕屏幕中心进行旋转,当玩家选中线索之后,线索围绕选中的线索位置进行旋转,当选中的两个线索可以合并的时候,切换到另一个界面进行结论选择。
数学基础:先看没选中线索的时候,物体旋转这个问题,如果放在3维空间比较复杂,要涉及圆的3维方程,我们可以放在2维空间里,把问题简单化,这个问题就变成了线索在一个2维的园内,沿着鼠标位置与圆心组成的向量进行移动,如果碰到了圆的边界,就反向移动,十分简单。
要注意的是,线索不是围着同一个圆进行旋转的,位置不同,半径不同,要找好半径。
也别忘了,根据线索的位置对线索进行缩放,要记录线索是在正面还是背面。
比较简单,我就放一部分代码吧。
//确定圆点到鼠标点连线方程的斜率
float k = deltaMouseAndScreenMiddle.y / deltaMouseAndScreenMiddle.x;
//确定垂直于圆点到鼠标点连线方程的斜率
float k2 = -1 / k;
//这里通过求点到直线垂足的距离的两倍确定单程距离
//然后通过乘以百分比确定移动距离
float a = 1 / k;
float b = 1;
float c = 0;
float m = x;
float n = y;
float xChuiZu = (b * b * m - a * b * n - a * c) / (a * a + b * b);
float yChuiZu = (a * a * n - a * b * m - b * c) / (a * a + b * b);
if (k == 0)
{
xChuiZu = 0;
yChuiZu = n;
}
else if (k > 1000000)
{
xChuiZu = m;
yChuiZu = 0;
}
//这里位移的长度并不是单纯的点到垂足的距离,而是延长这条线与圆交点到垂足的长度
//这条线的方程为 yl = kxl+y-kx;
//而圆的方程为 xl*xl + yl*yl = radius*radius
// xl^2 +k^2*xl^2 + 2*(y-k*x)*xl + (y-k*x)^2 - r^2 =0;
// 二次方程求根 公式 (-b+sqrt(b^2-4*a*c))/(2*a);
//b = 2 * (y - k * x);
//a = 1 + k * k;
//c = (y - k * x) * (y - k * x) - radius * radius;
//float xSphere = (-b + Mathf.Sqrt(b *b - 4 * a * c)) / (2 * a);
//float ySphere = k * xSphere - k * x - y;
//用上面求出的点计算到垂足的距离就是要求的单程位移
//上面方法求出来的结果有问题
//决定采用半径的平方减去垂点到圆心的向量的长的方式来计算单程位移
float displacement = Mathf.Sqrt(radius * radius - ((xChuiZu * xChuiZu) + (yChuiZu * yChuiZu)));
float displacement_x_xChuiZu = Mathf.Sqrt((x - xChuiZu) * (x - xChuiZu) + (y - yChuiZu) * (y - yChuiZu));
//这里x的变化数值并不能单纯的用百分比乘以单程路长求出
//这里单程长度是xy向量长度
//想要找出xy单程变化长度应该求出对应圆上的点
//然后使用圆上的点减去垂足的点,求出的xy是单程xy长度
//然后再乘上百分比就是xy变化数值
float x_xChuiZu = ((x - xChuiZu) * displacement) / displacement_x_xChuiZu + xChuiZu;
float y_yChuiZu = ((y - yChuiZu) * displacement) / displacement_x_xChuiZu + yChuiZu;
//为了让他的变化看起来像球
//点在不同位置的变化应该是不一样的
//我们可以使用点到圆心距离来影响变化速率
//效果与下面的缩放使用的方法一样
float changeSpeed = (displacement - displacement_x_xChuiZu) / displacement + 0.3f;
//float changeSpeed = 0.01f + (Mathf.Sqrt(400 * 400 - usedInChangeSpeed * usedInChangeSpeed)) / 400;
// 再根据鼠标离着圆点远近对旋转速度进行调整
// 这里的数值可以在调整
float mouseRotateSpeed = deltaMouseAndScreenMiddle.magnitude / 700;
mouseRotateSpeed = Mathf.Sqrt((deltaMouseAndScreenMiddle.x / 980) * (deltaMouseAndScreenMiddle.x / 980) + (deltaMouseAndScreenMiddle.y / 540) * (deltaMouseAndScreenMiddle.y / 540));
//这里给他平方的作用是曾大位置对移动速度的影响
// 比如以前是0.9 平方就是 0.81 1.1 就是 1.21
// 所以越近的就越满,越远的就越小
// mouseRotateSpeed = mouseRotateSpeed * mouseRotateSpeed;
float xDelta = mouseRotateSpeed * changeSpeed * xPercent * (x_xChuiZu - xChuiZu);
float yDelta = mouseRotateSpeed * changeSpeed * xPercent * ((y_yChuiZu - yChuiZu));
// 通过x的变化数值确定x的变化数值
float xText;
float yText;
//大于零即z在正半轴上,也就是屏幕内 向着鼠标点移动
if ((deltaMouseAndScreenMiddle.x * k2 - deltaMouseAndScreenMiddle.y) * (x * k2 - y) > 0)
{
xText = xDelta;
yText = yDelta;
}
else
{
xText = -xDelta;
yText = -yDelta;
}
ClueTextList[i].transform.position += new Vector3(xText, yText) * ClueTowards[i];
if ((ClueTextList[i].transform.position - new Vector3(Screen.width / 2, Screen.height / 2, 0)).magnitude > radius)
{
ClueTowards[i] *= -1;
ClueTextList[i].transform.position += new Vector3(xText, yText) * ClueTowards[i];
}
//要点在不同位置进行不同程度的缩放
//以点到圆点距离进行判断
float usedInChangeScale = Mathf.Sqrt(radius * radius - x * x - y * y);
float textScale = 0;
if (ClueTowards[i] > 0)
{
textScale = 1.5f - (usedInChangeScale / radius);
}
else
{
textScale = 1.3795f + (usedInChangeScale / radius);
}
ClueTextList[i].transform.localScale = Vector3.one * textScale * textScaleAdject;