All my scripts stink

Hi, see the following code snippet to understand what I mean.

using UnityEngine;
using System.Collections;

public class MeteoController : MonoBehaviour {
    bool isRainingOrSnowing = false;
    ParticleSystem rain;
    ParticleSystem.EmissionModule rainEm;
    ParticleSystem.VelocityOverLifetimeModule rainVelocity;
    ParticleSystem snow;
    ParticleSystem.EmissionModule snowEm;
    ParticleSystem.VelocityOverLifetimeModule snowVelocity;
    AudioSource rainSound;
    int currentDropsAmount = 0;
    GameObject lighting;
    Light lightingLight;
    Animation lightingAnimation;
    GameObject lightningBolt;
    Renderer lightningBoltRenderer;
    AudioSource thunderSound;
    DayNightSample dayNightSample;
    ParticleSystem.EmissionModule currentEmitter;
    WindController windController;
    public float currentRain;
    public float rainProbability = .2f;
    public float lightingPropability = 1f;
    public float maxRainParticles = 1000;
    public int dropsIncrease = 5;
    public float firstRainCheck = .5f;
    public float checkRainEvery = 10.0f;
    public float firstLightingCheck = 5.0f;
    public float checkLightingEveryEvery = 10.0f;
    // float currentFogAlpha = 0;

    void Start () {
        rain = GameObject.Find ("RainParticles").GetComponent<ParticleSystem> ();
        rainEm = rain.emission;
        rainVelocity = rain.velocityOverLifetime;
        currentEmitter = rainEm;
        snow = GameObject.Find ("Snow").GetComponent<ParticleSystem> ();
        snowEm = snow.emission;
        snowVelocity = snow.velocityOverLifetime;
        rainSound = GameObject.Find("RainSound").GetComponent<AudioSource>();
        lighting = GameObject.Find("Lighting");
        lightingLight = lighting.transform.FindChild("LightingLight").GetComponent<Light>();
        lightingAnimation = GameObject.Find("LightingLight").GetComponent<Animation>();
        lightningBolt = GameObject.Find("LightningBolt");
        lightningBoltRenderer = lightningBolt.GetComponent<Renderer>();
        thunderSound = GameObject.Find("Thunder").GetComponent<AudioSource>();
        dayNightSample = GameObject.Find("DayNightCycle").GetComponent<DayNightSample>();
        windController = GameObject.Find("GameController").GetComponent<WindController>();
        InvokeRepeating("TryRainOrSnow", firstRainCheck, checkRainEvery);
        InvokeRepeating("TryLighting", firstLightingCheck, checkLightingEveryEvery);
    }

So I have a couple of question:

  1. Do I really have to declare all those variables at the top? Mine is quite a simple project, this specific script controls the weather in the game. If I have so many variables for such a simple script I can’t imagine how it will look when things get bigger!
  2. I use all those GameObject.Find() in the start object because I don’t want to drag them manually into a public field in the inspector as I think that approach is more error-prone. This approach adds a substantial amount of time to the level-loading as Find() isn’t the fastest method. Should I just drag them in the inspector or is there any other best practice?

Thanks for your time.
J

Please post you code as suggested in this thread. That makes it easier for us to do suggestions as to what you can improve.

As for your questions:

Well, you declare variables at the top by convention, so as far as that goes; yes. Whether or not you need all those variables at the top for your specific script, you’ll need to post the entire script for anyone to be able to tell you.

Just wait until you make a typo :wink: No, I always prefare dragging an object to a field instead of using strings to identify objects, as that is imo a lot less error prone (always try to use specific types instead of the general GameObject for these fields to reduce the chances for errors.

Hi there, personnally I usually use the C# region blocks to keep things tidy.

I also have a very clear way of organizing my scripts, resulting of years of experience using unity.

If you’re curious about it, my scripts go like this:

using UnityEngine;
using System.Collections.Generic;

namespace                       MyGame.MyCategory.MySubCategory
{
    public class                MyScript : MonoBehaviour
    {
        #region Input Data
        //Stuff that should/can be set in inspector
        public float            _aCoolFloatValue;
        #endregion

        #region Members
        //private members
        int                     _aNiceIntegerValue;
        #endregion

        #region Unity
        //all the unity magic methods like Awake, Start, Update, OnTriggerEnter...
        void                    Awake()
        {
        }
        #endregion

        #region Triggers
        //Stuff that can be called from outside, wether directly or through SendMessage
        public void             DoSomething()
        {
  
        }
        #endregion

        #region Helpers
        //specific smaller/sub tasks which get split into methods that are used internally go here
        void                    MenialTask()
        {
  
        }
        #endregion

        #region Data types
        //Good way of storing various data that belong together, works well in inspector even in arrays or list
        [System.Serializable]
        public class            MyData
        {
  
        }

        //Looks clean in the inspector so i abuse it
        public enum             MyEnum
        {
      
        }
        #endregion
    }
}

When necessary I can also have events or properties regions.

This all folds nicely and I always know where to look for specific stuff even years after writing it.

Hope it helps !

PS: Regarding the use of Find(), if I may add, you’re dependent on object names when using it so I don’t think it’s less error prone than wiring things in the inspector, it also prevents you from reusing your component with otherwise named objects. Wiring in the inspector is just the way you do things in Unity, it differs from what you may be used to in other environnement but that’s how we roll here :smile:.

You can imagine all kinds of structures but efficient ways of getting references to objects will involve wiring things in the inspector or keeping references of spawned object (and if you spawn them it probably means you have a reference to a prefab that you wired in the inspector anyways :smile:)

Whatever the faults of Find (and yes, you should drag objects in the inspector for reasons stated above), it doesn’t add any noticeable time to level-loading. When people say Find is “slow”, that’s relative, as in doing it hundreds/thousands of times per frame, compared to direct references. It’s not slow as in “can time it with a stop watch”…we’re talking microseconds here, depending on how many objects are in the scene.

–Eric

2 Likes

the one thing that stands out to me is that you’re dealing with all the “bits” individually… to me it would make more sense to group the animator/sound/particle/whatever into a data class/structure, and then reference to that data structure. So instead of “find the rain particles, find the rain sound, find the rain this, find the rain that, find the rain other” you just “find the rain weather dataobject”. You then might also want to consider using something like a dictionary to store the references to the weather effect dataobjects, you can then add in another one without needing to rewrite everything.

1 Like

Your script is doing a_lot_of_things!

You could probably make things much easier on yourself by having a rain controller, a day-night controller, a lightning controller and so on. Then your main MeteoController uses those scripts instead of having to worry about a ton of variables.

Find() is generally a bad idea because it’s based on thing’s names. So if you know that there’s a bunch of Find calls around, you suddenly can’t rename anything, since there’s a non-zero probability that some other script’s reliant on the naming.

Especially if you work with other people, that’ll be a nightmare.

4 Likes

I would consider ditching the module storage. As far as I’m aware accessing a particle system module is a direct reference. So there is little to no value to caching it. That will cut the amount of variables down dramatically.

But overall I think @Baste is right. Why is one script controlling lightening, rain, and snow. Better to have a script for each, and then if you need it you can build a master script to rule them all.

1 Like

Thanks everyone! I see what you mean :slight_smile:
Next up on this channel, refactoring! stay tuned :wink: