I have to access variable ammoMagazine from this class
public class Pistol : MonoBehaviour {
public int ammoMagazine = 7;
}
then i tried this code :
public class AmmoCounter : MonoBehaviour {
public int ammo;
private Pistol _pistol;
void Start () {
_pistol = GetComponentInChildren<Pistol>();
}
void Update () {
ammo = _pistol.ammoMagazine;
guiText.text = "Pistol: " + ammo + "/7";
}
}
Why there's NullReferenceException: Object reference not set to an instance of an object ?
Thanks, im new in C#
There is probably no value assigned to the _pistol field, so either you didn't call Start before you called Update, or GetComponentInChildren<Pistol>() returned null.
public class AmmoCounter : MonoBehaviour {
public int ammo;
private Pistol _pistol = GetComponentInChildren<Pistol>();
void Update () {
ammo = _pistol.ammoMagazine;
guiText.text = "Pistol: " + ammo + "/7";
}
}
Initialize the _pistol-variable before calling the update-function (Check if the GetComponentInChildren()-function returns null)
Note that it's NullReferenceException.
I think for some reason Update() is being called before Start().
I know this has already been answered..but I think there will be some roadblocks ahead for you if you code everything with private variables like the accepted answer. Usually to get a reference in Unity you need to have an object in the scene with the desired attached script. So first you would re-write the script:
public class AmmoCounter : MonoBehaviour {
public int ammo;
public GameObject _pistol;
void Start( ){
ammo = _pistol.GetComponent< Pistol >( );
}
void Update( ) {
guiText.text = "Pistol: " + ammo + "/7";
}
}
In the scene you want an object with the Pistol script attached, then in the editor ( inspector ) you should drag that object into the _Pistol slot. There are several reasons for doing this but two important ones are 1) You're shortening the code and referencing the script once ( the current answer is duplicating the reference ) and 2) Using GetComponentInChildren is inefficient; Unity searches through every game object underneath a parent to get your component. Thus, a direct object reference is better. Also using this type of object reference will save you several headaches in the future, most notably easy reference and making it easier to follow your own code in the future ( you can see the reference in the editor rather than looking through code -- trust me magical references can be a nightmare ).
If you don't want to reference through objects read up on the static type in C#, this allows you to reference items without using GameObjects. However, static types are finicky creatures, so be careful and know what you're doing before using them
edit: grammar
Related
So I wanted to make a counter that counts how many times the player hitted a "player_grower". But the problem I'm getting that it isn't counting futher then 1.
public class Collision_Player_grower : MonoBehaviour
{
public GameObject Player_grower;
public float times_player_grower;
void Start()
{
times_player_grower = 0;
}
void OnTriggerEnter(Collider collision)
{
if (collision.gameObject.tag == "Player")
{
print("we hit an playergrower");
Destroy(Player_grower);
times_player_grower = times_player_grower + 1;
print("times hit =" + times_player_grower);
}
}
void Update ()
{
}
}
The result this gives me is that it prints: "times hit = 1", even when I hit two or more of those objects. I believe this happens because it doesn't save the value but I'm not sure.
How can I fix this?
Each of your Collision_Player_grower instances have their own respective field
public float times_player_grower;
so this is an individual counter for each of them.
You probably would make it static so it is "shared" among them all
// I also think an int would be probably more appropriate for your use case
public static int times_player_grower;
Or as an alternative - and cleaner in my eyes - would be to rather let the player itself track the collisions and count.
You either keep your current code but let the player store according value:
// Script on your player object
public class PlayerHitCountController : MonoBehaviour
{
public int times_player_grower;
}
and then do
public class Collision_Player_grower : MonoBehaviour
{
public GameObject Player_grower;
void OnTriggerEnter(Collider collision)
{
if (collision.TryGetComponent<PlayerHitCountController>(out var hitCounter))
{
print("we hit an playergrower");
Destroy(Player_grower);
hitCounter.times_player_grower += 1;
print("times hit =" + hitCounter.times_player_grower);
}
}
}
Or and that would be my actual approach go the total other way round.
// If Player_grower is the same as the object this script is attached to than probably you wouldn't need it
public class Collision_Player_grower : MonoBehaviour
{
// does nothing but holding the information
public GameObject Player_grower;
}
// Script on your player object
public class GrowCollisionChecker : MonoBehaviour
{
public int times_player_grower;
void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent<Collision_Player_grower>(out var grower))
{
print("we hit an playergrower");
Destroy(grower.Player_grower);
// Or if Player_grower is the same object as this is attached to anyway
//Destroy(grower.gameObject);
times_player_grower += 1;
print("times hit =" + times_player_grower);
}
}
}
This way your player has the full control over the counter and can e.g. also reset it where needed.
Most probably you are trying to count the triggers per Player_grower. What is happening is the following: let's say you have 5 Player_grower objects. 1 of them gets triggered. It is calling the OnTriggerEnter() on that particular object setting times_player_grower to 1 and then immediately destroying the object. Even though the Destroy statement is before the incremente and print statments Unity still executes everyting before destroying the object (calling Destroy only marks the object to get destroyed at the end of the frame, until then everything runs). So this is why it always prints 1.
Now to answer your problem - times_player_grower variable exists on every grower but you need to have it declared only 1 time, like a "global" variable instead of "local" for every object so that it will keep counting and not get destroyed together with the GameObject. Now there is 2 ways of achieving this:
The first one is to make the variable static like this: public static float times_player_grower; what static is doing here is declaring a shared variable across all instances of the Collision_Player_grower. All the objects of class Collision_Player_grower will have a common variable called times_player_grower. This way the variable does not get destroyed when the object gets destroyed and you can do your count there. You MUST research static variables if you don't know what they are.
Second one is keeping a count in a separate GameObject that does not get destroyed duing the trigger event.
Good luck
This problem is on Unity, but I think I am just doing the c# side wrong.
EDIT
It looks like by doing the code and storing a child Class B of parent Class A, and by saying is a Class A type, by modifing my variable of type Class A containing Class B I modify some sort of hybrid Class A/B that doesn't represent my real Class B Script
What I do is, having multiple script on different prefabs. Each of those script represent an item and all have has parent Usable which is a class that I actually use like an interface, but that will in the future get some stuff.
The full WeaponLaser and Usable script is below
When the player go over a drop, I instantiate the gameObject containing the script like this (using prefab)
GameObject Item = Instantiate(droppedItem, transform.position, Quaternion.identity);
Item.transform.parent = transform;
usableItem = droppedItem.GetComponent<Usable>();
usableItem.OnUsed += ReleaseItem;
and Use the item like this
if (usableItem != null)
usableItem.Use(firePoint.position);
The thing is, it looks like the script I call when I do Use() is another version.
I mean, If I set int fireCurrentShoot = 10; on top of the script WeaponLaser and then trought code in the Start for exemple I do fireCurrentShoot = 2;
It will work on the inside the script WeaponLaser, but when I call it using the above code
if (usableItem != null)
usableItem.Use(firePoint.position);
It will show fireCurrentShoot = 10 so without the modification
END EDIT
Hello,
I have a problem with heritage I don't understand, I cleaned all my class, and still I can't find why.
I have a class A :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Usable : MonoBehaviour
{
protected virtual void Start()
{
}
protected virtual void Update()
{
}
public virtual void Use(Vector3 pos)
{
}
protected virtual void Used()
{
}
}
and a class B
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponLaser : Usable
{
const int SHOOT_AVAILABLE = 5;
const float FIRE_COOLDOWN = 1;
float fireCurrentCooldown = 0.0f;
int fireCurrentShoot = 0;
protected override void Start()
{
base.Start();
Debug.Log("start");
fireCurrentShoot = SHOOT_AVAILABLE;
Debug.Log("fireCurrentShoot" + fireCurrentShoot);
}
protected override void Update()
{
Debug.Log(fireCurrentShoot); // value is = 5
base.Update();
}
public override void Use(Vector3 shootPosition)
{
Debug.Log(fireCurrentShoot);// value is = 0
base.Use(shootPosition);
base.Used();
}
void FireCooldown()
{
}
}
when I call Use, my Debug.Log of booth value give 0... but I am expecting to have fireCurrentShoot = 5
I call it like this *:
usableItem = droppedItem.GetComponent<Usable>();
usableItem.Use(firePoint.position);
why he is equal to 0?
Your inheritance seems fine, so the problem might be in the way you use these objects in Unity. This makes it a bit more difficult to be sure what the solution is, but here is what you could try:
Be sure that Start is called: I think it is the case for you since
you say you see a debug print, but remember that Start is not called
on objects that are deactivated in the Editor, so some values that
you set in start will not be initialized.
Name your objects in unity editor with unique names and add the name in the debug
Debug.Log(fireCurrentShoot + ", " + name);
This should help you sure you see the values for the object that interests you
You can also replace
int fireCurrentShoot = 0;
by a property:
int _fireCurrentShoot = 0;
private int fireCurrentShoot
{
get{ return _fireCurrentShoot;}
set{ _fireCurrentShoot = value; Debug.log("fireCurrentShot set to " + _fireCurrentShoot);}
}
this will allow you to see a message when the value is modified. You
can also set a debug point on the setter to see the callstack
EDIT:
I think I got it: you don't register to the instanciated object, but to your prefab
replace
usableItem = droppedItem.GetComponent<Usable>();
by
usableItem = Item.GetComponent<Usable>();
I'm making a game where i want to change which objects my player can collide with by changing the layer mask, but every time I try to change the variable in a different script it throws this error
Error CS0120: An object reference is required to access non-static
member `RaycastController.jumpableCollisionMask'
The code for where i create the variable:
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (BoxCollider2D))]
public class RaycastController : MonoBehaviour {
public LayerMask collisionMask;
public LayerMask jumpableCollisionMask;
The code for where i set the variable
using UnityEngine;
using System.Collections;
public class PlayerChanger : MonoBehaviour {
public float numberOfPlayersPerLevel;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.E)){
RaycastController.jumpableCollisionMask = 11;
}
}
}
I have tried using a setter but i couldn't get it to work. Thanks in advance and have a nice day =).
jumpableCollisionMask = 11
not
RaycastController.jumpableCollisionMask = 11
Note that you likely have another problem:
You set layer masks (which are just int) like this:
int layerMaskDogs = 1 << LayerMask.NameToLayer("Dogs");
int layerMaskFruits = 1 << LayerMask.NameToLayer("Fruits");
ok?
Never use "= 11" or any number or other value. In Unity it is now only possible to use the form 1<<LayerMask.NameToLayer("Blah")
Finally note you are using public to declare the LayerMask. That can be a bit confusing -- you only do that if you want to set it in the editor. If that's what you want to do, fine. But if you don't need to do that, just use private.
Finally note that you have this is TWO DIFFERENT SCRIPTS!!! This is the most basic problem in Unity. Fortunately it is easily solved:
-- add a public variable to your SECOND script
public class PlayerChanger : MonoBehaviour {
public RaycastController myRC;
-- IN THE INSPECTOR take your "RaycastController" and drag it to that public variable
-- Now use it like this
public class PlayerChanger : MonoBehaviour {
public RaycastController myRC;
...
...
...
//whenever you need to use it...
myRC.jumpableCollisionMask = 11;
Please read the literally 1000s of QA on this! Example, How to access a variable from another script in another gameobject through GetComponent?
I have the object that have the script component.
public class TeleportReference : MonoBehaviour {
private GameObject reference;
void Start () {
reference = null;
}
public void SetReference(GameObject other){
reference = other;
}
public GameObject GetReference(){
return reference;
}
Now if I search for an object and test the script variables
GameObject test = GameObject.FindGameObjectWithTag("Water");
print(test);
print(test.GetComponent<TeleportReference>());
print(test.GetComponent<TeleportReference>().GetReference());
it works just fine and GetReference() return the variable I stored.
But now if I use it whithin OnTriggerEnter2D
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Water")
{
print(other);
print(other.gameObject);
print(other.GetComponent<TeleportReference>());
print(other.GetComponent<TeleportReference>().GetReference());
}
}
GetReference() return null (or other variable that I used during Start() of TeleportReference class).
All other testing outputs remain the same.
Could anyone give a hint why this could happen? Does that mean that GetComponent created new instance of TeleportReference in second case?
GetComponent did not create a new instance of TeleportReference in second case. I have similar code in one of my projects and I haven't had any problems. So in this case I would look to see if the problem is somewhere else. Are you sure it's the same "Water" object? Do you have multiple objects with "Water" tag? Are you colliding before reference is assigned? There could be a myriad of things going on. Just test to narrow it down.
For example try performing an action on the other.gameObject object to verify it's the right object, like deactivating it. Also try using other.gameObject.GetComponent (not sure if this makes a difference).
Found the issue. It was in the order of assigning variables. That is - changes were made apperantly before Start() function was called. Thus at some point of the code the stored value was overritten back to null.
This works fine:
public class TeleportReference : MonoBehaviour {
private GameObject reference;
void Awake () {
reference = null;
}
public void SetReference(GameObject other){
reference = other;
}
public GameObject GetReference(){
return reference;
}
Thanks everyone for comments, that really helped me in debugging.
I am trying to get data from an int variable in Unity using C# code.
Below is the C# code I am using to get the int.
using UnityEngine;
using System.Collections;
public class endGameMessage : MonoBehaviour {
public static int score2;
void Start () {
GameObject thePlayer = GameObject.FindWithTag("Player");
gameScript game = thePlayer.GetComponent<gameScript>();
score2 = game.score;
}
// Update is called once per frame
void Update () {
Debug.Log (score2);
}
}
Below is the code from the other script I am trying to pull the data from.
using UnityEngine;
using System.Collections;
public class gameScript : MonoBehaviour {
//score
public int score = 0;
void OnTriggerEnter(Collider other) {
if(other.gameObject.tag =="hammer"){
GameObject.FindGameObjectWithTag("pickUpMessage").guiText.text = ("Picked Up A Hammer");
Destroy(other.gameObject);
Debug.Log("collision detected hammer");
audio.PlayOneShot(gotHit);
score = score+10;
}
}
}
I can get the the int value to come across to the other script but its always 0 even if the int was meant to be 10.
My question is how would i keep the value across the scripts? Any help is appreciated.
try this
public static int score2
{
get
{
return GameObject.FindWithTag("Player").GetComponent<gameScript>().score;
}
}
You have a lot of possibilities.
The first one is to set your Score as a static argument for you gameScript.
So you can access it anywhere just like that :
int myScore = gameScript.Score ;
And the declaration should be :
public static int score;
The second possibilities is far better if you want to save a lot of differents values from differents script.
In this case, you need to define a gameContext singleton.
If you don't know what is this, you should take a look at singleton in C# :
[https://msdn.microsoft.com/en-us/library/ff650316.aspx]
Singleton will allow you to have a single instance of your gameContext.
In your case, your singleton will have a Score attribute.
And you will be able to get the value from any scene and any scripts.
This is the best way so far.
score2 is read once at start and then never again. int is an integral type in C# and thus passed by value i.e. it receives a copy. There several ways to solve this problem.
The easiest solution is to access the gameScript.score directly - it provides read/write access to everyone anyway. To encapsulate it you may choose to define a property.
A better way could be to define a new class GameStatus which holds all relevant things. This can be implemented as singleton for example.