GameObject in SerializedField - OverRide - Apply All: Prefab Doesn't Update - c#

I added a script to my prefab. Then I put my prefab into my scene and drag/dropped the GameObjects into the appropriate fields within the inspector. I then clicked OverRides>>Apply All. (Which is common and I do this all of the time)
However, the game object I'm using for the Spawn Zone when the Game Object will be Instantiated will not apply to my Prefab. (The Prefab in the scene does have the Empty Game Object attached but not the main Prefab in the Project panel)
I'm using the same method that I use for Instantiating bullets but for some unknown reason the Project view prefab will say "None(GameObject)"
Here's the code:
[SerializeField]
private GameObject boss;
[SerializeField]
private float bossSpd;
[SerializeField]
private GameObject bossSpawnZone1; // This won't apply to my prefab in Project panel
private void Update()
{
if(startBoss == true)//StartBoss occurs when a GameObject is touched by player on another script. Just OnTriggerEnter2D set var to true
{
GetTheBoss();
}
}
void GetTheBoss()
{
Instantiate(boss, bossSpawnZone1.transform.position, Quaternion.identity);
startBoss = false;
}
I would include pics but I don't know how to upload them in here. Never used the IMG URL before. But trust me, I inserted the empty gameobject(SpawnZone) into the field. I also used the override to apply all. Yet the spawn zone field remains empty.
What I've tried:
1) Removing the script and re-adding it then filling the fields again.
2) Made the spawn zone public static and tried using GameObject.Find("PirateSpawnZone") in another script pertaining to the player.
3) Changing the variable name and saving the script.
4) Restarting Unity / Restarted computer completely then open Unity back up.

You can not have Scene references in a prefab. It is not possible. It only works for GameObject reference that are themselves a prefab living in the asset or references within one and the same prefab hierarchy.
However some workarounds exist
dependency injection
using dependency injection (e.g. Zenject)
ScriptableObject references
a ScriptableObject for setting the reference on scene start and referencing the ScriptableObject instead.
[CreateAssetMenu(filename = "new GameObjectReference", menuName = "ScriptableObject/GameObjectReference")]
public GameObjectReference : ScriptableObject
{
public GameObject value;
}
Create an Asset by right click in the Assets → Create → ScriptableObject → GameObjectReference
Then change your script field to
[SerializeField] private GameObjectReference bossSpawnZone1;
and everywhere where you use it use bossSpawnZone1.value instead.
This works now since the ScriptableObject instance itself lives in the Assets.
Then finally you need the setter component on the bossSpawnZone1 GameObject like
public GameObjectReferenceSetter : MonoBehaviour
{
[SerializeField] private GameObject scriptableAsset;
private void Awake()
{
scriptableAsset.value = gameObject;
}
}
Singleton pattern
having only the setter and making a public static reference (only works if there is only exactly one of those reference in the entire scene/game
public class SpawnZoneReference : MonoBehaviour
{
public static GameObject instance;
private void Awake ()
{
instance = gameObject;
}
}
And in your script instead use
Instantiate(boss, SpawnZoneReference.instance.transform.position, Quaternion.identity);
Or very similar using only a certain type like
public class BossSpawnZone : MonoBehaviour { }
On the GameObject and in your script do
bossSpawnZone1 = FindObjectOfType<BossSpawnZone>();

Related

Can someone explain how i can just call for ridgedbody2d with this code?

so I have a script calling from another class, I'm wondering how I can write this to only destroy the ridgedbody 2d. I know that it will keep the sprite in scene which is what I'm looking for.
private void OnTriggerEnter2D(Collider2D other)
{
DamageDealer damageDealer = other.gameObject.GetComponent<DamageDealer>();
health -= damageDealer.GetDamage();
}
If you pass in a Component reference to Destroy it will only destroy the according component but keep the rest of the GameObject untouched
The object obj will be destroyed now or if a time is specified t seconds from now. If obj is a Component it will remove the component from the GameObject and destroy it. If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject.
Destroy(damageDealer.GetComponnet<Rigidbody2D>());
If you do this quite often it might be better to store this reference already in Awake of the DamageDealer component and later pass it on like
public class DamageDealer : MonoBehaviour
{
// if possible already reference this via the Inspector
[SerializeField] private Rigidbody2D rigidbody;
// This is a read-only property returning the value of rigidbody
public Rigidbody2D Rigidbody => rigidbody;
private void Awake()
{
if(!rigidbody) rigidbody = GetComponnet<Rigidbody2D>();
...
}
...
}
then later you can simply do
Destroy(damageDealer.Rigidbody);

How to fix "the object of type 'GameObject' has been destroyed, but you are still trying to access it" error in Unity?

I'm creating a 2.5D fighting game in Unity with C#. Currently, I'm trying to make a bumper appear around the player and disappear after a set amount of time. I've managed to make the bumper appear and disappear once, but after that, when I try to make the bumper appear again, Unity has an error for me: "The object of type 'GameObject' has been destroyed but you are still trying to access it."
I've tried using the "instantiate" and "destroy" commands, following a tutorial by "Brackeys" on 2D shooting. After also following some questions on forums about the same issue, I've altered my code again, but the problem persists.
The firePoint is an empty object, from where the BumperPrefab is instantiated.
using UnityEngine;
public class weapon: MonoBehaviour
{
public Transform firePoint;
public GameObject BumperPrefab;
public float lifetime = 0.2f;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
attack();
}
}
void attack()
{
BumperPrefab = (GameObject) Instantiate(BumperPrefab, firePoint.position, firePoint.rotation);
Destroy(BumperPrefab, lifetime);
}
}
I expect the GameObject "BumperPrefab" to appear, stick around for 0.2 seconds and disappear. I should be able to repeat that as many times as I want, but what actually happens is that I can do this only once and then the error "The object of type 'GameObject' has been destroyed but you are still trying to access it" shows up and I can't make the BumperPrefab appear again.
Any help is much appreciated!
using UnityEngine;
public class weapon: MonoBehaviour
{
public Transform firePoint;
public GameObject BumperPrefab;
public float lifetime = 0.2f;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
attack();
}
}
void attack()
{
var bumper = (GameObject) Instantiate(BumperPrefab, firePoint.position, firePoint.rotation);
Destroy(bumper, lifetime);
}
Right now you're overwriting your public field containing the prefab object with your instantiated object, then destroying it. Set the instantiated object as a variable and you should be fine.
The problem is that in your code you don't care about is your GameObject exist. So for example if (for some reason) the object BumperPrefab will not be created, Destory() will try to act on null.
You can try add to BumperPrefab script bumper.cs with:
float lifetime = 0.2f;
private void OnEnable()
{
Desroy(this, lifetime)
}
problem is you are destroying BumperPrefab
when you Instantiate a new GameObject you should add it to the local variable like this
var newbumper = (GameObject) Instantiate(BumperPrefab, firePoint.position,firePoint.rotation);
and you must destroy your local variable which contains newly created gameObject
Destroy(newbumper , lifetime);

Variables in script do not show in Inspector (Unity)

I'm trying to learn how to use Unity and following online tutorials but I am currently having a problem that I don't understand how to fix.
I have a Sprite in my scene and I have attached a script to it however in the Inspector it shows the script is there but I cannot see the variables inside? I had this problem previously and it sorted itself out.
What is the cause of this problem/how do I fix it?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpaceShip : MonoBehaviour {
public float speed = 30;
public GameObject theBullet;
private void FixedUpdate()
{
float horzMove = Input.GetAxisRaw("Horizontal");
GetComponent<Rigidbody2D>().velocity = new Vector2(horzMove, 0) *
speed;
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Jump"))
{
Instantiate(theBullet, transform.position, Quaternion.identity);
}
}
}
Edit: The problem was solved by reimporting.
You either need to declare the variables as Public or [SerializeField] for member variables to appear in the inspector. Note that by declaring something as public allows access to the variable from outside the class (from other scripts/classes for example). By default, private is assigned to member variables.
Example:
public class testscript : MonoBehaviour
{
public int foo; // shows up in inspector
[SerializeField] private int bar; // also shows up while still being private
void Start()
{
}
}
Not is a problem, You forget to do something surely.
It is common at first with Unity.
Start again.
In the scene create a new GameObject and add you script.
If the inspector shows not variable:
The varible do not is public (false, if is public in you script)
There is some syntax error in the script!
or
You were not adding the correct script to the GameObject.
There are not many secrets to that, if all is well enough that the variable is public and this outside of a method of the script so that it is seen in the inspector.
One tip, do not use a GetComponent or Instantiate inside a FixedUpdate or Update because they are expensive, save the Rigidbody2D in a variable in the Start and then use it.
Sorry for my English and good luck.

Accessing container gameObject from component gameObject

I created a GameObject and named it "sensor". I then added a BoxCollider and a script (script_sensor) to sensor.
Then I created another GameObject and named it "taxi". I added a script (script_taxi) to taxi and created a public Collider2D in the script.
Then I assigned the sensor GameObject to taxi's public Collider2D.
And now, i want to access script_taxi from script_sensor.
Basically, How can i access script_taxi (Box 1 on the image), from script_sensor (Box 2)?
Check the image to understand better.
Ps: When i spam taxi prefabs, every sensor object should be able to find it's own container gameobject(taxi).
If you want to access script_taxi from script_sensor, you need some type of reference to script_taxi inside script_sensor. You can then use GetComponent. You could also use a variation of GameObject.Find, however these calls can be expensive.
public class script_sensor : MonoBehavior {
[SerializeField]
private GameObject taxi;
private script_taxi taxiScript;
void Start() {
taxiScript = taxi.GetComponent<script_taxi>();
}
}
Also it is recommended to follow C# naming conventions.
script_sensor => Sensor
script_taxi => Taxi
public Collider2D col; => [SerializeField] private Collider2D col;
Or with GameObject.Find() to find the taxi GameObject like this:
script_taxi taxi;
void Awake()
{
taxi = GameObject.FindWith("taxi").GetComponent<script_taxi>();
}

How do I pass variable from one script to another C# Unity 2D?

For example I have a variable (public static float currentLife) in script "HealthBarGUI1" and I want to use this variable in another script.
How do I pass variable from one script to another C# Unity 2D?
You could do something like this, because currentLife is more related to the player than to the gui:
class Player {
private int currentLife = 100;
public int CurrentLife {
get { return currentLife; }
set { currentLife = value; }
}
}
And your HealthBar could access the currentLife in two ways.
1) Use a public variable from type GameObject where you just drag'n'drop your Player from the Hierarchy into the new field on your script component in the inspector.
class HealthBarGUI1 {
public GameObject player;
private Player playerScript;
void Start() {
playerScript = (Player)player.GetComponent(typeof(Player));
Debug.Log(playerscript.CurrentLife);
}
}
2) The automatic way is achieved through the use of find. It's a little slower but if not used too often, it's okay.
class HealthBarGUI1 {
private Player player;
void Start() {
player = (Player)GameObject.Find("NameOfYourPlayerObject").GetComponent(typeof(Player));
Debug.Log(player.CurrentLife);
}
}
I wouldn't make the currentLife variable of your player or any other creature static. That would mean, that all instances of such an object share the same currentLife. But I guess they all have their own life value, right?
In object orientation most variables should be private, for security and simplicity reasons. They can then be made accessible trough the use of getter and setter methods.
What I meant by the top sentence, is that you also would like to group things in oop in a very natural way. The player has a life value? Write into the player class! Afterwards you can make the value accessible for other objects.
Sources:
https://www.youtube.com/watch?v=46ZjAwBF2T8
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.GetComponent.html
You can just access it with:
HealthBarGUI1.currentLife
I'm assuming that HealthBarGUI1 is the name of your MonoBehaviour script.
If your variable is not static and the 2 scripts are located on the same GameObject you can do something like this:
gameObject.GetComponent<HealthBarGUI1>().varname;
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;
}
TRY THIS!
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;

Categories