Copies of Scripts

Is there a way i can make “copies” of a script? What i am trying to do is have a interactable object scipt that has all the esentials for something/someone to “talk.” However, for each different object, i want it to say a different thing. So is there a way i can have a script be put onto object a, and then change it’s script to fit that object, and then put the same script on object b, but change the script to fit what that object needs. For example, i have a person that will change what he will say when a monster is destroyed. So is there a way i can put my script onto that person, and then change it so that it will change when he kills that monster. Then on another object, it will change what it says when it goes a specific distance. Am i making sense? If you need more clarification, just ask.

Heres my code. I use C#…

using UnityEngine;
using System.Collections;

public class interactableObject : MonoBehaviour {
	
	public GameObject m_boy;
	public float Dist_from_Object = 3;
	public float yIconOutofScreen = 100000;
	public GameObject interestIcon;
	public Texture2D m_backgroundTexture;
	public string text;
	public int stringNumbers = 3;
	public GUIStyle m_guiStyle;
	public string[] stringList;		//arrays for different speeches
	public bool[] boolList;
	public GameObject[] monsterList;
	
	
	private Rect textRect;
	private bool IconOn = false;
	private float m_distance;
	private bool textOn = false;
	private bool m_exclaimStart = false;
	private int m_counter;

	


	
	// Use this for initialization
	void Start () 
	{
		interestIcon.gameObject.active = true;
		m_guiStyle.normal.background = m_backgroundTexture;
		textRect.x = Screen.width;
		textRect.y = Screen.height / 10;
		textRect.height = 150;
		textRect.width = 150;
		
		
	}
	
	void Update()
	{
		ChangeBool();
		
	}
	// Update is called once per frame
	void OnGUI () 
	{
		
		
		m_distance = Vector3.Distance(gameObject.transform.position, m_boy.transform.position);
		
		if(m_distance <= Dist_from_Object)
		{
			if(IconOn == false)
			{
				interestIcon.gameObject.active = true;
				m_exclaimStart = true;
				IconOn = true;

				
				
			}
			
			if(Input.GetButtonDown("Talk"))
			{
				textOn = true;
			}
			
			if(textOn == true)
			{
				StringSay();
			}
			
		}
		
		else
		{
			Vector3 temp_position = interestIcon.transform.position;
			
			temp_position.y -= yIconOutofScreen;
			
			interestIcon.transform.position = temp_position;
		
			interestIcon.gameObject.active = false;
			
			IconOn = false;
			textOn = false;
		}
	
	}
	//ignore this
	public bool ExclaimStart
	{
		get {return m_exclaimStart;}
		set {m_exclaimStart = value;}
	}
	
	//use the public arrays and bools to display a new speech
	//depending on which bool is on
	void StringSay()
	{
		for(int i = 0; i < boolList.Length; i++)
			
		if(boolList[i] == true)
			GUI.Box(textRect, stringList[i], m_guiStyle);
		
	}
	
	void ChangeBool()
	{
		for(int i = 0; i < boolList.Length; i++)
		{
			if(monsterList[i].active == false)
			{
				int g = i + 1;
				boolList[g] = true;
				boolList[i] = false;
			}
		}
				
	}
}

This is what my code for my interactableobject is. At the bottom are arrays and loops to help switch between the speeches.

This sounds like you’re just looking for a nice way to manage the different text strings. While there are many various ways to do this, one very simple way might be:

public static class TalkResources
{
	public const string MonsterDeath1 = "OMFG the monster died";
	public const string MonsterDeath2 = "WAT the monster is dead!";

	public const string Greeting1 = "Hello adventurer!";
}


public class InteractableObject : MonoBehaviour
{
	
	public string CurrentText = String.Empty;

	private void Say()
	{
		GUI.Box(textRect, this.CurrentText, m_guiStyle);
	}
}

//creating your player
InteractableObject player = Instantiate(....
player.CurrentText = TalkResources.Greeting1;


//on the death of your monster
player.CurrentText = TalkResources.MonsterDeath1;

Unless maybe I’m misunderstanding. Are you asking for a nice way to manage the changing of messages or automatically cycling through them based on game events?

The way I’d do this is have a global script “GameManager” that has all the unique statuses -

enum Event {
  MonstersMurdered
  PotionsImbibed,
  DestroyedEarth,

  numberOfEvents
}
var eventStatus : int[] = new int[ Event.numberOfEvents ];

Then a monster could have, for example -

var notify : Event = Event.MonstersMurdered;

function OnDeath() {
  GameManager.eventStatus[ notify ]+= 1;
}

And when someone (or a sign or a cutscene or whatever) wants to know if you’ve murdered 10 monsters (or one specific boss critter, or whatever) -

class DialogueEntry {
  var text : String;
  var eventToCheck : Event;
  var eventLevelNecessary : int;
}
var dialogue : DialogueEntry[];

function Talk() {
  for ( var ix : int = 0; ix < dialogue.length; ix++ ) {
    if ( GameManager.eventStatus[ dialogue[ix].eventToCheck ] >= dialogue[ix].eventLevelNecessary ) { // or ==
      ShowText( dialogue[ix].text );
    }
  }
}

Using the enum ‘Event’ rather than int will let you choose from a nice list in the inspector for the dialogue requirements etc.

What i am mainly asking for is a way to switch between “talks” easisly without making a new script for each object, more like a copy of a script that i can change for the specific object i am working on.

For this, that may work as i want, but i have two questions.

  1. How do u make a script / class global ( i know about variables, but not quite so sure about an actual script)
  2. I need more clarification on what an Enum actually is. An article and/or a short summary would be helpful. Thanks.

The var in that “global” script should be

static var eventStatus

Static vars and functions can be acccessed from anywhere (ScriptName.varName) even if there are no gameobjects that are that type. With that script, you wouldn’t need to attach it to anything; if you later added an Update() or something else which requires an instance of the class, then you’d attach it to a gameObject.

I use global to mean a ‘singleton’ or a one-of class. I probably shouldn’t. >…<

Enums are lists of integers that can be referred to by name -

enum Integer {
Zero, One, Two, Three
}

Integer.Zero == 0, Integer.One == 1, Integer.Two == 2

You can manually set the values too.:

enum Powers {
XRay = 1, Flight = 0, Feather = 7
}

And when you have a
var power : Powers;

comma, the Inspector provides you with a nice drop-down list of all the options you can choose. Try it out with this simple script and you can see it:

enum DangerLevel {
  Blue, Orange, Red, BlackwatchPlaid
}

var currentDangerLevel : DangerLevel;

I used enum above so that in the DialogueEntry, you the game designer would have an easy-to-access list of events rather than having to type in integers from memory (always nasty and error-prone)

So, basiclly an enum is like an array except u acess the different data with names and not numbers?

then for the global…

So, can u make the script itself a global thing or just a variable?
Also, w/ c#, in ur example above, what would i put in place of “var”, just “void” in that case?

I think of an enum as separate from arrays completely. (The full name is ‘enumeration’ if you want to do your own searches on it)

Create an object named GameManager.
Create a script named GameManager.
Put the GameManager script on the GameManager object.

The GameManger up above does nothing itself, but you could easily add -

function Update() {
  for ( var i : int = 0; i < eventStatus.length; i++ ) {
    if ( event[i].time > TIme.time ) DoSomething();
  }
}

Obviously that doesn’t do anything right now but since it’s so closely related to the events it’s good to have that in the same script.

Unityscript variables are declared as (optional words in parentheses)

(private) (static) var name : Type;

C# is

(private/public) (static) Type name;

So a static var x : int[ ] would be public static int[ ] x;

But, is there any way u can make a whole script global, and any other script can access variables from that script?

There’s a sample of a “global” (blurgh, I hate that term) script in my post.

EDIT: there’s no real such thing as a global script though. Marking a class as static just enforces that all of its members must be static as well. Even if a script is not “global”, if it has “global” properties, they can be accessed statically:

public class MyInstanceClass
{
	public static string MyGlobalText = "asdf";
}

Ok, Vincenti, i have a couple of questions. I have been working with what you had first suggested in your first post and there are somet things i need help on.

  1. There is another class/variable in Unity that is called Event, so i need clarification on which is the “variable” event and which is the enum Event (in your example).
  2. If i cannot make a whole script static (global), which it seems to be the case, then i cannot seem to put many things “global”, like classes, because it says that it is declaring values or something like that.
  3. When i put a new class in my C# script, none of those variables came into the inspector. Is there a way to fix that, or am i making the code all wrong?

Heres my code i have:

GameMangager:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	
	public enum m_Event //changed the name so that it would not be mixed up
						//with the variable Event
	{
		MonstersKilled,
		
		numberOfEvents
	}
	
	
	public static int[] eventStatus = new int[ (int)m_Event.numberOfEvents];
	
	public class DialogueEntry
	{
		public string text;
		
	}
}

MonsterStats:

using UnityEngine;
using System.Collections;

public class monsterStats : MonoBehaviour {
	
	private int m_health = 5;
	public int m_experience = 10;
	public GameObject boy;
	public int yOutofScreen = -10000;
	public GameManager.m_Event notify = GameManager.m_Event.MonstersKilled;
	private playerStats m_playerStats;
	
	void Start()
	{
		m_playerStats = boy.GetComponent<playerStats>();
	}
	
	
	// Update is called once per frame
	void Update () 
	{
		
		if(health <= 0)
		{
			GiveExperience();
			GameManager.eventStatus[ (int) notify] += 1; //notify GameManager
			gameObject.active = false;
			Vector3 temp_position = transform.position;
			temp_position.y = yOutofScreen;
			transform.position = temp_position;
			
			Debug.Log("Boy Experience: " + m_playerStats.experience);
		}
	
	}
	
	public int health
	{
		get { return m_health; }
		set { m_health = value; }
	}
	
	void GiveExperience()
	{
		m_playerStats.experience += m_experience;
	}
	
	void Attack(int damage)
	{
		Debug.Log("Hurt Monster");
		m_health -= damage;
		
	}
}

the interactable object (focus on the bottom part…):

using UnityEngine;
using System.Collections;

public class interactableObject : MonoBehaviour {
	
	public GameObject m_boy;
	public float Dist_from_Object = 3;
	public float yIconOutofScreen = 100000;
	public GameObject interestIcon;
	public Texture2D m_backgroundTexture;
	public string text;
	public int stringNumbers = 3;
	public GUIStyle m_guiStyle;
	public string[] stringList;		//arrays for different speeches
	public bool[] boolList;
	public GameObject[] monsterList;
	
	
	private Rect textRect;
	private bool IconOn = false;
	private float m_distance;
	private bool textOn = false;
	private bool m_exclaimStart = false;
	private int m_counter;

	


	
	// Use this for initialization
	void Start () 
	{
		interestIcon.gameObject.active = true;
		m_guiStyle.normal.background = m_backgroundTexture;
		textRect.x = Screen.width;
		textRect.y = Screen.height / 10;
		textRect.height = 150;
		textRect.width = 150;
		
		
	}
	
	void Update()
	{
		ChangeBool();
		
	}
	// Update is called once per frame
	void OnGUI () 
	{
		
		
		m_distance = Vector3.Distance(gameObject.transform.position, m_boy.transform.position);
		
		if(m_distance <= Dist_from_Object)
		{
			if(IconOn == false)
			{
				interestIcon.gameObject.active = true;
				m_exclaimStart = true;
				IconOn = true;

				
				
			}
			
			if(Input.GetButtonDown("Talk"))
			{
				textOn = true;
			}
			
			if(textOn == true)
			{
				StringSay();
			}
			
		}
		
		else
		{
			Vector3 temp_position = interestIcon.transform.position;
			
			temp_position.y -= yIconOutofScreen;
			
			interestIcon.transform.position = temp_position;
		
			interestIcon.gameObject.active = false;
			
			IconOn = false;
			textOn = false;
		}
	
	}
	//ignore this
	public bool ExclaimStart
	{
		get {return m_exclaimStart;}
		set {m_exclaimStart = value;}
	}
	
	//use the public arrays and bools to display a new speech
	//depending on which bool is on
	void StringSay()
	{
		for(int i = 0; i < boolList.Length; i++)
			
		if(boolList[i] == true)
			GUI.Box(textRect, stringList[i], m_guiStyle);
		
	}
	
	void ChangeBool()
	{
		for(int i = 0; i < boolList.Length; i++)
		{
			if(monsterList[i].active == false)
			{
				int g = i + 1;
				boolList[g] = true;
				boolList[i] = false;
			}
		}
				
	}
	
	public class DialogueEntry //start the notification and such w/ GameManager
	{
 		public string text;
  		public GameManager.m_Event eventToCheck;
  		public int eventLevelNecessary;
	}

	public DialogueEntry[] dialogue;

	void Talk() 
	{
  	for ( int i = 0; i < dialogue.Length; i++ ) 
		{
    	if ( GameManager.eventStatus[ (int)dialogue[i].eventToCheck ] >= dialogue[i].eventLevelNecessary ) { // or ==
     	 	GUI.Box(textRect, dialogue[i].text, m_guiStyle);
    }
  }
}
}

There are other things i need to work on in this code, but it seems to me that somewhere (if i have like 20 signposts) something is going to get mixed up when a monster notifies the GameManger object.

Any solutions to my problems anyone?

I forgot about the Event class, sorry. You did right to rename it; I wasn’t using Unity’s Event at all. x_x

I don’t use C# enough myself to know its specific needs, but I do recall [Serializable] being required in some places - that might be what’s causing things to be not showing up in the inspector.

WHen something is static, that means only once instance of it exists for every copy of that class. If you declare the class static then everything in it must be static and you can have no instances of that class. Scripts themselves are neither static nor not static, they’re just scripts. It’s the class that’s static or not. :slight_smile:

Hmmm, the new class in my “interactable object” script just dont show up. None of the variables, nothing. I even put [SerializeField] and it doesnt show up in the inspector. Is there something different i have to do with classes with c#? Anyone know?

Heres my code for my object (i havent cahnged anything else yet)

using UnityEngine;
using System.Collections;

public class interactableObject : MonoBehaviour {
	
	public GameObject m_boy;
	public float Dist_from_Object = 3;
	public float yIconOutofScreen = 100000;
	public GameObject interestIcon;
	public Texture2D m_backgroundTexture;
	public string text;
	public int stringNumbers = 3;
	public GUIStyle m_guiStyle;
	public string[] stringList;		//arrays for different speeches
	public bool[] boolList;
	public GameObject[] monsterList;
	
	
	private Rect textRect;
	private bool IconOn = false;
	private float m_distance;
	private bool textOn = false;
	private bool m_exclaimStart = false;
	private int m_counter;

	


	
	// Use this for initialization
	void Start () 
	{
		interestIcon.gameObject.active = true;
		m_guiStyle.normal.background = m_backgroundTexture;
		textRect.x = Screen.width;
		textRect.y = Screen.height / 10;
		textRect.height = 150;
		textRect.width = 150;
		
		
	}
	
	void Update()
	{
		ChangeBool();
		
	}
	// Update is called once per frame
	void OnGUI () 
	{
		
		
		m_distance = Vector3.Distance(gameObject.transform.position, m_boy.transform.position);
		
		if(m_distance <= Dist_from_Object)
		{
			if(IconOn == false)
			{
				interestIcon.gameObject.active = true;
				m_exclaimStart = true;
				IconOn = true;

				
				
			}
			
			if(Input.GetButtonDown("Talk"))
			{
				textOn = true;
			}
			
			if(textOn == true)
			{
				StringSay();
			}
			
		}
		
		else
		{
			Vector3 temp_position = interestIcon.transform.position;
			
			temp_position.y -= yIconOutofScreen;
			
			interestIcon.transform.position = temp_position;
		
			interestIcon.gameObject.active = false;
			
			IconOn = false;
			textOn = false;
		}
	
	}
	//ignore this
	public bool ExclaimStart
	{
		get {return m_exclaimStart;}
		set {m_exclaimStart = value;}
	}
	
	//use the public arrays and bools to display a new speech
	//depending on which bool is on
	void StringSay()
	{
		for(int i = 0; i < boolList.Length; i++)
			
		if(boolList[i] == true)
			GUI.Box(textRect, stringList[i], m_guiStyle);
		
	}
	
	void ChangeBool()
	{
		for(int i = 0; i < boolList.Length; i++)
		{
			if(monsterList[i].active == false)
			{
				int g = i + 1;
				boolList[g] = true;
				boolList[i] = false;
			}
		}
				
	}
	[SerializeField] //doesnt show in inspector
	public class DialogueEntry //start the notification and such w/ GameManager
	{
 		public string text;
  		public GameManager.m_Event eventToCheck;
  		public int eventLevelNecessary;
	}
	
	[SerializeField] // doesnt show in inspector
	public DialogueEntry[] dialogue;

	void Talk() 
	{
  	for ( int i = 0; i < dialogue.Length; i++ ) 
		{
    	if ( GameManager.eventStatus[ (int)dialogue[i].eventToCheck ] >= dialogue[i].eventLevelNecessary ) { // or ==
     	 	GUI.Box(textRect, dialogue[i].text, m_guiStyle);
    }
  }
}
}

Any answers anyone?

Try marking the class itself as Serializable:

[System.Serializable]
public class interactableObject : MonoBehaviour {

You shouldn’t need to put ‘SerializeField’ before ‘public DialogueEntry[ ] dialogue’. Also, you want to put the ‘Serializable’ attribute before the DialogueEntry class, not the ‘SerializeField’ attribute (DialogueEntry is a class, not a field).

That shouldn’t be necessary, and is unlikely to solve the problem. (See my post above for more info.)

Woops, wrong class! Thanks Jesse!

Sweet, i think the [System.Serializable] thing worked. I tryed it earlier and it didnt work though (maybe i did it wrong).

Just to ask a question, what is [System.SerializableAtrribute]?

It’s the same as Serializable. I believe the C# compiler allows the “Attribute” suffix to be optional, though I may be wrong on the specifics of how or why that is.