Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Area Effector 2D does not seem to work while adjusting scale. [Custom Area Effector 2D - SOLVED]

Discussion in 'Physics' started by pRoFlT, Aug 25, 2015.

  1. pRoFlT

    pRoFlT

    Joined:
    Dec 20, 2014
    Posts:
    27
    I've implemented both an animator controlling the LocalScale of an Area Effector 2D and a script controlling the LocalScale of an Area Effector 2D. The Area Effector 2D has a force that pushes my player up like it is water. what i want is the water to lower and the Area Effector 2D to also lower and still effect the area while doing so.

    Problem is as soon as i adjust the scale (scripted or animated) my player falls through the water to the bottom. Once the animation or Script completes the player floats back up to the new level of water.

    This feels like a bug? Maybe it's supposed to work this way? Could i be going at this all wrong?

    p.s. i've posted same question on "Answers" still no answer :( I may end up removing area effector and creating my own i guess.

    Here is my scripted version
    Code (CSharp):
    1.  
    2. void FixedUpdate ()
    3.     {
    4.         float currentDrainY = transform.localScale.y;
    5.         if(draining && (drainMinY < currentDrainY))
    6.         {
    7.             //drain
    8.             transform.localScale = Vector3.MoveTowards(transform.localScale,new Vector3(transform.localScale.x,drainMinY,transform.localScale.z),speed * Time.deltaTime);
    9.         }
    10.         else if(!draining && (drainMaxY > currentDrainY))
    11.         {
    12.             //fill
    13.             transform.localScale = Vector3.MoveTowards(transform.localScale,new Vector3(transform.localScale.x,drainMaxY,transform.localScale.z),speed * Time.deltaTime);
    14.         }
    15.  
    16.     }
    Also i've run this in FixedUpate hoping maybe this would fix it as it was in Update first. Maybe i should try the late fixed update method?? I'll need to search for that real quick.

    Nope LateUpdate didn't work either.
     
    Last edited: Aug 25, 2015
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Whilst I don't like the idea of scaling physics objects which cause them to be regenerated, at least you're doing so in fixed-update. When you perform a scale operation, it cause all the 2D colliders on that GameObject or children to be regenerated (Box2D cannot modify existing collider shapes). This causes all its existing contacts to be deleted.

    After all the script fixed-updates are complete, all the effectors are executed followed by Box2D being updated. This means that when the effectors are executed, there will be no contacts for its colliders to process because all the contacts were removed due to the scaling operation. When Box2D runs after that, those contacts are recalculated.

    This process repeats meaning that the effector(s) don't process any contacts because between the scaling (where contacts are removed) and Box2D updating (where contacts are added), there are no contacts to process.

    The obvious solution to this is to execute all the effectors *after* Box2D has run however, the reason why they run before is because they add forces (etc) which I'd like to see run during that physics update.

    This is a tricky situation to solve; there simply isn't a better option than running the effectors after Box2D has run and new contacts are generated that I can think of right now.

    Note that 'LateUpdate' is after the frame, not after the fixed-update so it won't solve the issue. If we had a LateFixedUpdate and you did your work there then it would work correctly although the colliders wouldn't have any contacts during the frame rendering which for most of the time wouldn't be a problem unless of course you used 'IsTouching' or 'IsTouchingLayers' which looks at current contacts.

    Thinking about this...
     
    Last edited: Aug 27, 2015
    Deleted User likes this.
  3. pRoFlT

    pRoFlT

    Joined:
    Dec 20, 2014
    Posts:
    27
    @MelvMay Thanks for looking into this. I searched for a LateFixedUpdate thinking it made the most logical place to put this. I was also going to try and just move the area effector instead of changing scale. but it would probably have the same effect. I've been thinking i will just write my own version with maybe a waterLevel and i could apply a force while inside the trigger event and below waterLevel...then adjust waterLevel and don't mess with the scale.

    Unity could add a percentage of force applied function maybe. like a gradient or linear force with an public variable to adjust. same direction as force. maybe select from bottom from top etc.. yah thats not really what i need hmm...

    new thought... maybe i use two area effectors and just switch between one or the other. I wouldn't get the nice water draining effect. but would keep player from sinking to the bottom between transactions. i could make 3 to make it feel more gradual. but the player flying out of the water and floating in air before it raises all the way may look strange......


    ...ugh, guess i'm writing my own. i'll find a good use for the effectors!!! just not going to work for this.
     
  4. pRoFlT

    pRoFlT

    Joined:
    Dec 20, 2014
    Posts:
    27
    Okay wrote my own "Area Effector 2D" 2.0. It seems to work fine as i run my same code with it. I probably don't need all the same functionality as the unity one. I'm not sure what Drag function unity uses to slow objects down so i found one and modified it until it matched what i had.

    Also not sure how to let the trigger know my script is an area effector? guess it doesn't matter for me. I tried to inherit the area effector and add functionality but i guess that code is locked.

    Maybe someone can use this? it's not complete. only working for what i needed. has all variables ready to be used though.

    Anyone know how to apply a force at a point? Area effector has rigidbody force or collider force i only needed rigidbody but collider might be useful for something that rotoates like a floating barrel? or something.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6.  
    7.  
    8. public class AreaEffector2D_2p0 : MonoBehaviour
    9. {
    10.     public enum colliderList { RigidBody2D, Collider2D };
    11.  
    12.     private Vector2 targetPoint; // point at where the force is applied?
    13. //    private Rigidbody2D target;
    14.  
    15.     public bool useColliderMask=false;
    16.     public LayerMask colliderMask;
    17.     public bool useGloablAngle = false;
    18.     public float forceAngle=0; // 0-359 Maybe this should be property
    19.     public float forceMagnitude=0;
    20.     public float forceVariation=0;
    21.     public float drag=0;
    22.     public float angularDrag=0;
    23.     public colliderList forceTarget = colliderList.Collider2D;
    24.  
    25.  
    26.     private List<Rigidbody2D> _targets; // keep track of all items in and out of area effector
    27.  
    28.     void Awake ()
    29.     {
    30.         _targets = new List<Rigidbody2D>();
    31.     }
    32.  
    33.  
    34.     void FixedUpdate ()
    35.     {
    36.         Vector3 force;
    37.         float forceMag;
    38.         float dragForceMagnitude;
    39.         Vector3 dragForceVector;
    40.         float angularDragTorqe;
    41.  
    42.         if (_targets == null)
    43.             return; /// do nothing if no target aquired.
    44.  
    45.  
    46.         foreach(Rigidbody2D target in _targets) // go through list and ad force to them.
    47.         {
    48.             if(target==null) continue; // in case the target gets destroyed maybe? need something better then this. dont want list to fill up with destroyed objects.
    49.  
    50.             if(drag!=0)
    51.             {
    52.                 dragForceMagnitude = target.velocity.magnitude * target.velocity.magnitude * drag * Time.deltaTime; // 0.05f; i think Time.deltaTime works here. i had 0.05f but that is about my fixed update rate so maybe deltatime makes more sense.
    53.                 dragForceVector = dragForceMagnitude * -target.velocity.normalized;
    54.                 target.AddForce (dragForceVector);
    55.             }
    56.  
    57.             if(angularDrag!=0) // need to test this angular drag on something
    58.             {
    59.                 //angularDragTorqe = angularDrag * -target.angularVelocity; // hmmm need to only figure out +-
    60.  
    61.                 angularDragTorqe = angularDrag * Mathf.Clamp(Mathf.Round(-target.angularVelocity),-1,+1); // maybe this works. Could just say >0 or <0
    62.                 target.AddTorque(angularDragTorqe,ForceMode2D.Force); // this should work i think :)
    63.             }
    64.  
    65.             if( forceVariation!=0) forceMag = forceMagnitude + Random.Range(-forceVariation, forceVariation); // generate a force with random variation if not 0. May want to seperate this somehow to make non variation faster?
    66.             else forceMag = forceMagnitude; // normal force  no variation
    67.  
    68.             force = Quaternion.AngleAxis(forceAngle, Vector3.forward) * Vector3.right;; // forward? maybe up is normal. need to see what current area effector does?
    69.             target.AddForce(force * forceMag,ForceMode2D.Force); // give object force at an angle
    70.  
    71.         }
    72.     }
    73.  
    74.     void OnTriggerEnter2D(Collider2D coll)
    75.     {
    76.         if (useColliderMask) // are we using the mask
    77.         {
    78.             if((colliderMask.value & coll.gameObject.layer) > 0) // does the mask match
    79.             {
    80.                 _targets.Add(coll.gameObject.GetComponent<Rigidbody2D>()); // add to list
    81.             }
    82.         }
    83.         else _targets.Add(coll.gameObject.GetComponent<Rigidbody2D>()); // add to list
    84.     }
    85.  
    86.     void OnTriggerExit2D(Collider2D coll) // when leaving collider remove target
    87.     {
    88.         if (useColliderMask) // are we using the mask
    89.         {
    90.             if((colliderMask.value & coll.gameObject.layer) > 0) // idoes the mask match
    91.             {
    92.                 _targets.Remove (coll.gameObject.GetComponent<Rigidbody2D>()); //remove from list
    93.             }
    94.         }
    95.         else _targets.Remove (coll.gameObject.GetComponent<Rigidbody2D>()); // remove from list
    96.     }
    97.          
    98. }
    99.  
    100.  
    EDIT: Okay i've updated the code to use a list to keep track of all things in water during adjustment. not that i will need that but maybe later i will have other things floating in there. So i may need it....I also tried to implement a rotational drag or AngularDrag as the original area effector has. i've not tested this and it could possibly be done with less math to make it faster.

    i also fixed the use collider statement i had. it was always checking the collider mask. so now i separated the if statements for it.

    Maybe this will be useful for someone out there with the same issue.
     
    Last edited: Sep 1, 2015
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Just to let you know that I worked on a solution to this and it works pretty well so I'm looking at getting it into the release stream ASAP.

    It essentially splits-up the Box2D update into two stages:
    1. Find new/regenerated contacts
    2. Run simulation
    This means that I can perform the effector updates in-between 1 & 2 which would completely solve the problem when constantly modifying colliders (which results in contacts be constantly regenerated.
     
  6. pRoFlT

    pRoFlT

    Joined:
    Dec 20, 2014
    Posts:
    27
    @MelvMay, I see that Unity 5.3 will have a new 2D effector for buoyancy? Downloading now :) I wasn't fully happy with my implementation so i've not used it in my game yet. So i can now try this implementation. You guys are awesome! Thanks.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Enjoy! More features coming for that effector!
     
  8. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    I'm having a similar issue, actually has to do with water as well (but it's a top down 2d game and I was using scale to make the object "fall" into a "pit" with water.

    I'm still having this issue, though, so I was wondering if this fix was still in the works or not?

    Also, if I have something like an explosion with a blast that forms out from the center, wouldn't the best way to do that be to have an expanding Circle Collider 2D? However, if I do that.. it's constantly deleting and regenerating the actual collider? Is there a better solution?


    Thank you.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    A fix for this is on its way to our trunk and will be back-ported to 5.3 and 5.4 ASAP.
     
    Eluem likes this.
  10. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    you want to say that the change Collider, is that bad? that is, the system is implemented caching colliders size?
    colliders with triggers, never had problems!

    ok, i use this effector for water similition, and real need to change collider size of water displaysment
    but on change collider size, effector not work

    I am sure that this problem is linked to an effector, and it must be solved
    in v5.3.4.p3 this problem not solved
     
    Last edited: Apr 18, 2016
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Box2D isn't set-up to change the geometry of colliders. Doing so requires that they are recreated from scratch which obviously has a performance impact. It also means that contacts need to be regenerated during the next update. They are simply not meant to be changed but Unity exposes them as components with properties so users adjust/animate them. It does work but it has a performance impact.

    Triggers have nothing to do with this BTW so I don't follow your point.

    I explained the rest of the detail above in a lot of detail.


    I just checked and it looks like the fix got stalled for some reason. It has gone into our trunk but hasn't yet been backported to 5.4-beta and 5.3-patch. I'll get that done ASAP.
     
    Last edited: Apr 18, 2016
  12. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    like what you just referred to Box2D, but it's not their fault, but yours, then you are not using Box2D correctly, the more you do it right the next patch

    do not reply to any question, it box2D! it is not box2D uses Unity! it Unity uses the Box2D, and Unity is the problem, not Box2D

    if (Box2D isn't set-up to change the geometry of colliders.) and unity3d have, then why are you using box2d?
     
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    There's seems to be a language barrier here.

    You asked why is it bad to change collider size and I explained it to you. It is not a bug either in Box2D or Unity; it is how it was designed. You are not following at all.

    The fix has nothing to do with this, which won't change. I explained what the fix was but as I have seen in many of your posts, you don't follow which again is probably a language barrier.
     
    Last edited: Apr 18, 2016
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Wow. This is news to me!
     
  15. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    (then you->Unity3D are not using Box2D correctly)


    it will work properly in the future?

    i asked - (BuoyancyEffector2D not work on change collider size) you say - the Box2D
    i asked - (Collision2D on Polygon collider not return all collision) you say - the Box2D (you say nothing)
    i asked - (effect drag on velocity) you say - the Box2D
    i asked - (physics doll 2D not work on scaled -1x flip and bad rotation 180) you say - the Box2D (now i use two dolls left and right)

    here problem not in "language barrier", here problem what you referred to Box2D all time
    i use Unity3D not Box2D
    and now i cnow about Box2D more then Unity3D, this is problem...

    Box2D breaks logic of Unity3D
     
  16. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Nope. Again, you're not following.
     
  17. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    you're not following? YES or NO
    )))
     
  18. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    I'm trying to follow but your posts are hard to understand.

    Will what work correctly in the future?

    Why don't you message me directly instead of this thread being cluttered up.
     
  19. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    BuoyancyEffector2D work on change size collider
     
  20. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    You will find I already answered this here.
     
    Last edited: Apr 18, 2016
  21. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    I have just submitted the back-port for this fix to 5.4 beta and 5.3 patch release.

    Now, effectors will be updated after Box2D has been updated.
     
  22. immeasurability

    immeasurability

    Joined:
    Apr 22, 2014
    Posts:
    125
    this real answer! THX!!! at least there is hope to see it in the future
     
  23. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    This has just landed in 5.3.4p6 (due for release next week).
     
  24. URGr8

    URGr8

    Joined:
    Sep 10, 2012
    Posts:
    23
    I ran into something similar. I have a 2D point effect on an object, like a moving planet, rotating around a sun. When the planet is not moving then it pulls my spaceship in, but when the planet is moving (RoatateAround), then the effect doesn't work, it doesn't do anything. Seems like its the same behavior in the area effect. I'm using 5.3.3f1.
    Is there a way to get that working?
     
  25. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,563
    Yes there is. Try reading what I posted above. ;)