Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

AddExplosionForce extremely different results if called in Start and in Update

Discussion in 'Physics' started by TurleyE, Apr 24, 2020.

  1. TurleyE

    TurleyE

    Joined:
    Nov 2, 2015
    Posts:
    10
    I hope someone can help explain why I get totally different results, depending on if I execute from Start or while running.

    I have 9 blocks and from an empty Gameobject, I apply the same force to all 9 blocks.

    As you will see in the video, applying force in Start results in a small change to the blocks, where as if left until the mouse clicks then it is a huge change.
    I have tried Invoking after a delay, using coroutine etc and they all result in the same result as using Update.

    In a video I watched, they do the same thing as far as I can tell, and both methods result in the same effect, so i don't see why mine doesn't. I have tried it in 2017.2.0, as used in the video, as well as 2019.3.10 and 2019.3.11, and no difference.

    Can anyone help please?

    Video:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Bomb : MonoBehaviour
    6. {
    7.  
    8.     public Rigidbody[] rigidbodies;
    9.  
    10.     // Start is called before the first frame update
    11.     void Startz()
    12.     {
    13.         Explode();
    14.     }
    15.  
    16.    
    17.     private void Update()
    18.     {
    19.         if (Input.GetMouseButton(0))
    20.         {
    21.             Explode();
    22.         }
    23.     }
    24.  
    25.  
    26.     void Explode()
    27.     {
    28.         foreach (Rigidbody body in rigidbodies)
    29.         {
    30.             body.AddExplosionForce(150.0f, new Vector3(0.0f,-0.5f,0.0f), 2.0f);
    31.         }
    32.     }
    33.  
    34. }
     
  2. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    Try GetMouseButtonDown instead of GetMouseButton. With this simple scene running maybe without vsync (?), update ist called potentially hundreds of times per second and surely a couple of times until you release the mouse button. Multiple calls to addforce add up to this huge change in velocity of the bodies.

    to be more specific about what’s the cause:
    In Start you only call Explode() once. In update you call it many times because GetMouseButton is true for a couple of frames.
     
    TurleyE likes this.
  3. TurleyE

    TurleyE

    Joined:
    Nov 2, 2015
    Posts:
    10
    DOH! Thats exactly the reason for this. Thanks very much.
    I created this as a test, as my real project wasnt working as expected. In the real project I am correctly checking the mousebuttondown, but the effect is the opposite of this one - good explosion on Start, but the bits just drop if responding to click, or Invoke etc. Something to do with the model, so I will have to explore that - I created a model of the boxes in Blender, and it works the same as the unity ones, so it has to be a model issue. I will explore that. Thanks very much. I was missing the mouse connection, and was thinking something was wrong with AddExplosionForce :D
    Will check the model, and see why it fails misserably.
     
  4. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    The model has no effect on physics. Just the settings of the rigidbody and the colliders.
     
  5. TurleyE

    TurleyE

    Joined:
    Nov 2, 2015
    Posts:
    10
    Thanks. After quite a bit a bit of playing around, I have found the problem.
    The problem comes from the transform position of the prototype.
    If the GameObject exists in the scene as the explosion is applied, then all is good.
    If the GameObject is Instatiated from a prototype, then the explosion effect is applied based on the location that the objects would have been from the prototype, rather than the actual location they are at now.
    If the object had a Y0 position in the prototype, but is instantiated and placed at Y1, then the explosion needs to be applied to Y0 to get the same effect as a prototype with a Y1 and being instantiated at Y1 with an explosion at Y1.
     
  6. TurleyE

    TurleyE

    Joined:
    Nov 2, 2015
    Posts:
    10
    Just found that this only happens if you apply the change after Instatiation.
    If you set the position in the instantiation method, then it works with the changed position.
    If you instantiate and then on the next line you move the position, the effect applies in the wrong location.

    I.E.
    Code (CSharp):
    1. myFragged = Instantiate(fraggedProto, new Vector3(0.0f, 1.0f, 0.0f), Quaternion.Euler(Vector3.zero));
    2.  
    instead of

    Code (CSharp):
    1. myFragged = Instantiate(fraggedProto);
    2. myFragged.transform.position = new Vector3(0.0f, 1.0f, 0.0f);
     
  7. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    That might be because the transform doesn’t get automatically synchronized with the position of the rigidbody component. Try to set the position in the rigidbody component instead of the transform, then it should also work after instantiation

    Code (CSharp):
    1. myFragged = Instantiate(fraggedProto);
    2. myFragged.GetComponent<Rigidbody>().position = new Vector3(0.0f, 1.0f, 0.0f);
     
    Last edited: Apr 25, 2020
  8. TurleyE

    TurleyE

    Joined:
    Nov 2, 2015
    Posts:
    10
    Thanks. Just added some debug statements and can see there are some delays in applying position changes.

    In the Awake and OnEnable the transform and rigidbody positions match the prefab.
    In the first Start call, the transform position moves, but the rigidbody doesn't.
    I then get a LateUpdate (some times multiple) and a FixedUpdate, with the transform being the required position, but the rigidbody is still at the prefab position.
    Only at the next Update call, following the FixedUpdate, does the rigidbody move to the transform position.
    If I only had a GameObject with no children, then adjusting the position of the gameobject and the rigidbody works easily, but as the GameObject has 80 children, rather than iterate through them all to adjust the positions relative to the parent location change, I will just set the position in the Instantiate, as that results in the positions matching in every call.

    Thankyou very much for your help tjmaul. Not only do I now have the solution, I now know more about how things are working.
     
  9. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    That’s what it’s about :)
    I’m glad I could help