For some reason I get an error which looks like this:
UnassignedReferenceException: The variable LevelComplete of NPad1 has not been assigned.
and this is my code:
public class NPad1 : MonoBehaviour {
public Sprite img1 , img2;
public Rigidbody2D LevelComplete;
void Start () {
gameObject.GetComponent<SpriteRenderer> ().sprite = img1;
}
// Update is called once per frame
void OnTriggerEnter2D(Collider2D other) {
gameObject.GetComponent<SpriteRenderer> ().sprite = img2;
Instantiate (LevelComplete);
}
What have I done wrong?
Referring to this;
Clones the object original and returns the clone.
Which means you will have to instantiate LevelComplete before calling Instantiate(), which returns a clone of the existing object. You probably haven't set the instance in the Unity inspector. For more info, visit this guide on setting public variables.
Related
So I am able to Instantiate new objects at runtime and they spawn in with the correct scripts attached however the scripts do now spawn in with the variables fixed in their slots.
I need a way to spawn prefabs with the scripts attached AND the variable slots in the script are all filled in.
Deploy capsule script (linked to main camera)
public class deployCapsule : MonoBehaviour
{
public GameObject CapsulePrefab;
public Path path;
public float respawnTime = 1.0f;
void Start()
{
StartCoroutine(capsuleWave());
}
private void spawnCap()
{
GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.transform.position = new Vector2(1.0f, 1.0f);
path.followers.Add(a);
Debug.Log("1");
}
IEnumerator capsuleWave()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
spawnCap();
}
}
}
Path Follower script
public class PathFollower : MonoBehaviour
{
public float movementSpeed;
//private float pathProgress = 0;
public GameObject objectToSpawn;
public Transform[] positionPoint;
[Range(0,1)]
public float value;
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
void Update()
{
movementSpeed = 10f;
if (value < 1)
{
value += Time.deltaTime / movementSpeed;
}
iTween.PutOnPath(objectToSpawn, positionPoint, value);
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
I KNOW THIS IS NOT TECHNICALLY POSSIBLE.
But I need a method to get this done one way or another.
I am quite new to unity and would appreciate any help given.
Thank you in advance.
in deployCapsule, store a reference to the array of points
public Transform[] positionPoint;
assign the values in the inspector.
and then once you've instantiated the prefab, give it the array like this
//this is in the SpawnCap function
//GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.GetComponent<PathFollower>().positionPoint = positionPoint;
//rest of your function
alternatively, set the values in the Awake() or Start() function of the newly instantiated Capsule by getting a reference to a class that has the data.
void Start()
{
positionPoint = GameObject.Find("Spawner").GetComponent<deployCapsule>().positionPoint;
}
After instantiating your capsule prefab and assigning a reference to it named a (I suggest you change this naming to something more logical)
GameObject a = Instantiate(CapsulePrefab);
Assuming your prefab already has the PathFollower component attached, you could use the GameObject.GetComponent<T> method to access it.
var pathFollowerComponent = a.GetComponent<PathFollower>();
After which, you could populate the positionPoint[] Transform's array (assuming that's what you're after) with references to the "Points" GameObjects located in the hierarchy and the scene.
It's up to you how to go about this:
You could create a tag on each point, use GameObject.FindGameObjectsWithTag("Point");
Obtain the children from the "PathFollower" GameObject and add its child transforms to your array
Create a singleton instance or a "GameManager" class which stores the points located in a scene
If you create new points dynamically, create a listener and invoke events to add the new points to the array whenever they're instantiated.
Note that the mentioned above may not return the points in the order you placed them, so you may need to sort them! In general, there are many other ways which you can find by searching the forums, or on Google!
The issue here is that your prefab is in project while the path nodes are in scene. You have two approaches to fix that.
First, your path nodes are under a parent object, that parent holds a container script:
public class PathNodes : MonoBehaviour
{
[SerializeField] private Transform m_nodes;
public Transform [] Nodes => m_nodes;
}
Either you use the singleton pattern (yes it is fine when used properly) or have the newly created object use FindObjectOfType then you can access the nodes.
The second solution is to have the prefab of your object to create in the scene as an inactive object. Being in the scene, you can then drag and drop all you need from the scene into it. The prefab is dragged in place of the original project prefab (CapsulePrefab) and when creating a clone of it, you just need to set it active.
I've been using Unity to create a simple 2D game but the problem is that even when the game object "player" gets destroyed, the gameobject "isDead" (text) doesn't appear.
This is my script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class youDied_Text : MonoBehaviour
{
private Transform player;
private Text isDead;
// public static bool isDead;
// Start is called before the first frame update
private void Start() {
isDead = GetComponent<Text>();
}
void checkForDeath()
{
if (player==false)
{
isDead.gameObject.SetActive(true);
}
else
{
isDead.gameObject.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
player = GameObject.FindWithTag("Player").transform;
checkForDeath();
}
}
This script is attached in the text which I need to display in UI element.
As was noted currently you would get a NullReferenceException which is definitely not what you want.
There is absolutely no need / redundancy going through Transform at all actually. Simply store the GameObject reference instead
You are currently setting the object to inactive which has the Text attached ... which is the same object your component is attached to as well!
=> As soon as you end up in the second case once you set it to inactive => from now on Update is never called anymore!
In general as it sounds like this should only happen once anyway I would use a more event driven approach and have a component on your player like e.g.
public class Player : MonoBehaviour
{
public UnityEvent onDied;
private void OnDestroy ()
{
onDied.Invoke();
}
}
And then simply attach a listener/callback to that event once without poll checking states. You can do this either via the Inspector directly (just like in e.g. Button.onClick) or via code like e.g.
public class youDied_Text : MonoBehaviour
{
// Already reference things via the Inspector if possible!
[SerializeField] private GameObject player;
[SerializeField] private Text isDead;
private void Awake()
{
if(!isDead) isDead = GetComponent<Text>();
isDead.gameObject.SetActive(false);
// If you want to rather set it via the Inspector remove all the rest here
//if(!player) player = GameObject.FindWithTag("Player"). GetComponent<Player>();
// or even simpler
if(!player) player = FindObjectOfType<Player>();
player.onDied.AddListener(OnPlayerDied);
}
// If you want to rather set it via the Inspector make this public
private void OnPlayerDied()
{
isDead.gameObject.SetActive(true);
}
}
This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 2 years ago.
I keep getting this error, but I don't even know what is or isn't static in this context? I have tried solutions like setting instances and checking capitalization but I just get the same error. I want the shop script to change the monney value, which is written into debug until I set up the right U.I.
The Zoney script:
using UnityEngine;
using UnityEngine.UI;
public class Zoney : MonoBehaviour
{
public Text Money;
public int Monney;
private string Mony;
// Start is called before the first frame update
void Start()
{
Money = GetComponent<Text>();
}
public void setMonney(int Change)
{
Monney = Change;
}
// Update is called once per frame
void Update()
{
Mony = Monney.ToString();
Money.text = Mony;
}
}
The Shop script:
using UnityEngine;
public class Shop : MonoBehaviour
{
public int Change;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Change += 1;
Zoney.setMonney(Change);
Debug.Log(Change);
}
}
Because you're working with Unity, you need to follow the requirements of the engine.
In a case like this, where you need an instance of a component (MonoBehaviour), you really want to be referencing a Unity created instance, instead of creating a new one with the new keyword. Creating an instance of a component using the new keyword is going to leave you with an instance of the class that's not associated with any Unity GameObject.
The far more reliant way to get the component you want to reference, is to use the Inspector window, and drag into the object field, the right component on the desired object. In this case, I am going to assume you'll want to drag a Scene object (in your hierarchy) into the object field slot.
You would do that by first defining a variable. This can generally be done in one of two ways:
public Zoney zoney;
[SerializeField] private Zoney zoney;
In this example, once you've assigned your reference, use the variable zoney, instead of the class name Zoney. Note that your variable name could be anything else you feel is appropriate, e.g. _zoney, or myZoney.
Your new Shop script could then look like this:
public class Shop : MonoBehaviour
{
public int Change;
public Zoney zoney;
void Update()
{
Change += 1;
zoney.setMonney(Change);
Debug.Log(Change);
}
}
Zoney is a class, you need to create an instance of it first before using it.
Instantiate a class that derives from MonoBehaviour
Also very important, you need to update your shop object so it has the Zoney instance as a member object otherwise your updates to money wont be kept:
i.e.
public class Shop : MonoBehaviour
{
private Zoney;
public int Change;
// Start is called before the first frame update
void Start()
{
_HiddenZoney = gameObject.Addcomponent<Zoney>();
}
// Update is called once per frame
void Update()
{
Change += 1;
_HiddenZoney.setMoney(Change);
Debug.Log(Change);
}
}
Thanks #derHugo for the alert!
You need to create a object from Zoney class to access it's non static memebers. Try below:
public class Shop : MonoBehaviour
{
public int Change;
public Zoney myZoney; // Need to create the object
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Change += 1;
myZoney.setMonney(Change); // Access members using created object
Debug.Log(Change);
}
}
In Unity C# script I have a singleton game controller object in which the game variables are stored but I am getting odd behaviour when accessing them in a member function. It prints the initialized value, not the current one. In the update function however it prints the correct value each frame. I summarized the class below. The controller class has a static reference to itself. If you need to know additional details you can ask. I am new to C# and Unity so I might be lacking some obvious answer.
Thanks
public class controller : MonoBehaviour {
public int[] star = new int[64];
void Start(){ /* calls another function to set 0 for each star index */ }
void Update(){ // during gameplay star[0] gets a value of 1
print(star[0]); // prints correct value which is 1
}
public void checkValue(){
print(star[0]); // prints 0 incorrectly which should be 1
}
}
I've set up a little example. I created a button and an empty gameobject GameController. I added this code to the GameController:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public static GameController instance;
[System.NonSerialized] public int[] star = new int[64];
private void Awake()
{
if(instance == null)
instance = this;
else if(instance != this)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
private void Start()
{
StartCoroutine(SetAllTo(1));
}
// for simulating some changes during the game
private IEnumerator SetAllTo(int value)
{
yield return new WaitForSeconds(2.0f);
for(int i = 0; i < star.Length; i++)
star[i] = value;
Debug.Log("Setting done");
}
public void PrintFirst()
{
Debug.Log(star[0]);
}
}
Now I added an OnClick event to the button, dragged the GameController gameobject into the slot and picked PrintFirst.
I start the game and click the button once before the Coroutine log and once after and the console gives the following:
0
Setting Done
1
Edit:
The gameobject for the OnClick event must be in the scene, it can't be a prefab in the assets folder.
It seems that's the call to the start function may also occurs in your external calls before the call for ckeckValue
Try debugging by putting breakpoint in each of these functions and you can understand what is going on.
The start function runs once in the beginning of the game and not again.
For that you have pattern - Singleton
The second thing why to call external function to initialize class member? do it in your default contractor.
- C# default constractor already initialize 0 in int[].
if you still what to run Start from other scope in your code make it public (c# makes variable/methods as private by default)
I want this class to render a grid each time it is instantiated, but I am getting the error, error
CS0120: An object reference is required to access non-static member
`UnityEngine.GameObject.GetComponent(System.Type)'
So I instantiate an object of Renderer called Rend and set that equal to the non-static member but I am still getting the error? Any help would be greatly appreciated as I have researched for several hours and still can't figure this out.
using UnityEngine;
using System.Collections;
public class SetGrid : MonoBehaviour {
public int x = 1;
public int y = 1;
void Start()
{
Renderer Rend = GameObject.GetComponent<Renderer>().material.mainTextureScale = new Vector2 (x, y);
}
}
I am assuming this script is part of your grid game object which also has a component of type Renderer.
The correct syntax to scale the texture of the Renderer is following:
public class SetGrid : MonoBehaviour {
public int x = 1;
public int y = 1;
void Start()
{
// Get a reference to the Renderer component of the game object.
Renderer rend = GetComponent<Renderer>();
// Scale the texture.
rend.material.mainTextureScale = new Vector2 (x, y);
}
}
The error message was thrown because you tried to call GetComponent on a type of GameObject and not an instance of GameObject. The script itself is already in the context of a GameObject meaning that you can just access a component with GetComponent from a non-static method.
The problem is not with the Rend object, it's caused by the fact that the GetComponent method is non-static. That means you need to instantiate a GameObject object and use that one to call GetComponent.
Change GameObject.GetComponent to gameObject.GetComponent, so that you're referencing the gameObject that this MonoBehaviour script belongs to.
Or you can even not use gameObject.GetComponent and just use GetComponent by itself.
See the MonoBehaviour inherited members for details.