当在搜索‘如何实现小鳄鱼洗澡’或者‘水融合实现’时,百分百会搜到metaball,然后去外网读了几篇文档,感觉。。。。。。你懂得==
然后决定用贝塞尔曲线+圆球外切线 苟一个先看看效果。。。
目前效果如下:
这里我先用LineRenderer确保一下算法的正确性,目前并没有绘制网格。果然效果有点垃圾
关于外切线
https://www.mathopenref.com/consttangentsext.html
关于贝塞尔曲线
https://blog.csdn.net/eclipsexys/article/details/51956908
主要思路
计算出利用外切线,计算出下面8个点的坐标
通过这8个点,把赛贝尔曲线绘制出来。
反正目前效果不怎么样,这个用来做一些翻页动画还可以。。。
有时间我会在研究研究这个,实在不行还得转回metaball。。。
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class curve : MonoBehaviour {
private LineRenderer LR;
Vector2[] Mpos = new Vector2[6];
public Transform c1;
public Transform c2;
// Use this for initialization
void Start () {
LR = this.GetComponent<LineRenderer>();
LR.positionCount = 200;
LR.startWidth = 0.06f;
LR.endWidth = 0.06f;
}
private void FixedUpdate()
{
metaball(c1.GetComponent<CircleCollider2D>().radius, c2.GetComponent<CircleCollider2D>().radius, c1.position, c2.position, 2.4f, 0.5f);
}
private void metaball(float radius1,float radius2,Vector2 center1,Vector2 center2,float handleSize,float v)
{
float HALF_PI= Mathf.PI / 2;
float d = Vector2.Distance(center1, center2);
float maxDist = radius1 + radius2 * 2.5f;
float u1, u2;
//if (radius1 == 0 || radius2 == 0 || d > maxDist || d <= Mathf.Abs(radius1 - radius2)) return;
if (d < radius1 + radius2)
{//两球接触之后,这个主要是防止两球错乱
u1 = Mathf.Acos((radius1*radius1+d*d-radius2*radius2)/(2*radius1*d));
u2 = Mathf.Acos((radius2*radius2+d*d-radius1*radius1)/(2*radius2*d));
}
else
{
u1 = 0;
u2 = 0;
}
float angleBetweenCenters = Vector2.Angle(center2, center1)*3.14f/180;
float maxSpread = Mathf.Acos((radius1 - radius2) / d);//外切线相关,求出大圈中的夹角,也可以不abs,反正对于cos无所谓
float angle1 = angleBetweenCenters + u1 + (maxSpread - u1) * v;
float angle2 = angleBetweenCenters - u1 - (maxSpread - u1) * v;
float angle3 = angleBetweenCenters + Mathf.PI - u2 - (Mathf.PI - u2 - maxSpread);
float angle4 = angleBetweenCenters - Mathf.PI + u2 + (Mathf.PI - u2 - maxSpread);//四个切入点的角度
Vector2 P1 = new Vector2(1, Mathf.Tan(angle1)).normalized*radius1+center1;
Vector2 P2 = new Vector2(1, Mathf.Tan(angle2)).normalized*radius1+center1;
Vector2 P3 = new Vector2(1, Mathf.Tan(angle3)).normalized * radius2+center2;
Vector2 P4 = new Vector2(1, Mathf.Tan(angle4)).normalized * radius2+center2;//四个切线的切入端
float totalRadius = radius1 + radius2;
float d2Base = Mathf.Min(v * handleSize, Vector2.Distance(P1,P3) / totalRadius);
float d2 = d2Base * Mathf.Min(1, d * 2 / totalRadius);
float r1 = radius1 * d2;
float r2 = radius2 * d2;
Vector2 H1= new Vector2(1, Mathf.Tan(angle1-HALF_PI)).normalized * r1 + P1;
Vector2 H2 = new Vector2(1, Mathf.Tan(angle2 + HALF_PI)).normalized * r1 + P2;
Vector2 H3 = new Vector2(1, Mathf.Tan(angle3 + HALF_PI)).normalized * r2 + P3;
Vector2 H4 = new Vector2(1, Mathf.Tan(angle4 - HALF_PI)).normalized * r2 + P4;//四个切线的另一端
Drawpath(P1, H1, H3, P3, 0, 0);
Drawpath(P2, H2, H4, P4, 100, 0);
}
private void Drawpath(Vector2 A,Vector2 B,Vector2 C,Vector2 D,int i,float ii)
{
int n = i + 100;
for (; i < n; i++)
{//贝塞尔曲线
Mpos[0] = A + (B - A) * ii;
Mpos[1] = B + (C - B) * ii;
Mpos[2] = C + (D - C) * ii;
Mpos[3] = Mpos[0] + (Mpos[1] - Mpos[0]) * ii;
Mpos[4] = Mpos[1] + (Mpos[2] - Mpos[1]) * ii;
Mpos[5] = Mpos[3] + (Mpos[4] - Mpos[3]) * ii;
LR.SetPosition(i, Mpos[5]);
ii += 0.01f;
}
}
}