Esempio n. 1
0
    bool intersectTwoRangeEdgesAndPoint(Particle particle, int re0, int re1, int pt, ref ParticleContact contact)
    {
        ParticleContact c0 = default(ParticleContact), c1 = default(ParticleContact);

        if (m_rangeEdges[re0].intersect(particle, ref c0))
        {
            if (m_rangeEdges[re1].intersect(particle, ref c1))
            {
                if (c0.penetration < c1.penetration)
                {
                    contact = c0;
                    setDoorSide(re0, ref contact);
                }
                else
                {
                    contact = c1;
                    setDoorSide(re1, ref contact);
                }
            }
            else
            {
                contact = c0;
                setDoorSide(re0, ref contact);
            }
            return(true);
        }
        if (m_rangeEdges[re1].intersect(particle, ref contact))
        {
            setDoorSide(re1, ref contact);
            return(true);
        }
        return(particle.intersect(m_points[pt], ref contact));
    }
        public void TestConstructor()
        {
            var p = new List <Particle>
            {
                new Particle
                {
                    Position = new Vector2D(0, 0),
                    Velocity = new Vector2D(1, 0),
                    Mass     = 1
                },
                new Particle
                {
                    Position = new Vector2D(2, 0),
                    Velocity = new Vector2D(0, 0),
                    Mass     = 1
                }
            };
            var contact = new ParticleContact(p[0], p[1], 0.5, 1, new Vector2D(-1, 0));

            Assert.AreEqual(p[0], contact.PA, "PA");
            Assert.AreEqual(p[1], contact.PB, "PB");
            Assert.AreEqual(0.5, contact.Restitution, "Restitution");
            Assert.AreEqual(1, contact.Penetration, "Penetration");
            Assert.AreEqual(new Vector2D(-1, 0), contact.ContactNormal, "Contact Normal");
        }
Esempio n. 3
0
        /// <summary>
        /// 根据碰撞类型为两个指定的形状执行碰撞检测
        /// </summary>
        /// <param name="type"></param>
        /// <param name="sharpA"></param>
        /// <param name="sharpB"></param>
        public static ParticleContact DispatchToDetector(ContactType type, Shape sharpA, Shape sharpB)
        {
            Debug.Assert(sharpA.Type <= sharpB.Type);

            ParticleContact contact = null;

            switch (type)
            {
            case ContactType.CircleAndCircle:
                contact = ParticleCollisionDetector.CircleAndCircle(sharpA as Circle, sharpB as Circle);
                break;

            case ContactType.CircleAndEdge:
                contact = ParticleCollisionDetector.CircleAndEdge(sharpA as Circle, sharpB as Edge);
                break;

                //case ContactType.CircleAndBox:
                //    throw new NotImplementedException("未实现圆与盒的碰撞检测");
                //case ContactType.EdgeAndBox:
                //    throw new NotImplementedException("未实现边沿与盒的碰撞检测");
                //case ContactType.BoxAndBox:
                //    throw new NotImplementedException("未实现盒与盒的碰撞检测");
            }

            return(contact);
        }
        public void TestResolveVelocityWithAcceleration()
        {
            var p = new Particle
            {
                Position = new Vector2D(0, 0),
                Velocity = new Vector2D(1, 0),
                Mass     = 1
            };

            p.AddForce(new Vector2D(1, 0));
            p.Update(1);

            var contact         = new ParticleContact(p, null, 1, 0, new Vector2D(-1, 0));
            var resolveVelocity = new PrivateObject(contact);

            resolveVelocity.Invoke("ResolveVelocity", 1);

            Assert.AreEqual(new Vector2D(-1, 0), p.Velocity, "物体获得补偿速度");

            p.AddForce(new Vector2D(1, 0));
            p.Update(1);
            Assert.AreEqual(new Vector2D(0, 0), p.Velocity, "物体保持静止");

            p.AddForce(new Vector2D(-1, 0));
            resolveVelocity.Invoke("ResolveVelocity", 1);
            Assert.AreEqual(new Vector2D(0, 0), p.Velocity, "物体不会获得补偿速度");
        }
Esempio n. 5
0
    public void fillParticleContacts(Particle particle, List <ParticleContact> contacts)
    {
        ParticleContact contact = default(ParticleContact);

        for (int i = 0; i < 2; ++i)
        {
            if (particle.intersect(m_edges[i].normal, m_edges[i].d, ref contact))
            {
                contacts.Add(contact);
            }
        }

        for (int i = 0; i < 4; ++i)
        {
            int b = i * 2;
            if (intersectTwoRangeEdgesAndPoint(particle, s_rangEdgeIndices[b], s_rangEdgeIndices[b + 1], s_rangEdgeIndices[b], ref contact))
            {
                contacts.Add(contact);
            }
        }

        var ball = particle as NewBallParticle;

        if (ball != null)
        {
            //球
            fillBallContacts(ball, contacts);
        }
        else
        {
            //人
            if (((FBActor)particle.tag).configuration.bodyHeight >= m_doorHeight)
            {
                //人比球门高
                for (int i = 0; i < m_ballEdges.Count; ++i)
                {
                    if (particle.intersect(m_ballEdges[i].normal, m_ballEdges[i].d, ref contact))
                    {
                        contacts.Add(contact);
                    }
                }
            }
            else
            {
                for (int i = 2; i < m_edges.Count; ++i)
                {
                    if (particle.intersect(m_edges[i].normal, m_edges[i].d, ref contact))
                    {
                        switch (i)
                        {
                        case 2: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldA | DoorSide.kBack); break;

                        case 3: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldB | DoorSide.kBack); break;
                        }
                        contacts.Add(contact);
                    }
                }
            }
        }
    }
        public void TestResolveVelocityWithTwoObject()
        {
            var p = new List <Particle>
            {
                new Particle
                {
                    Position = new Vector2D(0, 0),
                    Velocity = new Vector2D(1, 0),
                    Mass     = 1
                },
                new Particle
                {
                    Position = new Vector2D(2, 0),
                    Velocity = new Vector2D(0, 0),
                    Mass     = 1
                }
            };
            var contact         = new ParticleContact(p[0], p[1], 1, 1, new Vector2D(-1, 0));
            var resolveVelocity = new PrivateObject(contact);

            resolveVelocity.Invoke("ResolveVelocity", 1 / 60.0);

            Assert.AreEqual(new Vector2D(0, 0), p[0].Velocity, "物体0失去速度");
            Assert.AreEqual(new Vector2D(1, 0), p[1].Velocity, "物体1获得物体0碰撞前的速度");
        }
Esempio n. 7
0
    //call all contact generators to report their contacts
    // returns number of contacts
    public int generateContacts()
    {
        int             limit       = maxContacts;
        int             i           = 0;
        ParticleContact nextContact = contacts[i];

        //nextContact = this.thisContact;

        while (i <= contactGenRegLen)
        //while(i <= maxContacts)
        {
            int used = gen.addContact(nextContact, limit);
            limit -= used;
            i++;
            if (contacts [i] != null)
            {
                nextContact = contacts [i];
            }


            //we've run out of contacts
            if (limit <= 0)
            {
                break;
            }
        }
        //MonoBehaviour.print("ParticleWorld: Contacts Generated");
        //return number of contacts used
        return(maxContacts - limit);
    }
Esempio n. 8
0
    public int fillContact(ParticleContact contact, int limit)
    {
        //initializing Particle here because I can't do it above
        particle = new MyParticle[2];

        //find current length of the cable
        float length = currentLength();

        //check if over extended
        if (length < maxLength)
        {
            return(0);
        }

        //otherwise return the contact
        contact.particle [0] = particle [0];
        contact.particle [1] = particle [1];

        //calculate normal
        MyVector3 normal = particle[1].getPosition().returnSubtractVectorFromThisVector(particle[0].getPosition());

        normal.normalize();

        contact.penetration = length - maxLength;
        contact.restitution = restitution;

        return(1);
    }
Esempio n. 9
0
    void fillBallContacts(NewBallParticle ball, List <ParticleContact> contacts)
    {
        ParticleContact contact = default(ParticleContact);

        if (ball.height >= m_doorHeight)
        {
            for (int i = 0; i < m_ballEdges.Count; ++i)
            {
                if (ball.intersect(m_ballEdges[i].normal, m_ballEdges[i].d, ref contact))
                {
                    contacts.Add(contact);
                }
            }
        }
        else
        {
            #region jlx 2017.05.15-log:添加动态计算碰撞球门斜边

            var dynamicSlopeEdge = calculateSlopeEdge(ball.position);
            if (ball.intersect(dynamicSlopeEdge.normal, dynamicSlopeEdge.d, ref contact))
            {
                contact.tagI = (int)(
                    DoorSide.kDoor |
                    DoorSide.kBack |
                    (ball.position.x > Fix64.Zero ? DoorSide.kFieldA : DoorSide.kFieldB));
                contacts.Add(contact);
            }

            #endregion
        }
    }
        public void TestResolveInterpenetrationWithTwoFixedObject()
        {
            var p = new List <Particle>
            {
                new Particle
                {
                    Position    = new Vector2D(0, 0),
                    Velocity    = new Vector2D(1, 0),
                    InverseMass = 0
                },
                new Particle
                {
                    Position    = new Vector2D(2, 0),
                    Velocity    = new Vector2D(0, 0),
                    InverseMass = 0
                }
            };
            var contact         = new ParticleContact(p[0], p[1], 0.5, 1, new Vector2D(-1, 0));
            var resolveVelocity = new PrivateObject(contact);

            resolveVelocity.Invoke("ResolveInterpenetration", 1 / 60.0);

            Assert.AreEqual(new Vector2D(0, 0), p[0].Position, "物体0位置不变");
            Assert.AreEqual(new Vector2D(2, 0), p[1].Position, "物体1位置不变");
        }
Esempio n. 11
0
 private void Start()
 {
     tr                = GetComponent <TrailRenderer>();
     startPos          = new Vector3(transform.position.x, transform.position.y, transform.position.z);
     throwableParticle = new Particle(new Vector3(startPos.x, startPos.y, startPos.z), 0.9f, 1f);
     boundingRectangle = new BoundingRectangle(new Vector3(startPos.x, startPos.y, startPos.z), 1, 1);
     particleContact   = new ParticleContact(throwableParticle, 0f, new Vector3());
 }
Esempio n. 12
0
 /// <summary>
 /// 向碰撞表中添加一个新的碰撞
 /// </summary>
 /// <param name="contact">碰撞信息</param>
 /// <returns>完成添加后若不允许继续添加则返回false,否则返回true</returns>
 private bool AddToContactList(ParticleContact contact)
 {
     if (_contactCounter++ < Settings.MaxContacts)
     {
         _contactList.Add(contact);
         return(true);
     }
     return(false);
 }
    /*
     **Maybe**
     *
     *      Add a particle contact list in here and add to that list with addContact.
     *      Create a particle contact generator and use the list created within that particle contact generator
     *
     *
     **Alternative**
     *      add ParticleContact List as a parameter use .Add to add to it. TRY THIS FIRST!!!!!
     */
    public int addContact(ParticleContact contact, int limit)
    {
        if (limit > 0)
        {
            contactReg.Add(contact);
            return(1);
        }

        return(0);
    }
        public void TestResolveContacts()
        {
            var resolver = new ParticleContactResolver(100);

            var p = new List <Particle>
            {
                new Particle
                {
                    Position = new Vector2D(0, 0),
                    Velocity = new Vector2D(1, 0),
                    Mass     = 1
                },
                new Particle
                {
                    Position = new Vector2D(2, 0),
                    Velocity = new Vector2D(0, 0),
                    Mass     = 1
                }
            };
            var contact = new ParticleContact(p[0], p[1], 1, 1, new Vector2D(-1, 0));

            var contactList = new List <ParticleContact>();

            resolver.ResolveContacts(contactList, 1 / 60.0);

            contactList.Add(contact);
            resolver.ResolveContacts(contactList, 1 / 60.0);
            Assert.AreEqual(new Vector2D(-1, 0), p[0].Position, "物体0依据速度分量分离");
            Assert.AreEqual(new Vector2D(0, 0), p[0].Velocity, "物体0碰撞后速度相反");
            Assert.AreEqual(new Vector2D(1, 0), p[1].Velocity, "物体1碰撞后速度相反");

            p = new List <Particle>
            {
                new Particle
                {
                    Position = new Vector2D(0, 0),
                    Velocity = new Vector2D(1, 0),
                    Mass     = 1
                },
                new Particle
                {
                    Position = new Vector2D(2, 0),
                    Velocity = new Vector2D(0, 0),
                    Mass     = 1
                }
            };
            contactList = new List <ParticleContact>
            {
                new ParticleContact(p[1], p[0], 1, 1, new Vector2D(1, 0))
            };
            resolver.ResolveContacts(contactList, 1 / 60.0);
            Assert.AreEqual(new Vector2D(-1, 0), p[0].Position, "函数满足对称性");
            Assert.AreEqual(new Vector2D(0, 0), p[0].Velocity, "函数满足对称性");
            Assert.AreEqual(new Vector2D(1, 0), p[1].Velocity, "函数满足对称性");
        }
Esempio n. 15
0
    ParticleContactResolver _onParticleCollided(Particle p1, Particle p2, ParticleContact contact)
    {
        var ball = p1 as NewBallParticle;

        if (ball != null)
        {
            if (_checkContact((FBBall)ball.tag, (FBActor)p2.tag))
            {
                //ball.setCollidedEventFlag();
                contact.normal = ajustActorBallCollideNormal(-contact.normal, (FBActor)p2.tag, ball.velocity);
                return(new PCR_Obstacle()
                {
                    particle = ball, contact = contact, restitution = config.ballCollisionRestitution_actorAndball
                });
            }
            return(null);
        }
        ball = p2 as NewBallParticle;
        if (ball != null)
        {
            if (_checkContact((FBBall)ball.tag, (FBActor)p1.tag))
            {
                //ball.setCollidedEventFlag();
                contact.normal = ajustActorBallCollideNormal(contact.normal, (FBActor)p1.tag, ball.velocity);
                return(new PCR_Obstacle()
                {
                    particle = ball, contact = contact, restitution = config.ballCollisionRestitution_actorAndball
                });
            }
            return(null);
        }

        FBActor actor = (FBActor)p1.tag;

        if (actor != null && actor.ignoreCollision)
        {
            return(null);
        }
        FBActor actor2 = (FBActor)p2.tag;

        if (actor2 != null && actor2.ignoreCollision)
        {
            return(null);
        }

        //碰撞数据保存
        actor.onActorCollided(actor2);
        actor2.onActorCollided(actor);

        return(new PCR_Particle_DontMove_KeepVelocity()
        {
            p1 = p1, p2 = p2, contact = contact, restitution = config.ballCollisionRestitution_actorAndactor
        });
    }
Esempio n. 16
0
    void OnCollisionStay(Collision collision)
    {
        float penetrationDepth = 0;

        if (collision.collider.CompareTag("Ground"))
        {
            ParticleContact pC = new ParticleContact(particle, null, restitution, collision.contacts [0].normal, penetrationDepth);
            pC.Resolve(Time.fixedDeltaTime);
//			Vector3 FrictionForce = new Vector3(particle.gravityForce.y * fritionFactor,0,0);
//			particle.AddForce (FrictionForce);
        }
    }
        public void TestCalculateSeparatingVelocityWithOneObject()
        {
            var p = new Particle
            {
                Position = new Vector2D(0, 0),
                Velocity = new Vector2D(1, 0),
                Mass     = 1
            };
            var contact = new ParticleContact(p, null, 0.5, 1, new Vector2D(-1, 0));

            Assert.AreEqual(-1, contact.CalculateSeparatingVelocity());
        }
 private static void TestDetectorsResult(
     ParticleContact expectContact,
     ParticleContact contact,
     string message = "")
 {
     Assert.IsNotNull(contact, $"{message} 产生了碰撞");
     Assert.AreEqual(expectContact.PA, contact.PA, $"{message} 物体A");
     Assert.AreEqual(expectContact.PB, contact.PB, $"{message} 物体B");
     Assert.AreEqual(expectContact.ContactNormal, contact.ContactNormal, $"{message} 碰撞法线");
     Assert.AreEqual(expectContact.Restitution, contact.Restitution, $"{message} 回弹系数");
     Assert.AreEqual(expectContact.Penetration, contact.Penetration, $"{message} 相交深度");
 }
Esempio n. 19
0
    void setDoorSide(int index, ref ParticleContact contact)
    {
        switch (index)
        {
        case 4: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldB | DoorSide.kLeft); break;

        case 5: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldB | DoorSide.kRight); break;

        case 6: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldA | DoorSide.kRight); break;

        case 7: contact.tagI = (int)(DoorSide.kDoor | DoorSide.kFieldA | DoorSide.kLeft); break;
        }
    }
Esempio n. 20
0
        /// <summary>
        /// Creates a new particle simulator that can handle up to the
        /// given number of contacts per frame.You can also optionally
        /// give a number of contact-resolution iterations to use. If you
        /// don't give a number of iterations, then twice the number of
        /// contacts will be used.
        /// </summary>
        public ParticleEngine(int maxContacts)
        {
            Particles   = new List <Particle>();
            ForceAreas  = new List <ParticleForceArea>();
            Forces      = new List <ParticleForce>();
            Constraints = new List <ParticleConstraint>();
            Resolver    = new ParticleContactResolver();

            m_contacts = new ParticleContact[maxContacts];
            for (int i = 0; i < maxContacts; i++)
            {
                m_contacts[i] = new ParticleContact();
            }
        }
Esempio n. 21
0
 public void onCollided(ParticleContact contact)
 {
     m_particle.notify_collided();
     if (m_willBeCatched)
     {
         m_willBeCatched      = false;
         m_willBeCatchedActor = null;
     }
     else
     {
         ballState = BallState.Free;
     }
     collidedContact  = contact;
     collidedVelocity = get3DVelocity();
 }
        public void TestResolveVelocityWithOneObject()
        {
            var p = new Particle
            {
                Position = new Vector2D(0, 0),
                Velocity = new Vector2D(1, 0),
                Mass     = 1
            };
            var contact         = new ParticleContact(p, null, 1, 1, new Vector2D(-1, 0));
            var resolveVelocity = new PrivateObject(contact);

            resolveVelocity.Invoke("ResolveVelocity", 1 / 60.0);

            Assert.AreEqual(new Vector2D(-1, 0), p.Velocity);
        }
Esempio n. 23
0
    void Start()
    {
        Vector3 startPos = new Vector3(transform.position.x, transform.position.y, transform.position.z);

        eventPoint        = new Vector3(100f, -5.1f, 0);
        particle          = new Particle(new Vector3(startPos.x, startPos.y, startPos.z), 0.8f, 1f);
        boundingRectangle = new BoundingRectangle(new Vector3(startPos.x, startPos.y, startPos.z), 1.8f, 2.8f);
        particleContact   = new ParticleContact(particle, 0f, new Vector3());

        Scene scene = SceneManager.GetActiveScene();

        string[] LevelsWithSuit = System.Enum.GetNames(typeof(GameManager.LevelsWithSuit));
        foreach (string level in LevelsWithSuit)
        {
            if (scene.name == level)
            {
                usableSuit = true;
            }
        }
    }
Esempio n. 24
0
 void OnCollisionEnter(Collision collision)
 {
     if (collision.collider.CompareTag("Ground"))
     {
         ParticleContact pC = new ParticleContact(particle, null, restitution, collision.contacts [0].normal, 0);
         pC.Resolve(Time.fixedDeltaTime);
     }
     else if (collision.collider.CompareTag("wall"))
     {
         ParticleContact pC = new ParticleContact(particle, null, restitution, collision.contacts [0].normal, 0);
         pC.Resolve(Time.fixedDeltaTime);
         Debug.Log(gameObject.transform.position);
     }
     else
     {
         Particle        other = collision.collider.GetComponent <MyPhysics> ().particle;
         ParticleContact pC    = new ParticleContact(particle, other, restitution, collision.contacts [0].normal, 0);
         pC.Resolve(Time.fixedDeltaTime);
     }
 }
        public void TestCalculateSeparatingVelocityWithTwoObject()
        {
            var p = new List <Particle>
            {
                new Particle
                {
                    Position = new Vector2D(0, 0),
                    Velocity = new Vector2D(1, 0),
                    Mass     = 1
                },
                new Particle
                {
                    Position = new Vector2D(2, 0),
                    Velocity = new Vector2D(0, 0),
                    Mass     = 1
                }
            };
            var contact = new ParticleContact(p[0], p[1], 0.5, 1, new Vector2D(-1, 0));

            Assert.AreEqual(-1, contact.CalculateSeparatingVelocity());
        }
Esempio n. 26
0
    //page 149 millington pdf
    //fils structure with given contact needed to prevent it from violating its constraint
    public int fillContact(ParticleContact contact, int limit)
    {
        particle = new MyParticle[2];

        //find current length of the rod
        float currentLen = currentLength();

        //check whether we're overextended
        if (currentLen == length)
        {
            return(0);
        }

        //otherwise return the contact
        contact.particle [0] = particle [0];
        contact.particle [1] = particle [1];

        //calculate normal
        MyVector3 normal = particle[1].getPosition().returnSubtractVectorFromThisVector(particle[0].getPosition());

        normal.normalize();

        //contact normal is depended on whether or not we're extending or compressing
        if (currentLen > length)
        {
            contact.contactNormal = normal;
            contact.penetration   = currentLen - length;
        }
        else
        {
            contact.contactNormal = normal.multiplyVectorByScalarVR(-1);
            contact.penetration   = length - currentLen;
        }

        //no bounciness so restitution is always zero
        contact.restitution = 0;

        return(1);
    }
Esempio n. 27
0
        public override bool AddContact(ParticleContact contact)
        {
            bool ret = PhysicsEngineForFunPINVOKE.ParticleCable_AddContact(swigCPtr, ParticleContact.getCPtr(contact));

            return(ret);
        }
Esempio n. 28
0
    ParticleContactResolver _onObstacleCollided(Particle particle, Obstacle obstacle, ParticleContact contact)
    {
        var ball = particle as NewBallParticle;

        if (ball != null)
        {
            ((FBBall)ball.tag).onCollided(contact);

            if (contact.tagI == (int)ArenaObstacle.DoorSide.kOutDoor)
            {
                return(new PCR_Obstacle()
                {
                    particle = ball, obstacle = obstacle, contact = contact, restitution = config.ballCollisionRestitution[0]
                });
            }

            PCR_Obstacle pcrObstracle = new PCR_Obstacle();
            pcrObstracle.particle = ball;
            pcrObstracle.obstacle = obstacle;
            pcrObstracle.contact  = contact;

            if ((contact.tagI & (int)ArenaObstacle.DoorSide.kBack) == (int)ArenaObstacle.DoorSide.kBack)
            {
                //后面
                pcrObstracle.restitution = config.ballCollisionRestitution[1];
            }
            else if ((contact.tagI & (int)ArenaObstacle.DoorSide.kLeft) == (int)ArenaObstacle.DoorSide.kLeft)
            {
                //左侧边
                pcrObstracle.restitution = config.ballCollisionRestitution[2];
            }
            else if ((contact.tagI & (int)ArenaObstacle.DoorSide.kRight) == (int)ArenaObstacle.DoorSide.kRight)
            {
                //右侧边
                pcrObstracle.restitution = config.ballCollisionRestitution[3];
            }
            else if ((contact.tagI & (int)ArenaObstacle.DoorSide.kCeil) == (int)ArenaObstacle.DoorSide.kCeil)
            {
                //天花板
                pcrObstracle.restitution = config.ballCollisionRestitution[4];
            }
            return(pcrObstracle);
        }
        return(new PCR_Obstacle_DontMove_KeepVelocity()
        {
            particle = particle, obstacle = obstacle, contact = contact, restitution = config.ballCollisionRestitution_actorAndobstacle
        });
    }
Esempio n. 29
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ParticleContact obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
        public virtual bool AddContact(ParticleContact contact)
        {
            bool ret = (SwigDerivedClassHasMethod("AddContact", swigMethodTypes0) ? PhysicsEngineForFunPINVOKE.IParticleContactGenerator_AddContactSwigExplicitIParticleContactGenerator(swigCPtr, ParticleContact.getCPtr(contact)) : PhysicsEngineForFunPINVOKE.IParticleContactGenerator_AddContact(swigCPtr, ParticleContact.getCPtr(contact)));

            return(ret);
        }