Exemple #1
0
    public List <List <LinkedShape> > FormGroupsWithNeighbors(float propagate, Vector3 propagationDirection, int maxGroupSize, Vector3 originPoint)
    {
        List <LinkedShape> picked     = new List <LinkedShape>();
        List <LinkedShape> potentials = new List <LinkedShape>();

        propagationDirection.Normalize();
        //propagate *= 0.6f;

        this.cost = 0;
        potentials.Add(this);

        bool hasPicked = true;

        while (hasPicked)
        {
            hasPicked = false;

            LinkedShape recorder = null;
            float       record   = propagate;

            //Trouve le potentiel noeud le moins cher. Les noeuds avec un coup plus grand que 'propagate' ne seront jamais choisient
            foreach (LinkedShape item in potentials)
            {
                if (item.cost <= record)
                {
                    record   = item.cost;
                    recorder = item;
                }
            }

            //Ajoue d'un nouveau noeud
            if (recorder != null)
            {
                potentials.Remove(recorder);
                recorder.AddToPickedList(picked, potentials, propagationDirection, originPoint);
                hasPicked = true;
            }
        }

        List <List <LinkedShape> > groupList = new List <List <LinkedShape> >();

        foreach (LinkedShape item in picked)
        {
            groupList.Add(new List <LinkedShape>(1)
            {
                item
            });
        }

        return(groupList);
    }
    void OnCollisionEnter(Collision collision)
    {
        if (collision.impulse.magnitude < hardness * massPerBlock || linkedShapes.Count <= 1)
        {
            return;
        }

        //Ignore la collision avec sois meme
        if (collision.transform != null && collision.transform.GetComponent <FragmentTree>() != null)
        {
            if (collision.transform.GetComponent <FragmentTree>().original == original)
            {
                return;
            }
        }

        //Trouve la piece qui s'est fait frappé
        LinkedShape hitShape = null;

        foreach (LinkedShape shape in linkedShapes)
        {
            if (shape.shape.tr == collision.contacts[0].thisCollider.transform)
            {
                hitShape = shape;
                break;
            }
        }
        if (hitShape == null)
        {
            return;
        }


        float quantitéDeMouvement = 0;

        if (collision.rigidbody != null)
        {
            quantitéDeMouvement = collision.relativeVelocity.magnitude * collision.rigidbody.mass;
        }
        else
        {
            quantitéDeMouvement = collision.relativeVelocity.magnitude * myRb.mass;
        }

        //Pour fix le 'je tombe sur le sol et je me fait propulsé dans les airs'
        Vector3 otherVel    = wasVel + collision.relativeVelocity;
        bool    addVelocity = myRb.velocity.magnitude < otherVel.magnitude;

        Break(hitShape, collision.contacts[0].point, -collision.impulse, quantitéDeMouvement, addVelocity);
    }
    void Break(LinkedShape shape, Vector3 point, Vector3 force, float quantitéDeMouvement, bool addVelocity)
    {
        if (linkedShapes.Count <= 1)
        {
            return;
        }

        if (intactVisual != null)
        {
            intactVisual.enabled = false;
        }

        //double time1 = EditorApplication.timeSinceStartup;
        Vector3 dir = force.normalized;

        float propagation = Mathf.Max(0, 0.025f * force.magnitude / (0.5f + elasticity) / massPerBlock);

        List <List <LinkedShape> > groups = shape.FormGroupsWithNeighbors(propagation, force.normalized, Mathf.Max(linkedShapes.Count / 2, 1), point);


        //Validate neighbors
        int totalInGroups = 0;

        for (int i = 0; i < groups.Count; i++)
        {
            totalInGroups += groups[i].Count;
            foreach (LinkedShape item in groups[i])
            {
                item.ValidateNeighbors(groups[i]);
            }
        }
        int skipLastGroup = linkedShapes.Count > totalInGroups ? 0 : 1;

        //Remove groups from list
        for (int i = 0; i < groups.Count - skipLastGroup; i++)
        {
            List <LinkedShape> group = groups[i];
            foreach (LinkedShape item in group)
            {
                linkedShapes.Remove(item);
            }
        }

        //Parcourt de l'arbre pour séparé les région qui ne sont plus en contact
        List <List <LinkedShape> > newGroups = FindSeperatedRegions();

        for (int i = 0; i < newGroups.Count; i++)
        {
            totalInGroups += newGroups[i].Count;
            foreach (LinkedShape item in newGroups[i])
            {
                item.ValidateNeighbors(newGroups[i]);
            }
        }
        //Remove newGroups from list
        for (int i = 0; i < newGroups.Count; i++)
        {
            foreach (LinkedShape item in newGroups[i])
            {
                linkedShapes.Remove(item);
            }
        }
        //Ajoute les nouveaux groupes à la liste
        groups.AddRange(newGroups);

        //Kinematic settings
        bool resetKinematic = false;

        if (myRb.isKinematic)
        {
            resetKinematic   = true;
            myRb.isKinematic = false;
        }
        Vector3 oldMassCenter = myRb.worldCenterOfMass;


        float velocityChange = quantitéDeMouvement / (totalInGroups * massPerBlock);

        //Nouveaux blocka
        for (int i = 0; i < groups.Count - skipLastGroup; i++)
        {
            List <LinkedShape> group   = groups[i];
            FragmentTree       newTree = Instantiate(newChunkPrefab.gameObject).GetComponent <FragmentTree>();
            newTree.linkedShapes   = group;
            newTree.hardness       = hardness;
            newTree.debugDraw      = debugDraw;
            newTree.relinkTree     = false;
            newTree.newChunkPrefab = newChunkPrefab;
            newTree.elasticity     = elasticity;
            newTree.original       = original;
            newTree.massPerBlock   = massPerBlock;

            Rigidbody rb = newTree.GetComponent <Rigidbody>();
            rb.velocity        = myRb.velocity;
            rb.angularVelocity = myRb.angularVelocity;
            rb.mass            = newTree.linkedShapes.Count * massPerBlock;
            rb.drag            = myRb.drag;
            rb.angularDrag     = myRb.angularDrag;
            rb.ResetCenterOfMass();

            foreach (LinkedShape item in group)
            {
                item.shape.tr.SetParent(newTree.transform, true);
            }

            Vector3 dist      = rb.worldCenterOfMass - point;
            float   alignment = Vector3.Dot(dist.normalized, dir);                  //de 0 à 1
            //float forceRatio = Mathf.Max(1.5f + 0.5f*alignment, 0.1f); // REMOVE
            float distanceFactor = Mathf.Pow(1 / (dist.magnitude + 1), elasticity); // de 0 à 1

            Vector3 addVel = dir * velocityChange * alignment * distanceFactor * 2;
            //print("remains: " + alignment * distanceFactor + "   vel: " + addVel);

            if (addVelocity)
            {
                rb.AddForceAtPosition(addVel, point, ForceMode.VelocityChange);
            }
            //rb.AddExplosionForce(force.magnitude*forceRatio, point, 10, 0);
        }

        //Reset mass settings
        myRb.ResetCenterOfMass();
        myRb.mass = linkedShapes.Count * massPerBlock;

        if (resetKinematic)
        {
            Vector3 newCenterOfMass = myRb.worldCenterOfMass;

            if (oldMassCenter.y < newCenterOfMass.y)
            {
                myRb.isKinematic = false;
            }
            else
            {
                myRb.isKinematic = true;
            }
        }
    }