Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by Moose5 · Jun 19, 2016 at 08:27 PM · c#collisiongetcomponentsendmessage

acting on other object during collision: SendMessage or GetComponent?

Common thing that happens in a million different games: A projectile hits something, and then does something to whatever it hits (damage, plays a sound, flashes color, etc). The reaction to the collision is different depending on the components attached to the objects involved, e.g. a piece of terrain wouldn't take damage. From what I know, there are two ways to deal with this: SendMessage(), a bunch of GetComponent() calls, or checking tags followed by either method calls depending on the tag. All of these work, but also seem to have their own problems.

SendMessage() seems like by far the most elegant and simple. the sender doesn't have to care what scripts the other object has, but if any of them have the method, it gets called. However this would result in a lot of SendMessage() calls that don't do anything, plus I've heard that SendMessage() is very slow, so a high-action moment with dozens of collisions happening in a single frame could take a big performance hit.

A bunch of GetComponent() calls to achieve the same thing seems a lot less elegant, but might perform better. What I mean is something like

 void OnCollisionEnter(Collision other)
 {
     IDamageable damageable = other.gameObject.GetComponent<IDamageable>();
     if (damageable != null) {//do damage stuff} 
 
     IHitFlashable hitFlash = other.gameObject.GetComponent<IHitFlashable>();
     if (hitFlash != null) {//do hitflash stuff}
 
     //and so on for any other relevant scripts
 }

This is a lot less elegant looking, but I understand that GetComponent<>() might be significantly faster than SendMessage(). However this still has the problem of making a bunch of unnecessary calls.

finally, there is the option of limiting either the SendMessage() or GetComponent<>() calls by checking the tag of the other object and making calls depending on what the tag is. However, then you run into the problem of needing a different tag for each different combination of relevant scripts which could be attached to the other object, and end up with a real messy pile of tags to keep track of.

SO my question is, which way do y'all prefer? or is there a pattern for this situation that I haven't thought of or read about that trumps them all? I realize that the difference between each method might be so small that its better to leave to personal preference, but I'm the kind of person who likes to do everything the 'best' way :]

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image smallbit · Jun 20, 2016 at 05:09 AM 0
Share

Nice comparison. I cannot tell you which is the proper way, but I can tell you about my typical setup.

1) Bullet know what can take damage (by tag), tag usage is limited to let set (enemy, environment) 2) When bullet hits enemy I take the component via interface (lets say IDamageable), I am sure that every enemy tag will have script that extends this interface 3) I do only one call passing collision point as argument (which is useful for some situations i.e. spawn blood on hit point) i.e. TakeDamage(Vector3 hitPosition); 4) The rest of the getting hit I do already on enemy side (normally I have an enum with the enemy type) and I execute damage effects differently for each based on this enum. As you said "The reaction to the collision is different depending on the components attached to the objects involved" but the components attached are normally related to the type of object that gets hit, and not the opposite way.

As it goes for the best way, I am afraid there isn't one, even if some code ninja would convince you one solution allocates less than another, it will work differently with i.e. more components etc.. And the elegant looking code, you cannot really measure that :)

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by jdean300 · Jun 20, 2016 at 07:28 AM

Avoid the tags mess. If you're going to have a bunch of different special cases, then trying to use tags to solve this problem is going to become a nightmare.

I'd prefer the GetComponent approach for a few reasons

  1. Compile time checking (SendMessage won't notice when you type "DamgeTargt")

  2. Explicitly describes the code. SendMessage goes by method name - once your project grows to many thousands of lines of code, can you remember every component that has a method by that name? And when adding a new method to a class, you have to consider whether or not that method could be called in a SendMessage call. You might be able to remember this stuff while regularly working on the project, but good luck if you take a break for a few weeks.

  3. Performance. This really does depend on your game and the target platform, but GetComponent is going to be faster. I have seen wildly different results from others' test results - some people say SendMessage is hundreds of times slower than GetComponent, others say it is only two or three times slower. Again, it comes down to platform and the specifics of your game.

The other option you might consider is having some kind EventRouter component inside of each gameObject. Then, your bullets collision code could be this:

 void OnCollisionEnter(Collision other)
 {
     var eventRouter = other.gameObject.GetComponent<EventRouter>();
     if (eventRouter == null)
         return;
 
     eventRouter.SendEvent<HitByBulletEvent>(new HitByBulletEvent(/*whatever data you need*/));
 }

And the components on a gameObject can subscribe to events with the EventRouter, either through delegates or function pointers. I'd prefer function pointers

 private Dictionary<Type, List<Action<Object>>>> m_EventSubscribers;
 
 public void Subscribe<T>(Action<Object> action)
 {
     if (!m_EventSubscribers.ContainsKey(typeof(T)))
         m_EventSubscribers.Add(typeof(T), new List<Action<Object>>());
 
     m_EventSubscribers[typeof(T)].Add(action);
 }
 
 public void SendEvent<T>(Object eventData)
 {
     foreach(var action in m_EventSubscribers[typeof(T)])
     {
         m_EventSubscribers(eventData);
     }
 }

The tradeoffs here are more memory and a bit more code, but you'll get better performance than SendMessage without having to make a mess of all your collision code. Performance wise, I would not be surprised if this was competitive with GetComponent calls - it would depend on how GetComponent was implemented.

To make it faster, use an enum to keep track of event types, then you don't have to call typeof constantly. But then you have maintenance of the enum.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to reference compound colliders? 1 Answer

how to make one script change a variable in another scipt 2 Answers

Distribute terrain in zones 3 Answers

Multiple Cars not working 1 Answer

Variables from one script to another. 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges