Coroutine wrong Behavior when scene is loaded - c#

Ok so I have this coroutine :
IEnumerator ShowCharTraits()
{
while(!hasPlayerChosen)
{
yield return null;
traitPanel.SetActive(true);
}
hasPlayerChosen = false;
traitPanel.SetActive(false);
// Debug.Log("Got called! job done");
}
It's being called like this from the awake method in my GameManager:
players = GameObject.FindGameObjectsWithTag("Player");
foreach (GameObject g in players)
{
ui_Controller.StartShowCharTraits();
g.GetComponent<PlayerToken>().isTurn = false;
}
StartShowCharTraits() is a simple method that does this :
public void StartShowCharTraits()
{
StartCoroutine("ShowCharTraits");
}
Now, I have checked the tags, no null reference exception, actually no errors or warnings are being thrown. If i load the scene in the editor and then play it everything works fine. traitPanel.SetActive(true); get called and my panel shows up. However when I load my scene from another scene using SceneManager.LoadScene(1); the above mentioned line is never reached. Any ideas why this is happening ?

Say you want to have one central place that is "like a singleton" in a Unity project. Example,
SoundEffects
LapTimer
Scores
SocialMediaConnections
All you do is this.
make your script SoundEffects.cs
recall that every Unity project must have a "preload" scene. (it's impossible to not have one)
in the preload scene, have a empty game object called "holder". make sure it is marked "DontDestroyOnLoad"
attach SoundEffects.cs to that holder
you're done.
there's just nothing more to it.
you're finished.
it's "just that simple"
So, any particular script, which happens to be attached to any particular object, in any particular scene, may need to access "SoundEffects"...
To do so, simply do this in Awake:
SoundEffects soundEffects = Object.FindObjectOfType<SoundEffects>();
then just use soundEffects anywhere in that script, for example soundEffects.PlayBoom(13) etc etc.
So in Awake()
Laps laps = Object.FindObjectOfType<Laps>();
Social social = Object.FindObjectOfType<Social>();
AI ai = Object.FindObjectOfType<AI>();
or whatever.
Unity is simple. Incredibly simple. It's just that easy.
write your script, LapTimer.cs or whatever
put it on a holder object in your preload scene (where else could it be?)
there's no "3", that's all there is. It's just that ridiculously simple.
Note that...
In the early days of Unity, someone unfortunately mentioned "singletons" on a QA board somewhere. (You can't have "singletons" in an ECS system, it's meaningless.) At the time, this led to huge discussions about how you can make a "singleton-like thingy" in Unity, which is piling confusion on confusion. Unfortunately from that day to this, you get people learning Unity, who see "singleton" mentioned here and there on the net, and it leads to endless confusion.
Once again, note that the idea of "managers" is just impossibly simple in Unity - explained above. It's trivial. It just couldn't be easier.
Note, above I mention you might want syntactic candy to avoid the incredible chore of typing Laps laps = Object.FindObjectOfType<Laps>();
There are very unfortunately no macros in Unity/c# so you need another way.
All you do is use a "Grid" script http://answers.unity3d.com/answers/1124859/view.html which has been popular for years in Unity.
But honestly, it's so simple to use Scores scores = Object.FindObjectOfType<Scores>(); that I usually just do that nowadays.

Ok how do I explain this. I have a singleton that acts as a data holder. While developing the scene with the game manager I had attached the singleton to the gamemanger object that hold a bunch of scripts. Now when I made the main menu I ofc added my singleton to it so I can carry info to the game scene and because of this my whole game manger object was being deleted. This is the culprit from the DataHolder :
void Awake()
{
if (instance == null)
instance = this;
else if (instance != this)
Destroy(gameObject);//This right here.
DontDestroyOnLoad(gameObject);
}
So I changed that line to Destroy(gameObject.GetComponent(instance.GetType()));

Related

Losing references after reloading the scene, even though they exist again

So basically im creating a space sandbox game on mobile where you can create your own universe. At the start of the game you can choose your rocket. Every rocket has its own Camera, Player and Spawner attached to it. Not the nicest solution but it works. After the player chooses his rocket, I destroy the spawners on the inactives ones, so they dont work.
My problem is when exiting the scene and choosing a different rocket and repeating the process, the SpawningManager with all the references to all Spawners lost the references to them. Even though I reloaded the scene all references are still lost.
Sorry if this was hard to follow but it was hard to explain.
Here is a part of the code that destroys the spawners(represented by colors)
if (BlueSelected == true)
{
Destroy(RedSpawner);
Destroy(OrangeSpawner);
Destroy(YellowSpawner);
Destroy(GreenSpawner);
}
And a part of one of the planet spawner(represented by colors)
{
public Transform SpawnPointBlue, SpawnPointRed, SpawnPointOrange, SpawnPointYellow;
public GameObject Mercury;
// Checks if the Spawner is greater than null (There or not) and Instantiates the Object at the Players Position
public void SpawnMercury()
{
if(SpawnPointBlue != null)
{
Instantiate(Mercury, SpawnPointBlue.position, SpawnPointBlue.rotation);
}
if(SpawnPointRed != null)
{
Instantiate(Mercury, SpawnPointRed.position, SpawnPointRed.rotation);
}
if(SpawnPointOrange != null)
{
Instantiate(Mercury, SpawnPointOrange.position, SpawnPointOrange.rotation);
}
if(SpawnPointYellow != null)
{
Instantiate(Mercury, SpawnPointYellow.position, SpawnPointYellow.rotation);
}
If I understood well, your SpawnerManager is in "don't destroy on load" and keep existing between scenes. When you start your game you have referenced manually the spawners to the manager and everything is fine then when you go to another scene and come back where the spawners should be, there is no more references into the manager ?
If so, this seams normal to me, the references between scenes are not supported and when a scene is unloaded, the references disappear.
If I misunderstood something I would be glad to dig for the solution a bit

Unity 5 C# - How to Change Scenes and Import all Resources from Last Scene

I'm not sure how to switch scenes and bring all of my resources with me. I do understand that upon load of new scene, the previous scene gets destroyed on load. I've explored some with DontDestroyOnLoad() but had no luck with what I'm trying to do.
I tried to make my player controller a prefab and simply put him into the next scene; however, I returned a heck of a lot of errors because of the many scripts I have. Mostly stuff like checkpoint, HP bars, and even the weapon.
What I need to know is how to import everything into the next scene. How do I do this without having to recode or even re-make all of the stuff that I need?
You're looking for LoadSceneMode.Additive. This is the second parameter of the LoadScene method and will load the new scene into the current one.
If you need to import every object from the previous scene, then what's the point in creating a new one?
What you could do is saving the objects positions into a file and then loading that file back on the next scene or try (again) with DontDestroyOnLoad();
I recommend to check the documentation of Unity about this function.
If you want an individual object not to be destroyed on the scene change then on the void Awake() function of Unity make a DontDestroyOnLoad(this.gameObject);
Could you provide more information? I ask because it seems from your description that
DontDestoryOnLoad
should accomplish what you want but you say it does not. As long as the object holding the components whose states you want to save is persisted into the next scene using that method, then all of those components' states should be persisted as well. Please elaborate and we can possibly provide a better answer. As for how to use it to save the state of every game object:
GameObject[] allObjects = UnityEngine.Object.FindObjectsOfType<GameObject>();
foreach(GameObject go in allObjects) {
if (go.activeInHierarchy) { /* and any other logic you want. Maybe like !isTerrain */
Object.DontDestroyOnLoad(go);
}
}
For the above code, I ripped it from https://answers.unity.com/questions/329395/how-to-get-all-gameobjects-in-scene.html

How to deal with two game modes in the same script?

If for instance I have a game which consists of just a single scene, and in that scene I make the user chose between the normal play mode or the tutorial play mode. The game has 4 different objects: a ball, 4 squares and a squarecontroller. In the tutorial mode i want to provide the user with a pointing arrow while pausing the game and continue after the user pressed the object being pointed at. Should I make a script for the normal mode and another one for the tutorial mode, make one script and check if a tutorial boolean is true or false in every function (boolean should be true if user pressed the tutorial button) or do some kind of preprocessing?
In the squarescript for example:
void OnCollisionEnter2D () {
if (isTutorial) {
PauseGame();
arrow.position = GetRelativePosition();
arrow.setActive(true);
} else {
if (canCollide) {
score++;
} else {
GameOver();
}
}
In the ballscript:
void OnMouseDown () {
if (!isTutorial) {
return;
}
ResumeGame();
}
We know nothing of your game so it's hard to answer. But as a rule of thumb: The less you have to type, the better. Also consider what will happen if you need to add new functionality to the game, will you have to go back and change tons in your code?
If so, you are most likely not writing good code.
As an attempt to give a concrete answer I'd say you should make an inheritance, create a class Level and make sub classes Tutorial and FreePlay or similar, that inherits from Level.
Then you can add all "general" functionality in the base class and the specific things goes in the sub classes
By structuring these behaviours inside if statements, it makes the code hard to understand and work with. Imagine what this will look like if you decide you want one of the squares to increase the players score AND show a tutorial arrow.
Split the behaviours into separate objects. For the square it could be something like a TutorialCollisionHandler, ScoreCollisionHandlerand HazardCollisionHandler. Then you can create different squares simply by changing which collision handlers are added to them, you don't even need to write any code!
Now depending on which mode the user picks, you can just use a different mix of squares. The same principle can be used with other tutorial or game specific behaviour.

Unity SetActive(True) Not working?

so I've been spending the past 9 hours trying to fix this. I have a weapon attached to a plane. I want this weapon to appear and be functional, after I get a specific number of kills. It does dissapear when I want it to, but it does not appear back. Also, I cannot use it while it is not visible.
Suggestions? Anyone who can see the problem here, is my saviour!
private GameManager game;
GameObject weapon_rocket;
// This works - Start class removes the object any creates any necessary referances
public void Start ()
{
weapon_rocket = GameObject.Find("weapon_rocket");
weapon_rocket.SetActive(false);
GameObject Player = GameObject.Find("Player");
game = (GameManager)GameObject.FindObjectOfType (typeof(GameManager));
GameManager gameManager = Player.GetComponent<GameManager> ();
}
// Here it doesn't recognise SetActive(True)
public void SwitchWeapon ()
{
if (game.Killed >= 1) {
weapon_rocket.SetActive (true); // this does not make the weapon reappear for some reason
CurrentWeapon = 3; // this makes the weapon usable - doesn't work when the weapon is not visible
}
null Reference Exception Already gave you a hint.
C# has a Garbage Collector as well as Java and any other programs.
Meaning, if your GameObject is Inactive and there is no Pointer/ Reference on it. It will be eligible to be garbage collected and destroyed to free some memory. It is Automatic unless you override the Finalize() function. Which I don't recommend if you don't know how CLR C# works.
To simply fix your problem. I recommend Referencing it first so the Garbage collector will ignore it.
In your Start(), you already Reference your Object so that is not going to be Garbage collected.
But I would bet that in your Editor. Your GameObject is grayed already. Meaning you have set it by InActive by default. That is why your GameObject.Find is throwing an Exception already. Make sure it is active So GameObject.Find can reference the Object First "BEFORE" Setting it to inactive. Or else. It is Garbage Collected already. Or worse, not even going to be Instantiated in the first place.
If you just want to make the object invisible, you could consider just disabling the mesh renderer instead of the entire object. And see if that allows it to be set to true and bring it back.
It's been a while since I have been in Unity, and still somewhat new to it myself. However, from what I remember there was an issue of a deprecated feature/object/method about setting the visibility of a game object. What it ended up being moved to was to the "BEHAVIOR" of a control and setting it from there.
So, that said, and that it HAS been a while, you can probably search on unity "Behavior"
But looking at this Unity link, it also states that if the parent object is not active, neither will any child under it.
So, I hope this can help further identify and resolve your issue. I will check back on this later tonight after work if not already resolved by then.
you must convert the GameObject weapon_rocket to
GameObject weapon_rocket = null;

Unity3d - GetComponentInChild passing data in C#

I'm pretty new to Unity3D and C# so I'm not entirely sure what I'm doing wrong in the following scenario.
In Unity3D I'm attempting to get the value of a variable (target) that is updated when the player moves close enough to the enemy that the script changes target from null to 'enemy' and gets the position and so on and so forth.
The turret that has a script on it for auto-targetting is a child to the main player gameobject.
Whenever I use the following:
targettingScript target;
target = gameObject.GetComponent<targettingScript>();
// or---
target = gameObject.GetComponentInChildren<targettingScript>();
...I can then test with a debug.log that it does pull "null" as it should at start up, but it doesn't seem to update when the turret finds a target and changes target from null.
I've read a few forum posts in various areas that some say you can't do this (pass data from a child component script to another gameobject that is instantiated (IE a missile firing after targetting is completed and then doing a homing-missile style of tracking) and others said that they did a check through all the levels of the gameObject till they found what they wanted, but I'm not understanding what that really means.
My questions are, 1 - is it possible to relay a variable from a child gameobject's component to another instantiated gameobject
2 - if so, how?
I apologize if this is a rather simple concept, but I'm not sure how to troubleshoot it.
I'm going to build a new scene and try various gameObjects and child objects and see what I can muster and if I find anything useful I will post it here.
In the mean time, thank you all for your time in reviewing my question.
sure,
since you instantiate the object run time, you should keep track of it,
public GameObject target;
public void Update() {
// if we dont have a target (find it).
if(target == null) {
target = GameObject.Find("Player");
}
// if we found the target take some health each frame.
if(target != null) {
playerhealth = player.GetComponent<PlayerHealth>();
playerhealth.health--;
}
}
you can of course also add a distance detector to the find.
if(target != null)
if(Vector3.distance(transform.position, target.transform.position) < 5) {
// target in range
} else {
// to far away ignore it.
target = null;
}
The best thing to do when you are instansiating gameobjects runtime you have to keep track of them if you are going to reference them later on, so create a manager that does this, create a empty gameobject, add a MgrScript to it, and have other objects call it as MgrScript.SpawnEnemy() that way we can reference the enemy's from an array or something like that.
If you dont use a manager and your scene is simple and small you can always use tags to reference the gameobjects, since it a bad idea to reference by name when you have a large and complex scene, because you will most likely reference the wrong item.

Categories

Resources