C#: Create a variable placeholder for an unknown script

I’ve seen this question asked, and the answer seems to be that it can’t be done…but it’s such a common thing to do in other languages I’m surprised. So, maybe I’m misunderstanding something.

I’m creating a molecular simulation game. It will have lots of atoms with basically all the same functions, but needing different parameters.

It seems the best way to do this (and avoid necessary code duplications) is to write a general “nucleus.cs” script with the action methods, which access a “characteristics.cs” script to determine these parameters.

But there seems no way to attach different (unknown or differently named) scripts to the variable because of C#'s restrictive casting.

I.e… the plan:

(This script goes on ALL atoms)

public class NucleusScript : MonoBehaviour {

    // External object references
    public IdontKnowWhatToPutHere characteristics;

    public void reactWithHydrogen(){
         if (distance < characteristics.electronegativity){
             // make boom and stuff
         }
}//end class

(OxygenCharacteristic.cs)

public class OxygenCharacteristics : MonoBehaviour {

    float ELECTRONEGATIVITY = 3.44; 

    public float electronegativity {
        get {return ELECTRONEGATIVIY;}
        SET {throw new error you can't do this yadda};
    } 
}//class

(NitrogenCharacteristic.cs)

public class NitrogenCharacteristic : MonoBehaviour {

    float ELECTRONEGATIVITY = 3.04; 

    public float electronegativity {
        get {return ELECTRONEGATIVIY;}
        SET {throw new error you can't do this yadda};
    }
)//class

Then, in unity editor, the nucleus script is dragged to ALL the different atom objects (I.e. Oxygen, Nitrogen, etc)…with this “characteristics” variable placeholder.

THEN, also in unity editor, the script “OxygenCharacteristic.cs” is dragged onto the “characteristics” placeholder within the nucleus script associated with Oxygen.

AND the “NitrogenCharacteristic.cs” script is dragged onto the “characteristics” spot for the nucleus script attached to the nitrogen object.

I hope this makes sense. It’s late.

I’m not locked into this solution. If there’s another way to accomplish this, please suggest it.

Thanks!

I’m creating a molecular simulation game. It will have lots of atoms with basically all the same functions, but needing different parameters.

From the example code you’ve given, it seems more like you have atoms with the same properties, but with different values. As such, can you not simply have a single Nucleus script, but set the appropriate ELECTRONEGATIVITY etc. properties via the inspector and save as a prefab for each nucleus type?

Either that, or it sounds like you might want subclasses of nucleus that inherit from the generic base class. e.g.

NucleusScript.cs - use this to define the generic properties that each nuclues will have, but don’t actually attach this script to an object.

using UnityEngine;
using System.Collections;

public class NucleusScript : MonoBehaviour {

	protected float ELECTRONEGATIVITY;

	// Define methods that can be overriden with specific implementations in derived classes
	protected virtual void Start () {
	}
	
	protected virtual void Update () {
 	}
}

NitrogenCharacteristics.cs - attach this to a nitrogen atom to override the generic base class methods with specific functionality for the nitrogen class.

using UnityEngine;
using System.Collections;

public class NitrogenCharacteristics : NucleusScript {

	// Override the Start() method defined in the base class
	protected override void Start () {
		ELECTRONEGATIVITY = 3.04f;
	}
	
}

OxygenCharacteristics.cs - attach this to an oxygen atom to override the generic base class methods with specific functionality for the oxygen class.

using UnityEngine;
using System.Collections;

public class OxygenCharacteristics : NucleusScript {

	// Override the Start() method defined in the base class
	protected override void Start () {
		ELECTRONEGATIVITY = 3.44f;
	}
}

Are you just asking for an interface? Forgive me if I have any syntax errors

public interface IHasElectronegativity {
    float electronegativity {get;}
}

public class NucleusScript : Monobehaviour {
    public IHasElectronegativity characteristics;
}

public class Oxygen : MonoBehaviour, IHasElectronegativity { 
     public float electronegativity {
         get {return 0;}
     } 
}

Note that interfaces can’t be serialised, but there are tricks to get around this.

So, I decided on using good ol’ fashioned class inheritance. It’s strange to say it felt Klugy (and cumbersome, and difficult) even though some would argue that (programmatically) it’s more proper. It just seems like such a builder friendly interface as Unity would have a better (easier) solution.

Maybe they can add this…?

I’m still open to better ways to do this…

—SOLUTION—

(InheritED class, AtomCharacteristics.cs)

using UnityEngine;
using System.Collections;

namespace AtomCharacteristics {
    public class Characteristics : MonoBehaviour {

        private float ELECTRONEGATIVIY;
        public string testvar = "This is a test variable accessed directly (not through getter).";

        // Constructor called when 
        // "Characteristics characteristics = this.gameObject.AddComponent<Characteristics>();" 
        // is used
        public Characteristics() {
            // Set vars and do stuff here if needed
        }// Characteristics constructor

        // Must be initialized since MonoBehaviour doesn't allow passing variables to constructors
        public void Init(string atomType) {
            if (atomType.IndexOf("Oxygen") > -1)  {ELECTRONEGATIVIY = 3.44F;} // should prolly use another class constructor to set all this
            if (atomType.IndexOf("Nitrogen") > -1){ELECTRONEGATIVIY = 3.04F;} // should prolly use another class constructor to set all this

        }// Init

        // Getter/Setter for electronegativity
        public float electronegativity {
            get { return ELECTRONEGATIVIY; }
            set { ELECTRONEGATIVIY = value; }
        }//electronegativity

	}//class Characteristics
}// namespace AtomCharacteristics

(InheritING class, NucleusScript.cs)

using UnityEngine;
using System.Collections;
using AtomCharacteristics; // My constructor class


public class NucleusScript : Characteristics {

    void Start() {// Use this for initialization ------------------------------------------
        Characteristics characteristics = this.gameObject.AddComponent<Characteristics>();
        characteristics.Init("Oxygen");

        Debug.Log("(testCharacteristics)Electronegativity is " + characteristics.electronegativity);
        Debug.Log("(testCharacteristics)testvar is " + characteristics.testvar);
    }//Start 

    void Update() {	// Update is called once per frame 
    }//Update

    public void reactWithHydrogen(){
         if (distance < characteristics.electronegativity){
         // make boom and stuff
    }//    reactWithHydrogen

    ////// other fun and useful method //////
}//end class