Search Unity

What do you think about this method to get the enemy damage info?

Discussion in 'Scripting' started by pleasurehouse, Apr 8, 2021.

  1. pleasurehouse

    pleasurehouse

    Joined:
    Oct 15, 2020
    Posts:
    96
    I wonder if there is a more efficient method than this to get the enemy's damage information.
    I have read that this method is very slow. What do you think?
    Thanks a lot!!

    Code (CSharp):
    1.  
    2.  
    3. public class Hit : MonoBehaviour
    4.      {
    5.          void OnTriggerEnter(Collider other)
    6.          {
    7.              if ( (IDamageable id = other.GetComponent<IDamageable>() ) != null)
    8.              {
    9.                  Debug.Log(id.damageLevel);
    10.              }
    11.          }
    12.      }
    13.  
    14.  
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    It's not slow. Where did you read that it's slow?

    Though there is a bit of a cleaner pattern:
    Code (CSharp):
    1. void OnTriggerEnter(Collider other)
    2. {
    3.     if (other.TryGetComponent(out IDamageable id))
    4.     {
    5.         Debug.Log(id.damageLevel);
    6.     }
    7. }
     
    Lekret and pleasurehouse like this.
  3. pleasurehouse

    pleasurehouse

    Joined:
    Oct 15, 2020
    Posts:
    96

    From here... it is the last post. He tested it (class vs interface)... interface is 150% more slow that class. I wondering if exist a better way to do it... i mean, without "GetComponent()"

    https://forum.unity.com/threads/getcomponents-possible-to-use-with-c-interfaces.60596/

    But, i like your way to do it!!

    Thank you so much!!
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    It is indeed slower to call GetComponent on an interface vs. a normal class. That being said, if you look at the numbers involved in that benchmark, the time each one takes is incredibly tiny:

    - He performed 10000 GetComponent calls with a normal class in around 1 millisecond. That's around 100 nanoseconds per GetComponent call.
    - He performed 10000 GetComponent calls with an interface in around 2.5 milliseconds. That's around 250 nanoseconds per call.

    We're not talking about doing 10,000 of these calls per frame. We're talking about doing a single one when an OnTriggerEnter happens. The numbers involved are just too small to reasonably worry about.
     
    pleasurehouse likes this.
  5. pleasurehouse

    pleasurehouse

    Joined:
    Oct 15, 2020
    Posts:
    96
    Ok, in this specific case what you say is true. Anyway I try to use GetComoponen () as little as possible. Until today I have used it only in the Start Function when it is strictly necessary. I have heard many other people say that if you use it indiscriminately the game slows down a lot.

    I prefer to reference objects in the editor through serialization. This also causes Unity to take longer to load at first (about 5 minutes for me at the moment). But then the game runs fast and lag-free.

    The first case has never happened to me so I can't compare. But I remember 4 months ago when I started writing my Unity game it loaded very fast and now it takes about 5 minutes ...

    OK, thanks so much for your help.
     
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    The real problem with GetComponent performance is when people just constantly are using it, hundreds or even thousands of times per frame. Calling it once for a collision is pretty trivial, and you're probably overoptimizing if you try to get rid of it. But I don't know the requirements of your game. For all I know your target platform may be Intel Atom CPU with onboard graphics connected to a new 480hz display, where this kind of performance tweaking would probably matter.
     
    lordofduct and PraetorBlue like this.
  7. pleasurehouse

    pleasurehouse

    Joined:
    Oct 15, 2020
    Posts:
    96

    Yes, my computer is quite old. It has very few resources, the CPU and the graphics card are low-end. I am interested in optimizing as much as possible (at least as long as I have this computer). I would not like that in the middle of the development of the game my computer could not support it and I could not continue programming it.
     
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    The sorts of situations people are referring to it being a problem is like say this:
    Code (csharp):
    1. void Update()
    2. {
    3.     if(this.GetComponent<MyScript>() != null && this.GetComponent<SomeOtherScript>() != null && this.GetComponent<MyScript>().SomeBoolValue)
    4.     {
    5.          this.GetComponent<MyScript>().DoSomething(this.GetComponent<SomeOtherScript>().DoSomethingParameter);
    6.     }
    7. }
    (yes, there are people out there that do basically this)

    For starters this logic could be boiled own to:
    Code (csharp):
    1. void Update()
    2. {
    3.     var mysc = this.GetComponent<MyScript>();
    4.     var myothersc = this.GetComponent<SomeOtherScript>();
    5.     if (mysc != null && myothersc && mysc.SomeBoolValue)
    6.     {
    7.          mysc.DoSomething(myothersc.DoSomethingParameter);
    8.     }
    9. }
    Reducing the 5 calls down to 2. Why unnecessarily do work that you don't have to keep doing?

    And then there's the other optimization that people suggest. Since the component is attached to this gameobject, it's not going anywhere. So you could just cache those in start:
    Code (csharp):
    1. private MyScript mysc;
    2. private SomeOtherScript myothersc;
    3.  
    4. void Start()
    5. {
    6.     mysc = this.GetComponent<MyScript>();
    7.     myothersc = this.GetComponent<SomeOtherScript>();
    8. }
    9.  
    10. void Update()
    11. {
    12.     if (mysc != null && myothersc && mysc.SomeBoolValue)
    13.     {
    14.          mysc.DoSomething(myothersc.DoSomethingParameter);
    15.     }
    16. }
    But these optimizations aren't necessarily because "GetComponent is terribly slow". It's that ALL work costs time, so why repeat yourself?

    Also, it makes it easier to read!

    This goes for any operation regardless of GetComponent. May it be sqrt, List.Contains, or whatever.

    At the end of the day don't be avoiding a method because of some boogie man logic of it being slow. If the method does what you need it to do... then it does what you need it to do!

    How else are you supposed to get the damage info of the collider you struck? You could have struck 1 of any number of colliders! It's not like you could cache that somewhere.
     
    Vryken, pleasurehouse and PraetorBlue like this.
  9. pleasurehouse

    pleasurehouse

    Joined:
    Oct 15, 2020
    Posts:
    96
    The only situation that I have seen (at the moment) that it is strictly necessary to use GetComponet is the one in the example in my question. In all the other cases that I have seen it has been enough to pass a reference of the GameObject containing the desired component through the editor. In this way, it is not even necessary to initialize within the Start () or Awake () function ... The problem with this is that if you change the name / location of any class, the reference is lost and the GameObject must be assigned again. But I think this way in runtime is the fastest