用Unity实现两滴水融合(初次试验)

当在搜索‘如何实现小鳄鱼洗澡’或者‘水融合实现’时,百分百会搜到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;
        }
    }
}


猜你喜欢

转载自blog.csdn.net/qq_33967521/article/details/84711651