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

measuring collision impact speed when hitting static objects

Discussion in 'Scripting' started by Grendelbiter, Oct 27, 2016.

  1. Grendelbiter

    Grendelbiter

    Joined:
    Oct 14, 2016
    Posts:
    123
    I am making a basic survival game for VR and I would like to make a tree I can fell with an axe. I don't want a hit to be registered if you just touch the tree, you should have to swing the axe with a certain speed. I'm trying to modify some scripts from the VRTK toolkit to achieve this. There's a sword script and a breakable cube script. The cube has a rigidbody, gravity on with a normal collider. I tried changing the rigidbody to kinematic but the script breaks then. Someone told me to try it with an OnTriggerEnter and changing the collider to isTrigger. That kind of works...if I hit the cube nothing happens, only if I hit another rigidbody first and then I just need to touch the cube and it explodes. But even if this setup would work there's still the problem that the tree doesn't have a proper collider to prevent the player going through. Adding another collider totally crashes the script. If you haven't figured out yet I'm a complete noob to everything game design related. I just started 2 weeks ago. Please someone help me set this up. I'd be willing to make you a model of your choice (nothing too complicated) or you can have this sweet Axe and/or Hammer: http://imgur.com/yDYxwP2

    Edit: Forgot to post the script. Here's the tree script:

    Code (CSharp):
    1. namespace VRTK.Examples
    2. {
    3.     using UnityEngine;
    4.  
    5.     public class ChoppableTree : MonoBehaviour
    6.     {
    7.         private float breakForce = 150f;
    8.  
    9.  
    10.         private void OnTriggerEnter(Collider col)
    11.         {
    12.             var collisionForce = GetCollisionForce(col);
    13.  
    14.             if (collisionForce > 0)
    15.             {
    16.                 ExplodeCube(collisionForce);
    17.             }
    18.         }
    19.  
    20.         private float GetCollisionForce(Collider col)
    21.         {
    22.             if ((col.GetComponent<Collider>().name.Contains("Axe") && col.GetComponent<Collider>().GetComponent<Axe>().CollisionForce() > breakForce))
    23.             {
    24.                 return col.GetComponent<Collider>().GetComponent<Axe>().CollisionForce() * 1.2f;
    25.             }
    26.                
    27.  
    28.             return 0f;
    29.         }
    30.  
    31.         private void ExplodeCube(float force)
    32.         {
    33.             foreach (Transform face in GetComponentsInChildren<Transform>())
    34.             {
    35.                 if (face.transform.name == transform.name) continue;
    36.                 ExplodeFace(face, force);
    37.             }
    38.             Destroy(gameObject, 10f);
    39.         }
    40.  
    41.         private void ExplodeFace(Transform face, float force)
    42.         {
    43.             face.transform.parent = null;
    44.             Rigidbody rb = face.gameObject.AddComponent<Rigidbody>();
    45.             rb.isKinematic = false;
    46.             rb.useGravity = true;
    47.             rb.AddExplosionForce(force, Vector3.zero, 0f);
    48.             Destroy(face.gameObject, 10f);
    49.         }
    50.     }
    51. }

    and here's the axe script, the same as the original sword script:

    Code (CSharp):
    1. namespace VRTK.Examples
    2. {
    3.     using UnityEngine;
    4.  
    5.  
    6.     public class Axe : VRTK_InteractableObject
    7.  
    8.     {
    9.         private VRTK_ControllerActions controllerActions;
    10.  
    11.         private VRTK_ControllerEvents controllerEvents;
    12.    
    13.         private float impactMagnifier = 120f;
    14.    
    15.         private float collisionForce = 0f;
    16.  
    17.    
    18.         public float CollisionForce()
    19.    
    20.         {
    21.             return collisionForce;
    22.         }
    23.             public override void Grabbed(GameObject grabbingObject)
    24.         {
    25.        
    26.             base.Grabbed(grabbingObject);
    27.        
    28.             controllerActions = grabbingObject.GetComponent<VRTK_ControllerActions>();
    29.        
    30.             controllerEvents = grabbingObject.GetComponent<VRTK_ControllerEvents>();
    31.  
    32.         }
    33.  
    34.     protected override void Awake()
    35.     {
    36.         base.Awake();
    37.         rb.collisionDetectionMode = CollisionDetectionMode.Continuous;
    38.     }
    39.  
    40.     private void OnCollisionEnter(Collision collision)
    41.     {
    42.         if (controllerActions && controllerEvents && IsGrabbed())
    43.         {
    44.             collisionForce = controllerEvents.GetVelocity().magnitude * impactMagnifier;
    45.             controllerActions.TriggerHapticPulse((ushort)collisionForce, 0.5f, 0.01f);
    46.         }
    47.         else
    48.         {
    49.             collisionForce = collision.relativeVelocity.magnitude * impactMagnifier;
    50.         }
    51.     }
    52. }
    53. }
     
    Last edited: Oct 27, 2016
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    You could try logging what the collision force is actually showing up as so you could see if your constants are set too low:
    Code (CSharp):
    1.  private float GetCollisionForce(Collider col)
    2. {
    3.    if ((col.gameObject.name.Contains("Axe"))
    4.    {
    5.       float colForce =  col.gameObject.GetComponent<Axe().CollisionForce();
    6.       Debug.Log("Collsion Force = " + colForce);
    7.       if (colForce > breakForce)
    8.       {
    9.            return colForce*1.2f;
    10.        }
    11.     }
    12.      return 0
    13. }  
    I also removed this section of your code:
    Code (CSharp):
    1. col.GetComponent<Collider>()
    col is the reference to the collider you hit, there is no need to get it again.
     
    Grendelbiter likes this.
  3. Grendelbiter

    Grendelbiter

    Joined:
    Oct 14, 2016
    Posts:
    123
    Trying to paste this code and it's giving me a parser error.

    Code (CSharp):
    1. namespace VRTK.Examples
    2. {
    3.     using UnityEngine;
    4.  
    5.     public class ChoppableTree : MonoBehaviour
    6.     {
    7.         private float breakForce = 150f;
    8.  
    9.  
    10.         private void OnTriggerEnter(Collider col)
    11.         {
    12.             var collisionForce = GetCollisionForce(col);
    13.  
    14.             if (collisionForce > 0)
    15.             {
    16.                 ExplodeCube(collisionForce);
    17.             }
    18.         }
    19.  
    20.         private float GetCollisionForce(Collider col)
    21.         {
    22.             if ((col.gameObject.name.Contains("Axe"))
    23.                 {
    24.                     float colForce =  col.gameObject.GetComponent<Axe().CollisionForce();
    25.                     Debug.Log("Collsion Force = " + colForce);
    26.                     if (colForce > breakForce)
    27.                     {
    28.                         return colForce*1.2f;
    29.                     }
    30.                 }
    31.  
    32.                 return 0f;
    33.                 }
    34.  
    35.  
    36.  
    37.         private void ExplodeCube(float force)
    38.         {
    39.             foreach (Transform face in GetComponentsInChildren<Transform>())
    40.             {
    41.                 if (face.transform.name == transform.name) continue;
    42.                 ExplodeFace(face, force);
    43.             }
    44.             Destroy(gameObject, 10f);
    45.         }
    46.  
    47.         private void ExplodeFace(Transform face, float force)
    48.         {
    49.             face.transform.parent = null;
    50.             Rigidbody rb = face.gameObject.AddComponent<Rigidbody>();
    51.             rb.isKinematic = false;
    52.             rb.useGravity = true;
    53.             rb.AddExplosionForce(force, Vector3.zero, 0f);
    54.             Destroy(face.gameObject, 10f);
    55.         }
    56.     }
    57. }
    Or should I paste this into a new script?
     
  4. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Whats the parse error?
     
  5. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    Probably Line 22, one too many opening bracket in If.
    Should be:
    Code (CSharp):
    1. if (col.gameObject.name.Contains("Axe"))
     
  6. Grendelbiter

    Grendelbiter

    Joined:
    Oct 14, 2016
    Posts:
    123
    The parse Error was Unexpected Symbol after removing the bracket as Kalladystine suggested the Error is CS 0119 expression denotes a type where a variable value or method group was expected. CollisionForce() is red in the editor and there's no tooltip when I mouse over it.
     
  7. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    Line 24, missing angle bracket in type declaration:
    Code (CSharp):
    1. float colForce =  col.gameObject.GetComponent<Axe().CollisionForce();
    Should be:
    Code (CSharp):
    1. float colForce = col.gameObject.GetComponent<Axe>().CollisionForce();
    Remember to add line numbers to errors, so we don't need to scan the whole code.

    This might still not do what you want - collider vs trigger might not fire where you want to, see Collision Matrix (bottom of the page).
    Even if it does, there might be a incorrect Collision Force - both the check and setting the value are done in OnCollision/OnTrigger. According to Execution Order, OnTrigger runs first, so it will get 0 on first collision. I don't see also where it's reset, so after first collision CollisionForce stays the same until next collision? I don't know that asset pack, so hard to say.

    To remedy - I'd say change it back to what the author of the package intended (that is - normal collider, not trigger) and try to work from there. From the original post I'm not sure why it was changed in the beginning.
     
  8. Grendelbiter

    Grendelbiter

    Joined:
    Oct 14, 2016
    Posts:
    123
    Because the script is for a box with a rigidboy and a normal collider, the box is a physics object you can move around i.e. when you bump into it. The tree has to be a static object until it's time to fall down that's why I changed the rigidbody on the tree to kinematic. I don't understand though why it doesn't just work with a kinematic rb, according to that collision matrix there is collision detection and messages between rb/rbkinematic.
     
  9. Grendelbiter

    Grendelbiter

    Joined:
    Oct 14, 2016
    Posts:
    123
    Just tried your correction, now there are no complaints from unity but it doesn't work. There's no debug.log message either when i hit it.
     
  10. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    So your saying this code never shows a Debug?:
    Code (CSharp):
    1.  if (col.gameObject.name.Contains("Axe"))
    2.                 {
    3.                     float colForce =  col.gameObject.GetComponent<Axe>().CollisionForce();
    4.                     Debug.Log("Collsion Force = " + colForce);
    If thats the case then your Contains code is always returning false. Maybe the names aren't set right? You could also try tagging your Axe object with the Tag Axe and trying this:
    Code (CSharp):
    1. if (col.gameObect.CompareTag("Axe"))
    2. {
    3.