Home > Mobile >  How to reverse a Force?
How to reverse a Force?

Time:04-19

(Hello, sorry if this is a really stupid question. I'm not good at coding and I probably don't understand what I'm doing)

I'm doing boids on Unity 3D and I'm trying to block them in a square area. Therefore I added Forces, one if they were going to far on the x and another one on the z axis. However I don't understand how to make a force so that they don't go too far on the -x and -z axis. How do I reverse the forces so those boids stay inside my area ?

Here's my x and z boundaries :

        //Force x
        float distX = Mathf.Max(0, transform.position.x);
        if (distX > 20)
        {
            float forceReject = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejectGround;
            sumForces  = new Vector3(-forceReject, 0, 0);
        }
        
        //Force z
        float distZ = Mathf.Max(0, transform.position.z);
        if (distZ > 20)
        {
            float forceReject = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejectGround;
            sumForces  = new Vector3(0, 0, forceReject);
        }
      

Here's the whole code because some asked it (however it's in french sorry)

public class Boid : MonoBehaviour
{
    public float zoneRepulsion = 2;
    public float zoneAlignement = 9;
    public float zoneAttraction = 30;
    public float hauteurSol = 0;

    public float forceRepulsion = 15;
    public float forceAlignement = 3;
    public float forceAttraction = 20;
    public float forceRejetSol = 100;

    public Vector3 target = new Vector3();
    public float forceTarget = 15;
    public bool goToTarget = false;
    public bool stopToTarget = false;
    private bool atTarget = false;

    public Vector3 velocity = new Vector3();
    public float maxSpeed = 10;
    public float minSpeed = 5;

    public bool drawGizmos = true;
    public bool drawLines = true;

    // Update is called once per frame
    void Update()
    {
        Vector3 sumForces = new Vector3();
        Color colorDebugForce = Color.black;
        float nbForcesApplied = 0;

        foreach (Boid otherBoid in BoidManager.sharedInstance.roBoids)
        {
            Vector3 vecToOtherBoid = otherBoid.transform.position - transform.position;
            Vector3 forceToApply = new Vector3();

            //Si on doit prendre en compte cet autre boid (plus grande zone de perception)
            if (vecToOtherBoid.sqrMagnitude < zoneAttraction * zoneAttraction)
            {
                //Si on est entre attraction et alignement
                if (vecToOtherBoid.sqrMagnitude > zoneAlignement * zoneAlignement)
                {
                    //On est dans la zone d'attraction uniquement
                    forceToApply = vecToOtherBoid.normalized * forceAttraction;
                    float distToOtherBoid = vecToOtherBoid.magnitude;
                    float normalizedDistanceToNextZone = ((distToOtherBoid - zoneAlignement) / (zoneAttraction - zoneAlignement));
                    float boostForce = (4 * normalizedDistanceToNextZone);
                    if (!goToTarget) //Encore plus de cohésion si pas de target
                        boostForce *= boostForce;
                    forceToApply = vecToOtherBoid.normalized * forceAttraction * boostForce;
                    colorDebugForce  = Color.green;
                }
                else
                {
                    //On est dans alignement, mais est on hors de répulsion ?
                    if (vecToOtherBoid.sqrMagnitude > zoneRepulsion * zoneRepulsion)
                    {
                        //On est dans la zone d'alignement uniquement
                        forceToApply = otherBoid.velocity.normalized * forceAlignement;
                        colorDebugForce  = Color.blue;
                    }
                    else
                    {
                        //On est dans la zone de repulsion
                        float distToOtherBoid = vecToOtherBoid.magnitude;
                        float normalizedDistanceToPreviousZone = 1 - (distToOtherBoid / zoneRepulsion);
                        float boostForce = (4 * normalizedDistanceToPreviousZone);
                        forceToApply = vecToOtherBoid.normalized * -1 * (forceRepulsion * boostForce);
                        colorDebugForce  = Color.red;

                    }
                }


                sumForces  = forceToApply;
                nbForcesApplied  ;
                
            }
        }

        //On fait la moyenne des forces, ce qui nous rend indépendant du nombre de boids
        sumForces /= nbForcesApplied;

        //On ajoute le rejet du sol
        float distSol = Mathf.Max(0,transform.position.y - hauteurSol);
        if (distSol < 2)
        {
            float forceRejet = Mathf.Pow(1.0f - (distSol / 2), 2) * forceRejetSol;
            sumForces  = new Vector3(0, forceRejet, 0);
        }

        //Rejet du plafond
        float distPlaf = Mathf.Max(5, transform.position.y);
        if (distPlaf > 10)
        {
            float forceRejet = Mathf.Clamp(5, 1.0f - (distPlaf / 2), 2) * -forceRejetSol;
            sumForces  = new Vector3(0, forceRejet, 0);
        }

        //Rejet pour la limite d' x
        float distX = Mathf.Max(0, transform.position.x);
        if (distX > 20)
        {
            float forceRejet = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejetSol;
            sumForces  = new Vector3(-forceRejet, 0, 0);
        }
        //Rejet pour la limite de -x
        if (distX < -15)
        {
            float forceRejetXNeg = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejetSol;
            sumForces  = new Vector3(forceRejetXNeg, 0, 0);
        }
        //Rejet pour la limite d' z
        float distZ = Mathf.Max(0, transform.position.z);
        if (distZ > 20)
        {
            float forceRejet = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejetSol;
            sumForces  = new Vector3(0, 0, forceRejet);
        }
        //Rejet pour la limite de -z
        if (distZ < -15)
        {
            float forceRejetZNeg = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejetSol;
            sumForces  = new Vector3(0, 0, forceRejetZNeg);
        }

        //Si on a une target, on l'ajoute
        float distToTarget = 0;
        if (goToTarget)
        {
            Vector3 vecToTarget = target - transform.position;
            distToTarget = vecToTarget.magnitude;
            if (distToTarget < 0.5f)
            {
                goToTarget = false;
                atTarget = true;
            }
            else
            {
                atTarget = false;
                Vector3 forceToTarget = vecToTarget.normalized * forceTarget;
                if (distToTarget < 5 && stopToTarget)
                    forceToTarget *= 10;
                sumForces  = forceToTarget;
                colorDebugForce  = Color.magenta;
                nbForcesApplied  ;
                if (drawLines)
                    Debug.DrawLine(transform.position, target, Color.magenta);
            }
        }

        //Debug
        if (drawLines)
            Debug.DrawLine(transform.position, transform.position   sumForces, colorDebugForce / nbForcesApplied);

        //On freine
        velocity  = -velocity * 10 * Vector3.Angle(sumForces, velocity) / 180.0f * Time.deltaTime;

        //on applique les forces
        velocity  = sumForces * Time.deltaTime;

        //On limite la vitesse
        if (velocity.sqrMagnitude > maxSpeed * maxSpeed)
            velocity = velocity.normalized * maxSpeed;
        if (velocity.sqrMagnitude < minSpeed * minSpeed)
            velocity = velocity.normalized * minSpeed;

        //Si on doit freiner sur la cible, on limite la vitesse
        if ((goToTarget || atTarget) && stopToTarget)
            if (distToTarget < 3)
                velocity = velocity.normalized * distToTarget/10.0f;


        //On regarde dans la bonne direction        
        if (velocity.sqrMagnitude > 0)
            transform.LookAt(transform.position   velocity);

        //Debug
        if (drawLines)
            Debug.DrawLine(transform.position, transform.position   velocity, Color.blue);

        //Deplacement du boid
        transform.position  = velocity * Time.deltaTime;
    }

    void OnDrawGizmosSelected()
    {
        if (drawGizmos)
        {
            // Répulsion
            Gizmos.color = new Color(1, 0, 0, 1.0f);
            Gizmos.DrawWireSphere(transform.position, zoneRepulsion);
            // Alignement
            Gizmos.color = new Color(0, 1, 0, 1.0f);
            Gizmos.DrawWireSphere(transform.position, zoneAlignement);
            // Attraction
            Gizmos.color = new Color(0, 0, 1, 1.0f);
            Gizmos.DrawWireSphere(transform.position, zoneAttraction);
        }
    }
}

CodePudding user response:

Well if you say this worked for you and you just ask about the "negative" direction you can simply invert check.

However, this

var forceReject = Mathf.Clamp(5, 1.0f - distX / 2, 2) * forceRejectGround;

seems to make little sense to me. You already know that distX > 20 so that you basically do

var forceReject = Mathf.Clamp(5, -9f /*or less*/, 2) * forceRejectGround;

which of course will always return 2 * forceRejectGround anyway. So this is either wrong or just completely redundant ;)

Also

distX < -15

can never be true since you already did

distX = Mathf.Max(0, transform.x);

so it can only be 0 or positive!


So basically you could probably simply do something like e.g.

//Force x
var x = transform.position.x;
if (Mathf.Abs(x) > 20) 
// basically equals
//if(x > 20 || x < -20)
{
    // will be positive if x > 20 and negative if x < -20 
    // (assuming forceRejectGround is positive of course)
    var forceReject = forceRejectGround * Mathf.Sign(x);

    sumForces -= Vector3.right * forceReject;
}
        
//Force z
var z = transform.position.z;
if (Mathf.Abs(z) > 20)
{
    var forceReject = forceRejectGround * Mathf.Sign(z);

    sumForces -= Vector3.up * forceReject;
}

However, as mentioned in the comments, in general you rather want to use a proper Rigidbody not do anything via transform at all but rather only through e.g. AddForce which already calculates the resulting velocities for you and reacts with collisions etc.

Or even further directly go with a Particle System and e.g. have your boid particles enclosed in Force fields

  • Related