I have a Manager class and it has lots of variables so I can reference it when I need it.
Will this reduce the performance ? or should I define it
public class Controller: MonoBehaviour
{
public GameObject Manager;
}
public class GetController : MonoBehaviour
{
public GameObject Controller ;
void dosomthing(){
var Ma = Controller.Getcomponent<Controller>().Managet
}
}
TLDR; Getcomponent() calls are expensive. It is OK if used once/rarely, but starts to have an effect when called continiously.
Store a reference (define) to it:
public class GetController : MonoBehaviour
{
// Will show up in unity's inspector.
// Drag-and-Drop the gameObject with the 'Controller' component attached to it.
[SerializeField]
private Controller yourController ;
void Dosomthing(){
var Ma = yourController.Manager
}
}
Also, most things in Unity can be exposed to the Inspector as long as it is serializable.
You can expose a Controller field to the inspector, and drag-drop the same GameObject.This lets you skip a GetComponent call and another define.
I suggest using a singleton pattern for managers.
public class GameManager : MonoBehaviour
{
public static GameManager singleton; // define variable as singleton
public int score = 2; // for example...
private void Start() => singleton = this; // setup single user class instance
}
And in the player class or any other class, call it without redefining it.
public class Player : MonoBehaviour
{
public void AddScore() => GameManager.singleton.score += 1; // add score to manager
}
Related
I'm creating an enemy (from EnemyCreator1 class) with both EnemyMove1 and MarkusEnemy scripts (EnemyMove1 is a parent class to MarkusEnemy class). In EnemyCreator1 class I set value mainState of the script EnemyMove1 to "CHASE", but when I'm trying to access it from that class it says that mainState is "IDLE" (Please read my coments below because there are more explanations about what am I trying to achieve)
public class EnemyMove1 : MonoBehaviour
{
public enum mainStates { IDLE, CHASE }
public mainStates mainState;
void Update()
{
Debug.Log(mainState); //mainstate == IDLE, but should be CHASE
}
}
public class EnemyCreator1 : MonoBehaviour
{
[SerializeField] private GameObject enemyPrefab;
public void CreateEnemyAndSetItsStateToChase()
{
GameObject enemy = Instantiate(enemyPrefab);
enemy.GetComponent<EnemyMove1>().mainState = EnemyMove1.mainStates.CHASE;
}
}
public class MarkusEnemy : EnemyMove1
{
void Update()
{
EnemyMove enemyMoveScript = GetComponent<EnemyMove>();
Debug.Log(enemyMoveScript.mainState); //mainstate == CHASE
}
}
From the above code it looks like you are inheriting from a different base class EnemyMove, not EnemyMove1.
Thank you guys for helping me, after searching for the information about base classes I decided that it is impossible to access directly it's variables from another objects' scripts so I just simply call methods with variables as arguments (I put variables in round brackets of the method)
I am trying to get all my abilities to follow instructions from a superclass to decrease the amount of repetitive code. I tried doing this by passing in Monobehavior as a parameter in constructor. This would work perfectly, except I get a warning saying I simply can't do this. Here is my super class.
public class Ability : MonoBehaviour {
private SpriteRenderer renderer;
private MonoBehaviour ability;
public Ability(MonoBehaviour b) {
ability = b;
renderer = ability.GetComponent<SpriteRenderer>();
}
public void Start () {
}
void Update () {
}
public void checkAvailability()
{
if (ability.GetComponentInParent<SpeedBall>().getAvail())
{
renderer.enabled = true;
}
else
renderer.enabled = false;
}
public void updateRenderer()
{
renderer.enabled = true;
renderer.transform.position = ability.GetComponentInParent<BoxCollider>().transform.position;
renderer.transform.localScale = new Vector3(.2f, .2f, 0);
}
and here is one of the child classes, which would work perfectly.
public class Sprite : MonoBehaviour {
private Ability ability;
void Start () {
ability = new Ability(this);
}
// Update is called once per frame
void Update () {
ability.updateRenderer();
ability.checkAvailability();
}
}
This is untraditional, but it should work. Is there anyway to accomplish this same thing without passing in Monobehavior. I can't extend multiple classes, and I need it to extend MonoBehavior. Thanks for any help!
You can access base class inherit members into derived class. For clarification suppose you have ExtendMonobhevior class (Your own version of Monobehaviour with additional functionalities).
class MonoBehaviourExtended : MonoBehaviour {
//your extended featuer of MonoBehaviour goes here
}
Now you can drive your normal classes(which you want to attach with gameobjects) from MonoBehaviourExtended(your custom extended version of MonoBehaviour ) it also contains MonoBehaviour
//inherit with extended monobehviour also contains extended features
public class Player : MonoBehaviourExtended {
//your normal class functinality
}
//inherit with extended monobehviour also contains extended features
public class Enemy : MonoBehaviourExtended
{
//your normal class functinality
}
And you get full access to the MonoBehaviour also.
I'm making a game in Unity3D with C# for mobile devices and can't figure out how to check which scene was loaded before the current scene. I need to check this to change the spawn point from the player gameobject. First I added a simple script to my buttons (loadnextscene and loadprevscene)
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Application.LoadLevel(sceneNumber);
}
}
A second scripts handles the touch input from the user and changes the movement of the player object.
So, for example: If the player clicks on the "load previous scene" button in the second Level to switch to the first level again, I want to set the spawn point of the player object on the right half on the screen and not on the left side like when the game was started the first time.
I tried it with Singleton and PlayerPrefs, but it did not work out.
You need to save the scene number to some variable before LoadScene, then check it after the scene loaded.
The only problem is that this variable will be destroyed after the new scene is loaded. So, to prevent it, you can use DontDestroyOnLoad. Here is what you do:
First, create a new empty game object, and attach the following script to it:
using UnityEngine;
using System.Collections;
public class Indestructable : MonoBehaviour {
public static Indestructable instance = null;
// For sake of example, assume -1 indicates first scene
public int prevScene = -1;
void Awake() {
// If we don't have an instance set - set it now
if(!instance )
instance = this;
// Otherwise, its a double, we dont need it - destroy
else {
Destroy(this.gameObject) ;
return;
}
DontDestroyOnLoad(this.gameObject) ;
}
}
And now, before you load, save the scene number in the Indestructable object:
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Indestructable.instance.prevScene = Application.loadedLevel;
Application.LoadLevel(sceneNumber);
}
}
And last, in your scene Start() check Indestructable.instance.prevScene and do your magic accordingly.
More info here:
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
*I did not compile the code, so there may be some errors, but this is the general idea.
Why did the PlayerPrefs approach did not work?
I think its the easiest way to solve your problem.
public class FirstLevel : MonoBehaviour {
public void Start() {
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
}
And then in the second scene simply read the saved PlayerPrefs
public class SecondLevel : MonoBehaviour {
string PrevScene;
public void Start() {
PrevScene = PlayerPrefs.GetString("SceneNumber");
// if there will be a third scene, etc.
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
public void GoToPrevScene() {
SceneManager.LoadScene(PrevScene);
}
}
You can solve this problem with a single static member variable in the SwitchScene class. No need for the singleton pattern or DontDestroyOnLoad.
public class SwitchScene : MonoBehaviour
{
public int sceneNumber;
private static int previousScene;
private int oldPreviousScene;
void Start()
{
oldPreviousScene = previousScene;
previousScene = sceneNumber;
}
public void HandleLoadPrevButtonClick()
{
SceneManager.LoadScene(oldPreviousScene);
}
}
In Unity, I have
public enum inven {Food,Scissors,Nothing};
public inven held;
How can I access the enum and, more importantly, the information contained in the held variable, from another script.
I tried the Singleton Method:
public class Singleton : MonoBehaviour {
public static Singleton access;
public enum inven {Nothing, Scissors, Food};
public inven held;
void Awake () {
access = (access==null) ? this : access;
}
}
to make global variables, accessed by
Singleton.inven.food //or
Singleton.access.held //respectively
However, that returned "Null reference exception: Object reference not set to an instance of an object."
I also tried using this:
public class Accessor : MonoBehaviour {
void Start() {
GameObject HeldItem = GameObject.Find("Story"); //where story is the Gameobject containing the script of the enum and variable
TextController textcontroller = Story.GetComponent<Textcontroller>(); //Where TextController is the sript containing the enum and variable
}
}
accessed by TextController.held etc, returned that it needed an object reference. What is the proper way of doing this?
Here's how I do my singletons. In my case, it's called SharedData.
using UnityEngine;
using System.Collections;
public class Booter : MonoBehaviour
{
void Start ()
{
Application.targetFrameRate = 30;
GameObject obj = GameObject.Find("Globals");
if(obj == null)
{
obj = new GameObject("Globals");
GameObject.DontDestroyOnLoad(obj);
SharedData sharedData = obj.AddComponent<SharedData>();
sharedData.Initialize();
}
}
}
This script is attached to an object in the first scene that loads, and it is set in the script execution order to go first. It creates a GameObject to attach the SharedData component to, then tells the engine not to delete that GameObject when new levels are loaded.
Then to access it, I do this:
public class Interface : MonoBehaviour
{
private SharedData m_sharedData;
public void Initialize()
{
GameObject globalObj = GameObject.Find("Globals");
m_sharedData = globalObj.GetComponent<SharedData>();
m_sharedData.LoadData(); // This is where I use something on the singleton.
}
}
In order to get variable(s), function(s) in another class, I have known 2 ways of doing this. First, is to use Get Component to the Script that we want to get the variable(s), function(s) into. Second, is to use Instance of the Script itself.
So I have made the following code:
First case: Get Component to the Script itself
public class Manager : MonoBehaviour
{
private AnotherManager _anotherManager;
private void Awake()
{
_anotherManager = GameObject.Find("Managers").GetComponent<AnotherManager>();
}
private void Start()
{
_anotherManager.myIntVariable = 10;
_anotherManager.MyFunction();
}
}
public class AnotherManager : MonoBehaviour
{
public int myIntVariable;
public void MyFunction()
{
}
}
Second case: Use Instance of the Script itself
public class Manager : MonoBehaviour
{
private void Start()
{
AnotherManager.instance.myIntVariable = 10;
AnotherManager.instance.MyFunction();
}
}
public class AnotherManager : MonoBehaviour
{
public static AnotherManager instance;
public int myIntVariable;
private void Awake()
{
instance = this;
}
public void MyFunction()
{
}
}
My question is: Is there any difference between those cases? In terms of good practice of coding for programmer or performance or it is just a matter of programmer's perspective or whatever else?
Thanks
The second example is the what is known as the Singleton Pattern and should be used very sparingly.
I try to never use the first approach either where you find the gameobject and hope it exists.
You can expose a field for the Unity Inspector so that you can wire it up the same as you can expose any other variable
public AnotherManager AnotherManager;
Alternatively, if you hate using public all over the place like that, like me, you can also indicate to Unity that you wish to expose this variable in the inspector with the SerializeField attribute
[SerializeField]
private AnotherManager anotherManager;
With both of these methods, you can then drag an an object that has the AnotherManager component attached into the field in the inspector.
If instantiated objects need access to this, you will need to wire it up when it is instantiated.
If you need help attaching it in unity I can attach some screenshots.