unity C# run method from another class - c#

I want to run metod in the class from another class and both of them atached to different obj
Two classes. the first is:
public class NewScore: MonoBehaviour {
public void updateScoreBy( int intr) {
Debug.Log("intr+4"+intr+4);
}
}
and the second is:
public class NewPlus: MonoBehaviour {
public NewScore newscore;
public void OnTriggerEnter2D(Collider2D obj) {
newscore.updateScoreBy(+1);
}
}
When I run my code I recive an arror "NullReferenceException: Object reference not set to an instance of an object" and it points on newscore.updateScoreBy(+1);
How can I fix it?

You need to initialize public NewScore newscore;: drag drop the object that contains that script on that variable in the Inspector panel

depending on what you want to do you could make the function static like:
public static void updateScoreBy(int intr)
{
Debug.Log("intr+4"+intr+4);
}
and call it with:
NewScore.updateScoreBy(1);

You didn't initialize newscore.
Change your NewPlus class like this so it will initialize newscore on construction.
public class NewPlus: MonoBehaviour {
public NewScore newscore;
public NewPlus(){
newscore=NewScore();
}
public void OnTriggerEnter2D(Collider2D obj) {
newscore.updateScoreBy(+1);
}
}

Related

How do I pass a variable between scripts in Unity 2d C#

For example, I have a variable "Wisps" that I want to change when the player picks up an object. But I don't know how to do it. I tried to add a WispDisplay object to call the classes, like in Java, but it doesn't seem to work.
public class WispCode : MonoBehaviour
{
WispDisplay wd = new WispDisplay();
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
wd.setWisp(wd.getWisp()+1);
Destroy(gameObject);
}
}
}
public class WispDisplay : MonoBehaviour
{
public int Wisp = 5;
public Text WispText;
void Start()
{
}
void Update()
{
WispText.text = "Wisp: " + Wisp.ToString();
}
public int getWisp()
{
return Wisp;
}
public void setWisp(int newWisp)
{
Wisp = newWisp;
}
}
Easiest (a tiny bit dirty) way is to use a static variable. Downside: you can only have exactly ONE.
Example:
public class MyClass: MonoBehaviour {
public static int wisps;
}
Then, in ANY class, just use this to access it:
MyClass.wisps = 1234;
The more elegant way, working with multiple class instances, is using references.
Example:
public class PlayerClass: MonoBehaviour {
public int wisps = 0;
}
public class MyClass: MonoBehaviour {
public PlayerClass player;
void Update(){
player.wisps += 1;
}
}
Then, you need to drag-drop (aka "assign") the "PlayerClass" Component (attached to the player) to the the Gameobject that should increase the Wisps count. You can duplicate these objects after assigning the reference.
Now, if you actually want to have some sort of collectible, I'd suggest this approach:
You Have a Player "PlayerClass" and some Objects that are collectible, which have Trigger Colliders.
The objects have this code:
public class Example : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
// probably a good idea to check for player tag:
// other.compareTag("Player");
// but you need to create the "Player" Tag and assign it to Player Collider Object.
if(TryGetComponent(out PlayerClass player))
{
player.wisps += 1;
}
}
}

How could I create a static array or list in a class that holds that class' objects c#

I couldn't find anything online so I'm sorry if this question is too basic.
I want to create a class that has a static list which contains all the objects of that class.
Something along these lines:
public class PlanetSpawner : MonoBehaviour
{
public static List<PlanetSpawner> planetList = new List<PlanetSpawner>();
public PlanetSpawner(Vector3 aStartingCoord, GameObject planet)
{
GameObject.Instantiate(planet,aStartingCoord,new Quaternion(0,0,0,0));
planet.transform.position = aStartingCoord;
planetList.Add(object that called the constructor);
}
}
This code is for a unity script and the object is created in another method (and class):
public GameObject planetPrefab;
// Start is called before the first frame update
void Start()
{
PlanetSpawner testPlanet = new PlanetSpawner(new Vector3(1, 1, 1), planetPrefab);
}
I know I could do this instead:
public GameObject planet;
// Start is called before the first frame update
void Start()
{
PlanetSpawner testPlanet = new PlanetSpawner(new Vector3(1, 1, 1), planet);
PlanetSpawner.planetList.Add(testPlanet);
}
and modify the constructor:
public class PlanetSpawner : MonoBehaviour
{
public static List<PlanetSpawner> planetList = new List<PlanetSpawner>();
public PlanetSpawner(Vector3 aStartingCoord, GameObject planet)
{
GameObject.Instantiate(planet,aStartingCoord,new Quaternion(0,0,0,0));
planet.transform.position = aStartingCoord;
}
}
But I believe the way I want to do it is cleaner and a little bit easier to use
You can just use this to refer to the current object:
public class PlanetSpawner : MonoBehaviour
{
public static List<PlanetSpawner> planetList = new List<PlanetSpawner>();
public PlanetSpawner(Vector3 aStartingCoord, GameObject planet)
{
GameObject.Instantiate(planet,aStartingCoord,new Quaternion(0,0,0,0));
planet.transform.position = aStartingCoord;
planetList.Add(this);
}
}
welcome to the community!
I see this is Unity3D related question, consider joining game dev exchange for more game development related questions and answers.
Problems
Firstly, don't use constructors with MonoBehaviours.
Secondly, class itself should not track its instances count. Make a second class, e.g. PlanetsContainer, which would track all those instances.
Thirdly, to separate logic, have planet data, creation and instances tracking on seperate classes, e.g. PlanetInstance, PlanetsSpawner, PlanetsContainer. PlanetsSpawner should be responsible only for instantiating planets (and maybe adding spawned planets to PlanetsContainer).
Solution
I'm providing complete source just to clarify the idea.
PlanetInstance.cs
public class PlanetInstance : MonoBehaviour
{
// Your planet data here
}
PlanetsContainer.cs
public class PlanetsContainer
{
public readonly List<PlanetInstance> planets;
public PlanetsContainer() : this(0)
{ }
public PlanetsContainer(int initialSize)
{
planets = new List<PlanetInstance>(initialSize);
}
}
PlanetsSpawner.cs
public class PlanetsSpawner : MonoBehaviour
{
[SerializeField] private PlanetInstance _defaultPlanetPrefab;
private PlanetsContainer _planetsContainer;
private void Awake()
{
_planetsContainer = new PlanetsContainer();
}
public void SpawnPlanet(Vector3 startingCoord, PlanetInstance prefab = null)
{
var prefabToSpawn = prefab ?? _defaultPlanetPrefab;
var spawnedPlanet = Instantiate(prefabToSpawn, startingCoord, Quaternion.identity);
_planetsContainer.planets.Add(spawnedPlanet);
}
}

"error CS0116: A namespace cannot directly contain members such as fields or methods" in Unity

I am working on a game in unity and in the script for controlling the buttons in the game mode menu.
While writing this error occurred:
error CS0116: A namespace cannot directly contain members such as fields or methods and i have no idea whats wrong.
Heres the code:
using System.Collections.Generic;
using UnityEngine;
public class SecondaryMenuControl : MonoBehaviour
{
public bool isSurvival;
public bool isSelectLevel;
public bool isGoBack;
}
// Start is called before the first frame update
void Start()
{
void OnMouseUp(){
if(isSurvival)
{
SceneManager.LoadScene(MainScene);
}
if (isSurvival)
{
SceneManager.LoadScene(SelectLevelMenu);
}
if (isGoBack)
{
SceneManager.LoadScene(IntroMenu);
}
}
// Update is called once per frame
void Update()
{
}
}
I hope somebody can help me.
Regards,
Keno
Remove the stray bracket;
public class SecondaryMenuControl : MonoBehaviour
{
public bool isSurvival;
public bool isSelectLevel;
public bool isGoBack;
} // remove this one!
// rest of the file
The error basically saids 'You defined some properties/fields/methods in a namespace' which you of course can't do. They all belong inside a class.
edit: this should be your output:
public class SecondaryMenuControl : MonoBehaviour
{
public bool isSurvival;
public bool isSelectLevel;
public bool isGoBack;
private void OnMouseUp(){
if(isSurvival)
{
SceneManager.LoadScene(MainScene);
}
if (isSurvival)
{
SceneManager.LoadScene(SelectLevelMenu);
}
if (isGoBack)
{
SceneManager.LoadScene(IntroMenu);
}
} // end of OnMouseUp
} // end of class
make sure you match an opening bracket with a closing one.

Where to initialize a static variable in Unity?

I'm using a static variable in a class but the problem is that it needs another value from another class for it's initial value(See the code snippet). I thought initializing it in Start function. But (correct me if I'm wrong) that means it will be reinitialized for every instance of the object which is something redundant since I want this variable to be initialized for just once at the creation of very first Unit which has UnitManager on.
So my question is at what place would be considered as a good practice to initialize this variable?
Thanks!
Code:
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
private void Start()
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
}
else
{
distanceToStop = 0.1f;
}
}
}
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
static bool distanceSet = false;
private void Start()
{
// If the distance is not set
if(!this.distanceSet)
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
} else {
distanceToStop = 0.1f;
}
this.distanceSet = true;
}
}
The "distanceSet" bool will be shared between the instances so you will only set the distance on the first one :D
Maybe consider calling UnitManager with an Init(); with the WorldCoordController value it needs.
You can create a custom class that will have a static reference to its self and be initialized only once (the first time it gets called).
Example:
public class ExampleClass
{
//Static Functionality
private static ExampleClass _inst;
public static ExampleClass Instance
{
get
{
if (_inst is null)
{
_inst = new ExampleClass();
_inst.Init();
}
return _inst;
}
}
//Class Values
public static int MyValue;
public int Value1;
//private Constructor
private ExampleClass()
{
}
//initialize values here
private void Init()
{
}
}
And then you can access the values like this:
//This will return the Value1 int
ExampleClass.Instance.Value1
or
//This will return the static MyValue int
ExampleClass.MyValue
From what you are asking, you can use only the Value1 from the above example and have it initialized only once in the init. If you want the value to be accessible only for read you can set it as property with "private set" operator.
The advantage of this is you dont need Start or Monobehaviour so it can work anywhere without having it in gameobjects.
Hope this helps, and happy coding!

OnMouseDown() null reference exception

public class TowerNode : MonoBehaviour {
public bool IsShopOpen=false;
//Z position
public Vector3 positionOffSet;
//colors
public Color hoverColor;
private Color startColor;
//GameObjects
public GameObject turret;
//shop
public Shop shop;
//Build Manager
BuildManager buildManager;
void Start()
{
rend=GetComponent<Renderer>();
startColor = rend.material.color;
buildManager = BuildManager.instance;
shop = GetComponent<Shop>();
}
//When mouse is on the turret node
public void OnMouseDown()
{
Debug.Log("Mouse is Down");
bool IsShopOpen = true;
if (IsShopOpen == true)
{
Debug.Log("shop is open");
shop.onEnable();
}
if (EventSystem.current.IsPointerOverGameObject())
{
return;
}
if (!buildManager.CanBuild)
{
return;
}
if (turret != null)
{
Debug.Log("Cant Build Here!!!");
return;
}
buildManager.BuildTurretOn(this);
}
the other script of the shop is this:
public class Shop : MonoBehaviour
{
public TurretBlueprint Archery;
public TurretBlueprint Treb;
public TurretBlueprint Workamp;
public TurretBlueprint Barracks;
public Button Archeryy;
public Button Trebb;
public Button WorkCampp;
public Button Barrackss;
BuildManager buildManager;
void Start()
{
buildManager = BuildManager.instance;
disableAllButtons();
//OnEnable();
}
public void SelectArchery()
{
buildManager.SelectTurretToBuild(Archery);
Debug.Log("archery!!!!");
}
public void SelectTreb()
{
buildManager.SelectTurretToBuild(Treb);
Debug.Log("Treb!!!!");
}
public void SelectWorkamp()
{
buildManager.SelectTurretToBuild(Workamp);
Debug.Log("Work Camp!!!!");
}
public void SelectBarracks()
{
buildManager.SelectTurretToBuild(Barracks);
Debug.Log("Barracks!!!!");
}
public void onEnable()
{
Archeryy.gameObject.SetActive(true);
Trebb.gameObject.SetActive(true);
WorkCampp.gameObject.SetActive(true);
Barrackss.gameObject.SetActive(true);
}
public void disableAllButtons()
{
Archeryy.gameObject.SetActive(false);
Trebb.gameObject.SetActive(false);
WorkCampp.gameObject.SetActive(false);
Barrackss.gameObject.SetActive(false);
}
}
I need when i click on the game object that the shop will open the sop got few buttons under it, but it gives me:
"NullReferenceException: Object reference not set to an instance of an object
TowerNode.OnMouseDown () (at Assets/Scripts/TowerNode.cs:51)
UnityEngine.SendMouseEvents:DoSendMouseEvents(Int32)"
and I don't understand why.
The error you are getting implies that an object in the OnMouseDown function is null when executed:
NullReferenceException: Object reference not set to an instance of an object TowerNode.OnMouseDown () (at Assets/Scripts/TowerNode.cs:51)
You should look at ine 51 of TowerNode.cs and ascertain what can be null on that line. Could shop or buildManager be null? Perhaps this event is firing before you have initialised your TowerNode object.
It seems you are trying to access a component (Shop) from a completely unrelated GameObject. If you want all of your TowerNode objects to reference the Shop then you could use GameObject.Find. This isn't really recommended though; it seems like there is a better way to link these two objects but I am unsure of your use case.

Categories