Search Unity

Creating a "current" of Forces along path for Physics objects and particles?

Discussion in 'Physics' started by wickedpopular, Aug 31, 2019.

  1. wickedpopular

    wickedpopular

    Joined:
    Oct 29, 2016
    Posts:
    24
    Hello! I'm trying to create a system that creates a directional path of physics forces, like a water or wind current. I would like this path to follow a spline path I've created in the editor, so that I can create multiples of them in a level. The paths are not straight and can be quite curvy.

    To do the physics part, I've been doing horizontal raycasts along the spline, then applying a force to the object in the direction of the spline. But I don't know how to make this affect particles as well. I can't just do a procedural mesh with a texture because the particles (bubbles in my case) need to respond to objects with physics when touched.

    How can I properly apply these kinds of complex directional forces to my objects?
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,554
    I'd think on this as a force field, like gravity. I'd use an approach like this:
    1. Start with the position of the object.
    2. Find the point in the spline that is closest to the object.
    3. Compute the distance from the object to that point.
    4. Compute the force magnitude based on that distance. For example, you could define a radius around the spline within which an object would get affect by the force. This would create effectively a "tube" where the force affects objects. You may also apply some formula so the force is stronger the closer to the spline, and weaker the farthest. Force wouldn't be applied beyond the radius.
    5. Multiply the resulting force with the tangent of the spline in the point computed in 2. Apply the resulting force vector to the object.
    Hope this helps!
     
    SparrowsNest likes this.
  3. wickedpopular

    wickedpopular

    Joined:
    Oct 29, 2016
    Posts:
    24
    Thanks for replying! Yes, that's basically what I'm doing for objects, but what about the particles? I can't get the particles from an emitter to respond to the forces this way.
     
  4. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,554
    I have no experience with particles, but possibly there is some way to modify their behavior.

    I know that you can emit your own particles (indeed that's what I do for tire smoke in car simulation), and also I know you can keep track of all particles emitted. There should be a way to enumerate the live particles and modify their position explicitly. This way you could apply a similar technique to the particles in the scene.
     
  5. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    1,860
    You can access each particle position and velocity though its particle system.

    I have an example at home where i create a ring of particles and "shoot" it forward.
    I can post it when i get home if you want.
     
    Edy likes this.
  6. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,554
  7. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    1,860
    well well.. you actually have all the information you need right in the docs (who would have thought! -- no I mean seriously, just look at this page on the docs and tell me it's not a joke..)
    here: https://docs.unity3d.com/ScriptReference/ParticleSystem.GetParticles.html

    *I started writing an essay on what I did 2 years ago when I looked at the docs for one of the methods and they have a very clear and good explanation of exactly this

    Okay.. so this is from an old shooter prototype i made in late 2017, it's for a laser gun, when you hit the trigger it starts powering up and after x warm up it shoots a beam that pierces everything and only stopped by a static collider (IE terrain\building), I also wanted to make it so it starts powering up on mouse down, charge up when holding and fire on mouse release, maybe a overheat element.. sorta like the covenant pistol in halo.. anyways.. besides the point.


    What I first have is 3 things, a line renderer for the laser itself, one particle system named 'laser' that leaves small glowing particles on the beam (line renderer), and the one in question, called 'warmupFX' here, that is set to 'circle' in the shape module, after warmup time is over, I move them from local space (where they track the gun) to world space, and add some velocity to them in the .forward direction.

    this is the main function:
    (some unrelated stuff, but you can just look at the docs link i have at the top for a clean examlpe)
    Code (CSharp):
    1.     IEnumerator Shoot(){
    2.  
    3.         ringFX_Main.simulationSpace = ParticleSystemSimulationSpace.Local;
    4.         ringFX.Play ();
    5.         yield return new WaitForSeconds (warmup);
    6.         float d = range;
    7.         RaycastHit[] rh = Physics.RaycastAll (Camera.main.transform.position, Camera.main.transform.forward, range);
    8.         List<RaycastHit> hits = new List<RaycastHit> ();
    9.         for(int i = 0; i < rh.Length; i++){
    10.         //foreach (RaycastHit h in rh) {
    11.             if (rh[i].collider.attachedRigidbody != null && rh[i].collider.attachedRigidbody.isKinematic) {
    12.                 float c = Vector3.Distance (lazer.transform.position, rh[i].point);//(lazer.transform.position - h.point).magnitude;
    13.                 if (c < d) {
    14.                     d = c;
    15.                 }
    16.                 continue;
    17.             }
    18.             if (rh[i].collider.GetComponentInParent<IDamageable> () != null)
    19.                 hits.Add (rh[i]); //NOTE: Multi-collider objects can recive multiple hits from the same beam. ~maybe good for "bonus damage"?
    20.         }
    21.  
    22.         //TODO: make an array\list of indexes to know what to hit istead of another raycasthit list
    23.  
    24.         for(int i = 0; i < hits.Count; i++){
    25.         //foreach (RaycastHit hit in hits) {
    26.             if (Vector3.Distance (lazer.transform.position, rh[i].point) < d)
    27.                 hits[i].collider.GetComponentInParent<IDamageable> ().GetDamage (new HitInfo (damage, Player.instance.gameObject, hits[i].point));
    28.         }
    29.         Vector3 w = ringFX.transform.position;
    30.         int pa = ringFX.GetParticles (ringParticles);
    31.         for (int i = 0; i < pa; i++) {
    32.  
    33.             //ringParticles [i].position = ringFX.transform.TransformDirection (ringParticles [i].position) + w;
    34.             ringParticles [i].velocity += transform.forward * 100;
    35.         }
    36.         ringFX.SetParticles (ringParticles, pa);
    37.         ringFX_Main.simulationSpace = ParticleSystemSimulationSpace.World;
    38.         ringFX.Stop (false, ParticleSystemStopBehavior.StopEmitting);
    39.         laserFX_SM.length = d;
    40.         //main.maxParticles = Mathf.RoundToInt(d * p);
    41.         lazerFX.Play ();
    42.         Player.instance.AddStress ((ADS) ? sss * .75f : sss);
    43.         lazer.enabled = true;
    44.         lazer.SetPosition (0, lazer.transform.position);
    45.         lazer.SetPosition (1, lazer.transform.position + (lazer.transform.forward * d));
    46.         yield return new WaitForSeconds (.35f);
    47.         lazer.enabled = false;
    48.         yield return new WaitForSeconds (cooldown);
    49.         canShoot = true;
    50.     }
    51.  
     
    Edy likes this.