|
先上最终效果
*最后在挥动方面的角度计算仍有问题,有问题的代码放在最后请大手子们指点一下。
===================================================
昨晚看到了这题,但是觉得可能会上头导致失眠,所以没写,结果还是失眠了……
如果要我个人说的话,我建议让美术制作“轻度弯曲”“中度弯曲”“重度弯曲”三个动画,然后让程序根据挥动力度在这三者间切换就好。
现在我写的是另一个解决方案,即通过代码更新Mesh来实现。
废话不多说,关键代码如下:
首先是计算插值的代码,也是照搬的逍遥剑客的算法:
private float GetCantileverW(float x, float L)
{
return Mathf.Pow(x, 2f) * (3 * L - x) / (2 *Mathf.Pow(L, 3f));
}
其次是更新Mesh用到的代码,代码都在注释里我就不废话解释了:
public void RefreshRod(float distance)
{
CantileverDistance = distance;
//第一步,制造一个鱼竿的Mesh
//1.0,清理数据
RodMesh.Clear();
colors.Clear();
vertices.Clear();
triangles.Clear();
//1.1,拿到每个节点的长度
//1.1.1,计算弯曲之后的鱼竿节点
List<Vector3> rodeList = new List<Vector3>();
for (int i = 0; i < RodeCount; i++)
{
rodeList.Add(new Vector3(0, RodeLength * i, CantileverDistance * GetCantileverW(RodeLength * i, RodeLength * (RodeCount -1))));
}
//1.1.2,由于弯曲之后鱼竿长度会变相增长,所以进行一次缩放
float realLength = 0f;
for (int i = 1; i < RodeCount; i++)
{
realLength += (rodeList - rodeList[i - 1]).magnitude;
}
for (int i = 1; i < RodeCount; i++)
{
rodeList *= RodeLength * (RodeCount - 1) / realLength;
}
//1.1.3*,绘制顶端到钓块的线
Debug.DrawLine(
fish.transform.position,
transform.TransformPoint(rodeList[RodeCount - 1])
);
//1.2,根据每个节点长度,计算出面片
float unitEuler = 2 * Mathf.PI / (float) SplitCount;
for (int i = 1; i < RodeCount; i++)
{
for (int j = 0; j < SplitCount; j++)
{
float x1 = Radius * Mathf.Sin(unitEuler * j);
float x2 = Radius * Mathf.Sin(unitEuler * (j + 1));
float z1 = Radius * Mathf.Cos(unitEuler * j);
float z2 = Radius * Mathf.Cos(unitEuler * (j + 1));
AddQuad(
new Vector3(x1, rodeList.y, z1 + rodeList.z),
new Vector3(x2, rodeList.y, z2 + rodeList.z),
new Vector3(x1, rodeList[i-1].y, z1 + rodeList[i-1].z),
new Vector3(x2, rodeList[i-1].y, z2 + rodeList[i-1].z)
);
AddQuadColor(Color.gray, Color.white);
}
}
//1.3,计算上下顶面
for (int j = 0; j < SplitCount; j++)
{
float x1 = Radius * Mathf.Sin(unitEuler * j);
float x2 = Radius * Mathf.Sin(unitEuler * (j + 1));
float z1 = Radius * Mathf.Cos(unitEuler * j);
float z2 = Radius * Mathf.Cos(unitEuler * (j + 1));
AddTriangle(
new Vector3(x2, rodeList[0].y, z2 + rodeList[0].z),
new Vector3(x1, rodeList[0].y, z1 + rodeList[0].z),
new Vector3(0, rodeList[0].y, 0f)
);
AddTriangleColor(Color.white);
AddTriangle(
new Vector3(x1, rodeList[RodeCount - 1].y, z1 + rodeList[RodeCount - 1].z),
new Vector3(x2, rodeList[RodeCount - 1].y, z2 + rodeList[RodeCount - 1].z),
new Vector3(0, rodeList[RodeCount - 1].y, rodeList[RodeCount - 1].z)
);
AddTriangleColor(Color.gray);
}
//1.4,给Mesh赋值
RodMesh.vertices = vertices.ToArray();
RodMesh.triangles = triangles.ToArray();
RodMesh.colors = colors.ToArray();
RodMesh.RecalculateBounds();
RodMesh.RecalculateNormals();
}
效果如下:
(所以如果不缩放长度,弯曲程度越大则钓竿实际长度会无止境的增加)
这个函数只提供了单一方向的挥动,所以挥动方向由父物体提供,我们要另写一个新的挥杆者计算挥杆方向:
……
//由于FPSController的问题,不能从鼠标位置正确的得到旋转的速度,所以直接从GameObject的Rotation上拿
public Transform PlayerTrans;
public Transform CameraTrans;
public FishingRod Rod;
//挥动系数
public float Force;
//偏移累计量
public Vector2 Offset;
//目前偏移量
public Vector2 CurOffset;
//偏移回振力度
public float Resistance;
//偏移方向
public Vector3 OffsetDir;
//上次的角度
public Vector2 LastAngle;
public float test;
这里有一个问题,那就是我使用的是默认的FpsController,导致不能正确的用Input.mousePosition拿到旋转的方向和速度大小,所以这里我从Player的y轴上取到水平方向的旋转分量,再从Camera的x轴上取到垂直旋转的分量。
// Update is called once per frame
void Update ()
{
//获得当前挥动角度
Vector2 nowAngle = new Vector2(PlayerTrans.localRotation.y, CameraTrans.localRotation.x);
if (nowAngle != LastAngle)
{
//加入最大偏移限制,刚进入游戏会有一个1000+的巨额偏移
Offset += ((nowAngle - LastAngle).magnitude > 10f ? Vector2.zero : (nowAngle - LastAngle));
}
//对偏移累积量进行修正
float temp = 1 - (Resistance / Offset.magnitude);
Offset *= (temp >= 0 ? temp : 0);
//目前偏移量向累积量进行修正
Vector2 offsetBetweenTotalAndCurrent = Offset - CurOffset;
if (offsetBetweenTotalAndCurrent.magnitude < Resistance)
CurOffset = Offset;
else
CurOffset += offsetBetweenTotalAndCurrent.normalized * Resistance;
//根据得到的偏移量之模刷新Mesh
Rod.RefreshRod(CurOffset.magnitude * Force);
Rod.transform.localRotation = Quaternion.Euler(new Vector3(0f, - Vector2Angle(CurOffset) - 90f,0f));
LastAngle = nowAngle;
}
好吧,下面就是有问题的代码了,拿到这水平和垂直的旋转分量后我应该能计算出鱼竿的y轴欧拉角,不过不知道为啥总有一个方向挥不动,请大手子指教一下:
private float Vector2Angle(Vector2 e)
{
//e.x是水平旋转分量 e.y是垂直旋转分量
float res;
if (e.y == 0f)
{
res = e.x > 0 ? 0 : 180f;
print(res);
return res;
}
res = (float) Math.Atan(e.y / e.x);
res = res / Mathf.PI * 180;
if (e.y > 0)
res = Mathf.Abs(res);
else
res = -Mathf.Abs(res);
print(res);
return res;
}
我太累了,失眠+写完代码的空虚感……我先出去吃个饭然后睡会,下午还要写自己的东西……
P.S.顺带一提,实际上作为挥动钓竿的约束条件的CantileverDistance,实际上可以用正切函数从挥动角度上拿到的,因为挥动角度更好量化而挥动距离确不行。
P.S.2.还有就是实际上为了保证鱼竿在视野内的效果,在弯曲程度小的时候应该抬高鱼竿,在弯曲程度大的时候应放低鱼竿,保证鱼竿都在视野范围内。
P.S.N.还有一堆的东西,不说了,吃饭了……
===================================================
感谢 @逍遥剑客 提供的公式
感谢Unity C# Tutorials
感谢腾讯GAD的翻译 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|