public void GetObject(string name, out float bounciness, out BounceCombineType bounceCombineType)
    {
        Model model = new Model();

        models.TryGetValue(name, out model);
        model.GetAttribute(out name, out bounciness, out bounceCombineType);
    }
    public void SetObject(string name, float bounciness, BounceCombineType bounceCombineType)
    {
        Model model = new Model();

        GetObject(name, out model);
        //Debug.Log(model.ToString());
        model.SetAttribute(name, bounciness, bounceCombineType);
        models[name] = model;
    }
 public Model(string name, float mass, Vector3 normal, ModelType modelType)
 {
     this.name              = name;
     this.modelType         = modelType;
     this.forces            = new Dictionary <string, Force>();
     this.normal            = normal;
     this.mass              = mass;
     this.vel               = Vector3.zero;
     this.bounciness        = 0;
     this.bounceCombineType = BounceCombineType.Average;
 }
    public void CalHit(string name, string otherName, Vector3 p1, Vector3 p2, out Vector3 v1, out Vector3 v2)
    {
        Model self = new Model();

        GetObject(name, out self);
        Model other = new Model();

        GetObject(otherName, out other);
        //根据两个物体的恢复系数组合类型的优先级决定最后的恢复系数组合类型
        BounceCombineType bounceCombineType = self.bounceCombineType.CompareTo(other.bounceCombineType) > 0 ? self.bounceCombineType : other.bounceCombineType;
        float             bounciness        = 0.0f;

        if (bounceCombineType == BounceCombineType.Average)
        {
            bounciness = (self.bounciness + other.bounciness) / 2.0f;
        }

        if (bounceCombineType == BounceCombineType.Minimum)
        {
            bounciness = Mathf.Min(self.bounciness, other.bounciness);
        }

        if (bounceCombineType == BounceCombineType.Multiply)
        {
            bounciness = self.bounciness * other.bounciness;
        }

        if (bounceCombineType == BounceCombineType.Maximum)
        {
            bounciness = Mathf.Max(self.bounciness, other.bounciness);
        }


        float   m1  = self.mass;
        float   m2  = other.mass;
        Vector3 v10 = self.vel;
        Vector3 v20 = other.vel;


        Debug.Log("self: " + self.ToString());
        Debug.Log("other: " + other.ToString());
        Debug.Log("self v10: " + v10);
        Debug.Log("other v20: " + v20);

        Vector3 normal1 = self.normal;
        Vector3 normal2 = other.normal;

        Debug.Log("p1: " + p1 + " p2: " + p2);
        Vector3 dir = p1 - p2;

        Debug.Log("dir: " + dir.x + " " + dir.y + " " + dir.z);
        dir = AlignVector3(dir, new Vector3(ignoreVectorValue, ignoreVectorValue, ignoreVectorValue));
        dir = Vector3.Normalize(dir);


        Debug.Log("CalHit: dir:" + dir);

        //小球模型没有表面法向量(设为0),所以这里是两个小球碰撞的情况
        if (normal1 == Vector3.zero && normal2 == Vector3.zero)
        {
            //一动一静
            if (v10 == Vector3.zero)
            {
                Vector3 v20_normal = Vector3.Dot(v20, dir) * dir;
                //Debug.Log("v20_normal: " + v20_normal);
                Vector3 v20_else = v20 - v20_normal;
                v20 = v20 - v20_else;
                //Debug.Log("v20: " + v20 + " v20_else: " + v20_else);
                if (v10 == v20)
                {
                    v1 = v10;
                    v2 = v20 + v20_else;
                    SetObject(name, m1, v1);
                    SetObject(otherName, m2, v2);
                    return;
                }
                if (m2 < 0)
                {
                    Debug.Log("CalHit: m2>>m1");
                    v1 = v20 + v20 * bounciness - v10 * bounciness;
                    v2 = v20;
                }
                else
                {
                    Debug.Log("CalHit: m2~m1");
                    v1 = (m2 * v20 * (1.0f + bounciness) + m1 * v10 - m2 * v10 * bounciness) / (m1 + m2);
                    v2 = (m1 * v10 * (1.0f + bounciness) + m2 * v20 - m1 * v20 * bounciness) / (m1 + m2);
                }

                v2 = v2 + v20_else;
            }
            //一动一静
            else if (v20 == Vector3.zero)
            {
                Vector3 v10_normal = Vector3.Dot(v10, dir) * dir;
                Vector3 v10_else   = v10 - v10_normal;
                v10 = v10 - v10_else;
                if (v10 == v20)
                {
                    v1 = v10 + v10_else;
                    v2 = v20;
                    SetObject(name, m1, v1);
                    SetObject(otherName, m2, v2);
                    return;
                }
                if (m2 < 0)
                {
                    Debug.Log("CalHit: m2>>m1");

                    v1 = v20 + v20 * bounciness - v10 * bounciness;
                    v2 = v20;
                }
                else
                {
                    Debug.Log("CalHit: m2~m1");

                    v1 = (m2 * v20 * (1.0f + bounciness) + m1 * v10 - m2 * v10 * bounciness) / (m1 + m2);
                    v2 = (m1 * v10 * (1.0f + bounciness) + m2 * v20 - m1 * v20 * bounciness) / (m1 + m2);
                }
                v1 = v1 + v10_else;
            }
            //两动,只支持一种碰撞情况
            else
            {
                v10 = AlignVector3(v10, new Vector3(ignoreVectorValue, ignoreVectorValue, ignoreVectorValue));
                v20 = AlignVector3(v20, new Vector3(ignoreVectorValue, ignoreVectorValue, ignoreVectorValue));
                float angle1 = Mathf.Acos(Mathf.Abs(Vector3.Dot(Vector3.Normalize(v10), dir)));
                float angle2 = Mathf.Acos(Mathf.Abs(Vector3.Dot(Vector3.Normalize(v20), dir)));

                //两个小球都有速度且至少一个速度不在连心线方向上,无法计算
                if (angle1 > ignoreVectorValue || angle2 > ignoreVectorValue)
                {
                    Debug.Log("CalHit: two velocities not supported");
                    v1 = self.vel;
                    v2 = other.vel;
                }
                //两个小球都有速度且都在连心线上,即一维的碰撞
                else
                {
                    if (v10 == v20)
                    {
                        v1 = v10;
                        v2 = v20;
                        SetObject(name, m1, v1);
                        SetObject(otherName, m2, v2);
                        return;
                    }
                    if (m2 < 0)
                    {
                        Debug.Log("CalHit: m2>>m1");

                        v1 = v20 + v20 * bounciness - v10 * bounciness;
                        v2 = v20;
                    }
                    else
                    {
                        Debug.Log("CalHit: m2~m1");

                        v1 = (m2 * v20 * (1.0f + bounciness) + m1 * v10 - m2 * v10 * bounciness) / (m1 + m2);
                        v2 = (m1 * v10 * (1.0f + bounciness) + m2 * v20 - m1 * v20 * bounciness) / (m1 + m2);
                    }
                }
            }
        }
        //小球碰表面
        else if (normal1 == Vector3.zero)
        {
            if (v20 != Vector3.zero)
            {
                Debug.Log("CalHit: one normal with velocity not supported");
                v1 = self.vel;
                v2 = other.vel;
            }
            Vector3 normalDir = AlignVector3(normal2, new Vector3(ignoreVectorValue, ignoreVectorValue, ignoreVectorValue));
            ;
            Vector3 v10_normal = Vector3.Dot(v10, normalDir) * normalDir;
            Vector3 v10_else   = v10 - v10_normal;
            v10 = v10 - v10_else;
            if (v10 == v20)
            {
                v1 = v10 + v10_else;
                v2 = v20;
                SetObject(name, m1, v1);
                SetObject(otherName, m2, v2);
                return;
            }
            if (m2 < 0)
            {
                Debug.Log("CalHit: m2>>m1");

                v1 = v20 + v20 * bounciness - v10 * bounciness;
                v2 = v20;
            }
            else
            {
                Debug.Log("CalHit: m2~m1");

                v1 = (m2 * v20 * (1.0f + bounciness) + m1 * v10 - m2 * v10 * bounciness) / (m1 + m2);
                v2 = (m1 * v10 * (1.0f + bounciness) + m2 * v20 - m1 * v20 * bounciness) / (m1 + m2);
            }
            v1 = v1 + v10_else;
        }
        //小球碰表面

        else if (normal2 == Vector3.zero)
        {
            if (v10 != Vector3.zero)
            {
                Debug.Log("CalHit: one normal with velocity not supported");
                v1 = self.vel;
                v2 = other.vel;
            }
            Vector3 normalDir  = AlignVector3(normal1, new Vector3(ignoreVectorValue, ignoreVectorValue, ignoreVectorValue));
            Vector3 v20_normal = Vector3.Dot(v20, normalDir) * normalDir;
            Vector3 v20_else   = v20 - v20_normal;
            v20 = v20 - v20_else;
            if (v10 == v20)
            {
                v1 = v10;
                v2 = v20 + v20_else;
                SetObject(name, m1, v1);
                SetObject(otherName, m2, v2);
                return;
            }
            if (m2 < 0)
            {
                Debug.Log("CalHit: m2>>m1");
                v1 = v20 + v20 * bounciness - v10 * bounciness;
                v2 = v20;
            }
            else
            {
                Debug.Log("CalHit: m2~m1");

                v1 = (m2 * v20 * (1.0f + bounciness) + m1 * v10 - m2 * v10 * bounciness) / (m1 + m2);
                v2 = (m1 * v10 * (1.0f + bounciness) + m2 * v20 - m1 * v20 * bounciness) / (m1 + m2);
            }
            v2 = v2 + v20_else;
        }
        else
        {
            Debug.Log("CalHit: two normal not supported");
            v1 = self.vel;
            v2 = other.vel;
        }
        Debug.Log("self v1: " + v1);
        Debug.Log("other v2: " + v2);
        SetObject(name, m1, v1);
        SetObject(otherName, m2, v2);
    }
 public void GetAttribute(out string name, out float bounciness, out BounceCombineType bounceCombineType)
 {
     name              = this.name;
     bounciness        = this.bounciness;
     bounceCombineType = this.bounceCombineType;
 }
 public void SetAttribute(string name, float bounciness, BounceCombineType bounceCombineType)
 {
     this.name              = name;
     this.bounciness        = bounciness;
     this.bounceCombineType = bounceCombineType;
 }