How to fix unintended scene buildIndex of -1 in Unity - c#

Essentially, after testing a few level prototypes, I've decided to stick with my current game idea so I started creating a GameManager to control the flow of levels, etc. I don't have any additional libraries or asset packages being used outside of the default, but for some reason the buildIndex of all of my scenes is -1, which I learned according to the API, means that they're supposed to be loaded through an AssetBundle. Now I can't load anything with SceneManager and I'm not sure how to move forward. I did temporarily have the 2d-extras-master folder in the project as I assumed I'd be using it, but removed it after realizing I wouldn't need it. Does anyone know how to reset the buildIndices of my scenes to the values in the Build Settings? Any/All help is greatly appreciated!
Edit: I should also mention, that the latest Scene I added (when I still had the 2d-extras-manager) still retained a normal buildIndex of 0
Edit #2: So I've found that I can access the buildIndices of the other scenes amongst themselves. It's only when I try to access the buildIndices from my MainMenu Scene that things don't work
Edit #3: I've found a fix, but it doesn't necessarily answer the question. I found that I can force the LoadScene function to work if I know what the buildIndex is, but if I search for it via a scene name, it would return -1.
ex.
// where 1 is the buildIndex of Scene "Main" in BuildSettings
// works
SceneManager.LoadScene(1);
// doesn't work
int index = SceneManager.GetSceneByName("Main").buildIndex; //returns -1
SceneManager.LoadScene(index);
// also doesn't work (Where current scene is buildIndex 0)
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);

SceneManager.GetSceneByBuildIndex or SceneManager.GetSceneByName and functions alike work only on loaded scenes. If scene isn't loaded it will return -1. Reason is, you can load scenes additively, so it's possible to have even 5 loaded scenes.
It's true that the api is lacking in many ways.
In your case you are trying to use it right after SceneManager.LoadScene(1);, int index = SceneManager.GetSceneByName("Main").buildIndex; returns -1 most likely because scene will be loaded on the next frame "officially".
You could try to wait 1 frame in coroutine and then do that. But usually you will have scene index or scene name to load/save it and not care about logic after scene has been loaded. You can create a manager which will store all of the loaded scenes where you could look up their build indices if you need them to decide what scene to load next.
Alternatively you can use Addressables package which handles a lot, it's hard to get into but scene loading works way better there in my opinion.

In the build menu, accessed by clicking in File on Unity Editor you can organize your scenes and add them to the flow like in this image
I'm not sure of it, but I'm supose when you didn't assigned a Scene to the flow, it get sceneIndex = -1. So load a scene, go to BuildSettings, add it to the build flow, do the same to all of them. I think this way you can solve it.

You can use this method to get buildIndex.
https://docs.unity3d.com/ScriptReference/SceneManagement.SceneUtility.GetBuildIndexByScenePath.html
And after checking the validity of the buildIndex, if the buildIndexis not equal to -1, then the scene exists in the build settings.
public static bool SceneExists(string scenePath)
{
return SceneUtility.GetBuildIndexByScenePath(scenePath) != -1;
}

Related

Destroying Instantiated Clone Components Breaks Original Game Object Components?

Maybe im missing something obvious but to keep it short. I have working code for a character. When you "dash" I want to leave behind an after-image type effect, by cloning the player, removing its unneeded components and then applying a shader. Issue is as soon as I instantiate the clone the original player stops functioning (cant move etc). It still has all its components and everything as normal, and the clone does get the correct components removed. But it still breaks. As soon as I remove that line, its back to normal. Any ideas?
This is the only relevant code in the script that instantiates the clone.
private void DodgeEffect()
{
GameObject _DodgeSFX = Instantiate(gameObject, transform.position, transform.rotation );
Destroy(_DodgeSFX.GetComponent<PlayerController>());
Destroy(_DodgeSFX.GetComponent<PlayerCombat>());
Destroy(_DodgeSFX.GetComponent<WarpController>());
Destroy(_DodgeSFX.GetComponent<Animator>());
}
its because you are making a copy of gameObject. while Instantiate() returns a GameObject, it also returns whatever you put into the first section of the method. instead, make a seperate gameObject than the player in the editor, and make _DodgeSFX public so you can put the copy into the slot. Then, just instantiate that seperate GameObject and you wont have to destroy the components through script(because you remove the components in the editor), saving time
Ok so from some testing I think its down to the Unity.InputSystem only allowing 1 instance of each Input to be enabled at once. When I instantiated a clone of the player, it still goes through the Enable/Awake functions before those components are destroyed, and since the Inputs on that clone were never disabled, that becomes the "main" one. If I set the main player's scripts with Inputs deactive and then active again, it all works as normal. Note that the script was still working on the main character just fine, it was only the inputs that was broken. Im still not sure why this is the case, if its a limitation of the input system, or intentional, cant seem to find documentation of this experience anywhere.

Loading scene in Unity makes the references in that scene null

I am making my first game in Unity and I'm trying to load the first level of it when the cutscene at the start ends. I don't know if it's possible to make the script do something after a video clip ends, so I wrote my code like this:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class CutsceneEnd : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine("wait");
}
IEnumerator wait()
{
yield return new WaitForSeconds(36);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
But the problem is not with my method of waiting for the end of the video, it's with the scene it loads. I can't move my character because all the references in the scripts are null. I have no idea what I did wrong.
Unity references should be stored in the scene file. Are you using any source control like git? If someone else did not push the changes to the .unityscene file or the .meta files for the associated scripts/prefabs, it might break the references.
I think we need some more information here.
If you referring to references (public variables) to Assets/GameObjects in the loaded scene, then you may have simply never placed the references in the first place. Unity's public variables should be saved within the Scene file and should always load with the Scene.
Double check to see if the references are actually null. Are you using an animation when you load into the Scene? This can keep you from being able to manual move anything. For example, if you animate the character when loading the scene, it could get stuck in the animation clip and you won't be able to move it.
Lastly, if you are referring to references created within the code to other scripts, objects, or variables, then these may break between scenes if you don't utilize 'DontDestroyOnLoad'.
Just spit-balling here, I need more information to correctly find the solution.

Multiple Checkpoints / Respawning Zones

Basically I have three classes to try and collect the checkpoints and respawn at the last one reached. The code seems fine, however I'm getting a null reference error upon reaching the checkpoint during runtime. The problem seems to be inside Unity.
private CheckPoint cp;
I can't get anything to go into the inspector section for this instance. Granted, I do a call upon start
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
I've tired an empty object and I've tried placing one of my checkpoint objects but nothing seems to work. Any advice?
1. Check if you have multiple gameObjects tagged "CheckPoint".
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
is going to find the first gameObject with that tag and try to get your component, if there is no component, you will get null reference
2. Use this instead
FindObjectsOfType<Checkpoint>();
for more: https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html
3. Use a list/array/any other container in your "CheckpointManager" class and into Start() method of each Checkpoint do:
CheckpointManager.container.add(this);
this should be much easier to manage and you will not have to use tags.

Unity 5.5.0f3 play animation backwards at runtime

Original question on the Unityforums here
I've been trying to get an animation to not only slow down and speed up, but also play backwards depending on user input for my Hololens-application. I am using the Mecanim system, not legacy animations.
The whole thing is supposed to happen at runtime, through dynamic user input.
I know that it's possible through scripting, as I had it working before I lost local progress and some files during some Unity-Collaborate issues. As stupid as it sounds, since then I have not been able to remember what I did different from my current approach.
Right now I'm manipulating the value Animator.speed, but that only works for values >= 0.
Any help would be greatly appreciated!
Edit: In case the link is not working or visible for anybody, here is my code:
private Animator anim;
//...
anim = gameObject.GetComponent<Animator>();
//...
public void OnManipulationUpdated(ManipulationEventData eventData)
{
if (anim.isActiveAndEnabled)
{
anim.speed = eventData.CumulativeDelta.x;
anim.Play("KA_Cover_Anim");
return;
}
//...
}
Edit2: Incorrectly marked as dupicate! The linked question does not regard a similar problem and required a different solution
Edit3: For clarification, the linked "duplicate" uses the legacy animation system which is irrelevant for my question. In Mecanim, the new animation system in Unity 5.xx, you can not access the Animations directly as shown in the selected answer. Neither is it possible to alter the animation speed as shown in in the second answer.
I'm not exactly sure what you're end goal is, but you can play animations backwards and at different speeds by using a parameter.
On the animation state, you can make it watch a parameter and multiply it against the default speed of the animation. All you need to do in code is something like
animator.setFloat("Speed",-1.0f);
Hope that helps.

C# [Persistent Saving and Loading]

Alright, so basically I have this slight issue that I'm trying to get a fix for. I'm using a GameObject called GameControl that I have learned from the Unity Tutorial guy. What I'm trying to do is be able to edit the options after they have been loaded. I can get them to save and load just fine. I had to switch the options up differently for the Singleplayer and Multiplayer mode because they have different save and load data. Now when I save/load this data back. I'm having troubles getting them to edit after loading, because it seems to be continuously loading the saved data, so if I were to make a change, it alters back to the saved data.
When I was just following along, I had this when the options were both the same and I used:
void Start() {
GameControl.control.Load();
}
Which seemed to work just fine, but now I have two different load files SP Options and MP Options. And I just don't know where to put these files, I thought maybe in my Switch Operation where I have it to load when I click Singleplayer, or when it loads Multiplayer at click. But this is where I have the continuous loading problem. And when I go to edit the options in the Window, it reverts back, please help me understand where to put these loads. I don't want to have a load button, I don't like the idea of that, I want it to be an automatic load, when you click Singleplayer (get singleplayer load files); and Multiplayer (get multiplayer load files).
void OnGUI() {
GUI.skin=mainSkin;
menuSelection=GUI.SelectionGrid(new Rect(Screen.width*.025f,Screen.height*.025f,buttonW,buttonH), menuSelection, button, 1);
switch(menuSelection) {
default:
break;
case 0:
windowRect=GUI.Window(0,windowRect,SPOptionsWindow,"Singleplayer Options (Pre-Game)");
break;
case 1:
windowRect=GUI.Window(1,windowRect,MPOptionsWindow,"Multiplayer Options (Pre-Game)");
break;
case 2:
LeaderboardsWindow();
break;
}
}
Here is where I have it loading the Load files; however I am unsure this is where it's supposed to be unless there is more code to make it stop running after the first time it loads. I've also tried to load it in the SPOptionsWindow(); and MPOptionsWindow(); but I get the same result.
Ahhhhh, long time fix! So basically what I did to correct this was to add more code in the GameControl.cs file. Although some features aren't the same, all I had to do was just recreate the same types with different naming conventions. More code, however it definitely works. However temporarily. Thinking long-term, however, I'm not sure if this is the exact fix that I would appreciate to have.
Problems may occur: •The actual options taking place would require more code to implement. •Maybe I won't be able to implement more code, but I would have to change it back to being the same?
These I don't really know until I reach that bridge, but however, it's a fix for now, and if there are any other answers to this, please throw your idea out there :)

Categories