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. Dismiss Notice

Is this a good, inexpensive idea?

Discussion in 'General Discussion' started by Tomnnn, Aug 20, 2014.

  1. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I am starting a new project and since I'm still a newbie I'm practicing different approaches to just about everything. The idea in question is the following:
    I made a C# script called 'Properties' that contains a handful of booleans and it's a monobehavior so I can attach it to gameobjects. To give a quick example, there are many objects that can be interacted on in my game. They are all on the use layer and I use a layermask with that layer to narrow them down for raycasting and linecasting.

    When I get an object from the linecast, I do the following:

    Code (CSharp):
    1. Properties prop = raycasthit.transform.getComponent<Properties>();
    2. //check for a door
    3. if(prop.isDoor)
    4. {
    5. //door code
    6. }
    Is this idea scalable and not expensive for the computer? Any objects I hit I know will have this script because of the layer mask, so I can always grab the Properties component. I know all gameobjects can use tags, but I think comparing booleans is faster than comparing strings and using a script component removes the limit on kinds of objects and information you can store for any particular object. I have the booleans isDoor and isClosed assigned to door objects to check when a door is opened or closed. Part of my game will also involve repairable objects which can have the booleans isRepairable and isBroken, or something along those lines. If this is a good idea... then great, feel free to use it. If not, please let me know what would happen if used in game with hundreds to thousands of objects using the monobehavior.

    The idea came to me in the limited use and application of tags + the speed of comparing strings vs comparing booleans. Hopefully it's a good idea.
     
  2. Sornelo

    Sornelo

    Joined:
    Dec 31, 2011
    Posts:
    33
    I think a good place to start would be to define your behaviors in different "property" components. You could have an abstract base class (meaning you never use it directly) and implement it with the different behaviors.

    For example...

    Code (csharp):
    1.  public abstract class Property: MonoBehaviour {
    2.     public abstract void Interact();
    3. }
    Code (csharp):
    1.  public class Door : Property
    2. {
    3.     public override void Interact()
    4.     {
    5.         // Door logic goes here
    6.     }
    7. }
    Now you can put the door script on your door. With your raycasthit, you can interact with any derived property component:

    Code (csharp):
    1.  raycasthit.gameObject.GetComponent<Property>().Interact();
     
    Last edited: Aug 20, 2014
    Zaladur and calmcarrots like this.
  3. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I know this functions very similarly to inheritance, I was trying to come up with a not too expensive but very modular method to replace inheritance - for at least just this project. Here's how the class looks today to maybe give a better idea of what it's being used for:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Properties : MonoBehaviour
    5. {
    6.     public bool isDoor = false;//what objects can be opened like doors
    7.     public bool isClosed = false;//whether or not a door is opened / closed
    8.     public bool isFlickering = false;//whether or not a light source is flickering
    9.     public bool isBroken = false;//whether or not a device can be operated
    10.     public bool isRepairable = false;//whether or not a broken object can be fixed
    11.     public bool isPickup = false;//whether or not an object can be taken into your inventory
    12.     public bool isDraggable = false;//whether or not an object can be moved in the world
    13.     public bool isTrigger = false;//whether or not interaction with this object will trigger an event like a trap
    14.     public bool needsInspection = false;//designates an object that needs to be inspected
    15.     public bool dropsSanity = false;//whether or not an object will cause sanity loss when stared at
    16.     public bool SanityNear = false;//whether or not an object will affect sanity when within a certain distance
    17.     public float sanityDistance = 0;//how close to an object the player can be before sanity affects take place
    18.     public bool raisesSanity = false;//whether or not an object will cause sanity gain when stared at
    19. }
    20.  
    I know I could do something with inheritance but I was trying to avoid it. Also to reiterate, I wanted to get around the limitations of tags and have a modular solution. The idea is to have a list of properties available on objects on a certain layer to make handling them easy when they're interacted with without using any string comparisons.
     
  4. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    The real question for me would be - Do ALL of your objects you are attaching this script to use MOST if not ALL properties defined? It seems to me like you are attempting to throw every property an object might have into one script. Sanity properties, door properties, Broken object properties - All of these seem like they should be separated. Since Unity is component based, if you DO need, say, a door that also raises your sanity when looking at it, you can just add both components.

    Is there a reason you are avoiding inheritance? Difficulty understanding how to implement, or some kind of design choice?
     
    StarManta and Sornelo like this.
  5. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I guess it's a design thing. I wanted the functionality of a component that inherits so you could ask for a property from any object and not worry about the details. I wanted it to flow something like this

    step 1 - ray cast against everything in the 'use' layer
    step 2 - do if statements to check which properties the object has
    step 3 - execute code based on true if statements

    And yes, any prefab in the game can contain most of the properties. I'll most likely replace 'isRepairable' and things like that with just 'needsInspection' and have an array of objects needed to successfully inspect objects. I have a big programming background and I've been told to avoid inheritance because string processing and inheritance were the most expensive / least efficient operations for the languages at the time I was learning them.

    --edit

    That's basically what I wanted to achieve. Attach a property (component) to an object to avoid dealing with tags or something like that. Is it inexpensive to have multiple small components attached to an object vs 1 large one that may have a few at the time unused components?

    This also would touch on adding and removing components via code since a door may be a broken object & a draggable object that needs to be repaired, brought to a location and then the properties script will set those to false and set the door property to true. I acknowledge a lot of the things I'm saying are probably insignificant performance hits, I just like the style.
     
    Last edited: Aug 21, 2014
  6. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    Technically, what you want to do will work, and if that is your preference and what makes sense to you, then I won't stop you from doing it. The only thing I will say is, don't skip inheritance because of efficiency. It makes very little difference, and I don't feel that it is a good idea to sacrifice good code design in an attempt to pre-optimize your code. I promise you, if you are running into optimization issues in Unity, it won't be because you are using inheritance.
     
  7. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    I was told by R 'thunderfist' Keene that "pre-optimization is the root of all evil". This seems to be something that all of you experienced coders know. I've also been told before to get it working with good design before worrying about optimizing.

    I'll keep this in mind for future projects. If the design is wonky but is not bad performance wise, I'll stick with it for this project. It's such a small project that I could probably afford to use multiple Gameobject.find calls in every frame. The project has....

    less than 20 doors
    less than 100 objects that occasionally have a Properties script on them
    less than 40 enemies
    1 boss enemy

    Because of what the enemies are, they have 1 texture wrapped around them without any UV work needed. That will be true for maybe half of the items and most of the walls and floors. The boss will have the only complicated texture. I'm not worried about optimization now, I'm trying out a solution that could scale in a bigger project.

    Thanks everyone for the input. It seems ultimately I just got a reminder of things I forgot at some point in the last year.
     
  8. Woodlauncher

    Woodlauncher

    Joined:
    Nov 23, 2012
    Posts:
    173
    No. That is a bastardization with a completely different meaning than what Kay actually said.

    The real quote is this:
     
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    I'm not seeing how this script is an alternative to GameObject.Find. I think what everyone else is suggesting as the assumed alternative was something more like this:
    Code (csharp):
    1.  
    2. public class Door : MonoBehaviour {
    3. public bool isOpen;
    4. }
    5. ....
    6. public class Pickup : MonoBehaviour {}
    7. .....
    8. //in your raycast code
    9. Door d = raycastHit.transform.GetComponent<Door>();
    10. if (d) {
    11. //do door stuff
    12. }
    13. Pickup p = raycastHit.transform.GetComponent<Pickup>();
    14. if (p) {
    15. //do pickup stuff
    16. }
    17.  
    18. ....
    19. //and you can also use this
    20. Pickup[] allPickupsInScene = FindObjectsOfType<Pickup>();
    21. //which is nearly as slow as GameObject.Find, but WAY more useful.
    22.  
     
  10. BFGames

    BFGames

    Joined:
    Oct 2, 2012
    Posts:
    1,543
    What i would do is to make an abstract Property class (as someone mentioned) with a abstract handler method.

    Now as you know each type of object will have this method implemented, you can call it no matter what type of object it is you hit with your raycast/linecast (under the assumption they have their own layer as you seem to use).

    Then each object have their own code in the handler method. Much cleaner this way and much more scale-able.
     
  11. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Since it's been mentioned the most, I'll look into making an abstract class. I wanted something small I could attach to an object that I could use in a function to quickly identify what it is without tags or something like that.

    I had a feeling that checking for a property.isDoor would be faster than sorting through a list of doors every time a raycast hits something to check if one was hit or trying to name objects and check if the name contains "door" or something.

    It's been very easy to work with to have a script to slap onto random objects in the game to make them behave different, idk. I'll compare it to an abstract class way of doing it afterwards.