Is this a good, inexpensive idea?

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:

Properties prop = raycasthit.transform.getComponent<Properties>();
//check for a door
if(prop.isDoor)
{
//door code
}

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.

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…

 public abstract class Property: MonoBehaviour {
    public abstract void Interact();
}
 public class Door : Property
{
    public override void Interact()
    {
        // Door logic goes here
    }
}

Now you can put the door script on your door. With your raycasthit, you can interact with any derived property component:

 raycasthit.gameObject.GetComponent<Property>().Interact();
2 Likes

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:

using UnityEngine;
using System.Collections;

public class Properties : MonoBehaviour
{
    public bool isDoor = false;//what objects can be opened like doors
    public bool isClosed = false;//whether or not a door is opened / closed
    public bool isFlickering = false;//whether or not a light source is flickering
    public bool isBroken = false;//whether or not a device can be operated
    public bool isRepairable = false;//whether or not a broken object can be fixed
    public bool isPickup = false;//whether or not an object can be taken into your inventory
    public bool isDraggable = false;//whether or not an object can be moved in the world
    public bool isTrigger = false;//whether or not interaction with this object will trigger an event like a trap
    public bool needsInspection = false;//designates an object that needs to be inspected
    public bool dropsSanity = false;//whether or not an object will cause sanity loss when stared at
    public bool SanityNear = false;//whether or not an object will affect sanity when within a certain distance
    public float sanityDistance = 0;//how close to an object the player can be before sanity affects take place
    public bool raisesSanity = false;//whether or not an object will cause sanity gain when stared at
}

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.

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?

2 Likes

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.

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.

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.

No. That is a bastardization with a completely different meaning than what Kay actually said.

The real quote is this:

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:

public class Door : MonoBehaviour {
public bool isOpen;
}
....
public class Pickup : MonoBehaviour {}
.....
//in your raycast code
Door d = raycastHit.transform.GetComponent<Door>();
if (d) {
//do door stuff
}
Pickup p = raycastHit.transform.GetComponent<Pickup>();
if (p) {
//do pickup stuff
}

....
//and you can also use this
Pickup[] allPickupsInScene = FindObjectsOfType<Pickup>();
//which is nearly as slow as GameObject.Find, but WAY more useful.

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.

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.