Unity Scene Management – Timed Loading and Build Indexing

March 17, 2019

Advancing Tower Defense Tutorial

Altering Scene Format

Youtube – Unity- Scene Manager and Keeping Objects when Loading/Unloading

By: Egon Everest

Myriad Games Studio – HOW TO USE THE UNITY SCENEMANAGER

I continued to updated the scene management of my tower defense tutorial. One of the biggest additions was that I did decide to create a single location for all of the OverlayCanvas button methods I wanted to use. This was just a script called the OverlayCanvasManager that I added to the GameManager object. This just made sense with how often different UI buttons would do similar actions, like going to the menu. This script then became the sole reference point between the Base Scene and the SceneManagerLite object in the Logic Scene.

As I was working with the references between the OverlayCanvasManager and the SceneManagerLite, it became more clear that the SceneManagerLite should still directly handle all of the actual scene management. The OverlayCanvasManager would then become the reference to use for the OverlayCanvas buttons (since I needed an object to drag in the inspector for the buttons, but that has to be within the same scene), and would basically tell the SceneManagerLite what to do based on what buttons were pressed.

Having the SceneManagerLite be directly responsible for everything scene related also made more sense for holding variable values. Now instead of several scripts needing to have information about different build indices for scenes like the Main Menu or the Current Level, this information could just be kept in this one location and updated much more easily.

PROBLEMS

The first main issue I was having with this setup is that the loading times of the scenes appear to be off. Sometimes the scenes would overlap because the next one would be finished loading before the previous was unloaded. I need to be able to perform some sort of check to do one after the other, or have some simple UI setup to block the process until everything is properly loaded.

The next big issue I had was debugging all of these new scene transitions. I updated every instance of transitioning between scenes, so making sure these all went to the right place took some time. I also had an issue where using the Menu or Retry methods from the OverlayCanvasManager (which tied in to the Menu or RetryLevel methods of the SceneManagerLite) was unloading my Logic Scene and just loading unintended scenes. My debugging led me to believe that this was an issue with the data transfer from the Current Level Scene to the SceneManagerLite.

As part of having all of the build index information be in the SceneManagerLite, I needed a way for it to know the build index of whatever the Current Level Scene was. I could not get this information from anything in the Base Scene, as this has its own build index. To solve this, I created a very simple object in the Level Scene, SceneInformation, that would have a script, SceneInformation, that set the currentLevelBuildIndex value in the SceneManagerLite to this object’s scene build index at Start. This was not happening however, as when I Debugged the Menu method, it was showing me that the currentLevelBuildIndex was 0. This showed me why the Logic Scene was being unloaded, and that this value was not being updated, as it was remaining at its default of 0.

I think what is causing the issue is that I am using the SceneManager GetActiveScene method, and this may not be doing what I thought it did. This is the suggested method to get your scene’s build index normally, but this may not be the case when you have multiple. If there are multiple, the ActiveScene may not necessarily be the one the object is in.

NOTES

From the problems I ran into, I had to do more research on the SceneManager for Unity, specifically what an active scene meant. The active scene is the scene that objects are created in whenever objects are instantiated. So if you have multiple scenes open, instantiated objects do NOT automatically appear in the scene of the script instantiating them. Everything from any scene that is instantiated will go to the one designated active scene. When you add scenese additively, the active scene does not change.

With this information, I updated my SceneManagerLite so its transition would now set the newly loaded scene as the active scene as well. This makes sense as I don’t want the Logic Scene to be where objects are instantiated, so immediately making newly loaded scenes active removes it from being the active scene. This also helped my issue with finding the build index of the Current Level scene. It’s obvious I want that to be the active scene when the player is in game, and now using the SceneManager method GetActiveScene will properly return the build index of the Current Level scene itself.

This ideally works in theory, but I ran into a new issue where I could not set the newly loaded scenes as active because Unity did not think they were loaded yet. I got the error message:

ArgumentException: SceneManager.SetActiveScene failed; scene ‘Level01’ is not loaded and therefore not set to active

This seemed to be caused by an issue where loading scenes takes a bit of time, so it wasn’t loaded when Unity was calling to set the scene to active. I investigated a solution with IEnumerators for this.

Looking into IEnumerators to deal with the timing issue for setting my active scene led me to this great scene management source by Myriad Games Studio. They had the script written out for a clean asynchronous scene loader. I used this as the basic foundation for a Scene Loader of my own. I needed to tweak it some for my additive scene needs, and I decided to not use the Singleton class they used for now just to keep it simpler. This now set the active scene specifically after loading the scene, so this solved that issue! Now however, I found out it was loading the wrong scene index.

The reason I was loading the wrong build index now with my Menu and Retry methods is because the SceneInformation script that was getting that active build index at Start was returning a value of 1. I had it return the active scene build index in Update to see if it ever changed, and it would correctly change to 4 on the second frame. Not only did it return 1 in Start, it also returned 1 on the very first run of Update. Then every other instance was the proper 4. This has something to do with the fact that when I load a scene I set it active as well, so there is some delay between creating the Base Scene and creating the Level Scene where Start functions in the Level Scene run before the Level Scene is set to active.

The fact that I was loading in to the proper level though gave me an idea to fix it. The fact that the right level was initially loading meant somewhere had the build index correct, and that was the Level Selector. With this information, I simply looked into the SceneManagerLite LevelSelect method and set the currentLevelBuildIndex in there to be the value of the index that is passed in. This ensures that whatever index is loaded for the level will also be the index used for the other methods, which actually makes sense.

Unity Scene Management – Creating Project SceneManager

March 16, 2019

Advancing Tower Defense Tutorial

Altering Scene Format

Youtube – Unity- Scene Manager and Keeping Objects when Loading/Unloading

By: Egon Everest

Following in the footsteps of the FAR team from a Unite 2017 talk, I wanted to update my scene management in the tower defense tutorial to match that from the talk. To begin, I wanted to create a general Logic Scene to hold all of my managers and a Base Scene to hold general assets consistent between levels.

To start I needed to break up my current level scenes into their various parts since these will have all of the basics for every scene we are attempting to construct…

Since the Scene Fader will be used constantly as a way to transition between any and all scenes, this was included in the Logic scene that will persist the entire time the game is open. To make this accessible to all the other scenes and scripts however, I chose to have its script create a public static instance of itself. This was copied directly from the way the BuildManager was setup (creating a simple sort of singleton reference from the Brackeys tutorial):

public static SceneFader sceneFaderInstance;

private void Awake()
{
if (sceneFaderInstance != null)
{
Debug.Log(“More than one Scene Fader in scene”);
return;
}
sceneFaderInstance = this;
}

This way I could just go into all the scripts that had a public reference for the Scene Fader to drag into in the Inspector, and have the sceneFader variable to be set to SceneFader.sceneFaderInstance at Start instead of relying on the public reference.

Next I determined that I needed to figure out how to manage loading/unloading these various scenes now. Using basic Unity scene management, my scripts just load one scene at a time and unload all the current scenes. So even though I could test this by dragging in a Level scene and a Logic scene at the same time to make sure the new setup worked, everything would be back to loading one scene at a time as soon as I called a basic LoadScene method. To learn this, I went to look for a new tutorial.

I came across a Scene Manager tutorial dealing with loading/unloading objects in a more controlled manner that seemed perfect for what I was looking to do. There is a Scene Manager method called LoadSceneAsync which gives more options for how you load a scene. You give it a build index as well as a LoadSceneMode.

    LoadSceneMode has two options:

  • Single: the basic way Unity loads scenes where it also unloads all other currently loaded scenes
  • Additive: this just additionaly loads the inserted scene; this does not unload any other scenes

The Additive LoadSceneMode is the first step to accomplishing what I am looking for. At this time, I also decided it may make more sense to add some type of SceneManager object to my Logic scene to hold a SceneManager type script to deal with these functions. I did not want to run into any issues with Unity’s built in SceneManager so I just named all of this SceneManagerLite for now. This would use a similar singleton setup as referenced earlir for the BuildManager and the SceneFader.

Continuing along with this tutorial, this scene management method requires you to unload the currently loaded scene as well when needed. To do this, there was a simple Scene Manager method, UnloadScene. This is currently obsolete however but just needs replaced with UnloadSceneAsync. Similarly to LoadSceneAsync, this requires at minimum the build index of the scene you wish to unload.

So when I started to look into changing all of the scripts to fit within this new scene management scheme, I came across the realization that my Scene Fader is basically my Scene Manager Lite already. Every script that deals with changing scenes acceses the Scene Fader first to perform the “FadeOut” method created, which contains both the simple fade effect as well as the actual LoadScene method constantly being used that I wanted replaced. With this discovery, I renamed my Scene Fader to the Scene Manager Lite and made the necessary edits here. This simplified everything as now I could simply just change the FadeOut method to use the LoadSceneAsync and UnloadSceneAsync methods and it would apply to all the existing calls to that method.

I did end up needing to go through each method call and touching them up because the tutorial set the scene loading method up with a string input, and I wanted to change this to an int input to go with the build index. I figured the overall scene layout and build indices were pretty set at this point, so using build index instead of the scene names would be more consistent and easier to work with in the future as I added levels.

Outside Scene Management

Something important to note is that some of the scripts I wanted to update with the new Scene management would actually be referencing build indices for a scene other than themselves. Each of these are in the OverlayCanvas, which is an object I want to keep in the BaseScene, as all of these objects will remain consistent through every level. These are those scripts:

  • CompleteLevel: deals with functionality of UI menu when player successfully defeats a level
  • GameOver: deals with functionality of UI menu when player fails a level
  • PauseMenu: deals with functionality of UI menu when player pauses the game

This means that when they want to inform the SceneManagerLite of what scenes to load/unload, they will actually want to reference the build index of the LevelScene, not the index of their own scene (BaseScene).

Unity ML Agents – Setup

March 15, 2019

Unity ML Agents

Balancing Ball Setup


Basic Project Settings

Make sure the “Scripting Runtime Version” for every platform you are targeting to build is set to (.NET 4.6 Equivalent or .NET 4.x Equivalent). I had to update the project to work with Unity 2018 and it already had .NET 4.x Equivalent as the default setting for all of my platforms.

Overall GameObject Hierarchy

The overall platform prefab has a “Ball 3D Agent” script which needs a brain property

The brain object then holds a Tensor Flow model property

Setting Up Training Environments

There are two ways to train your objects: in the Unity Scene Editor in by using an executable.

The first example will train in the Unity scene editor. This is done by accessing the “Ball 3D Academy” object, adding “3DBallLearning” brain to the Broadcast Hub of the “Ball 3D Academy” script, and checking the Control check box. The Broadcast Hub exposes the brain to the Python process, and the Control checkbox allows that Python process to control the brain.

Next I needed to use Anaconda Prompt to run the learning processes. Since I’m still getting the hang of this, I ran into a few basic issues noted in the PROBLEMS section.

After successfully completing the training, the trained model is located at path:

models/<run-identifier>/<brain_name>.nn

You then want to bring your model (the .nn file) into your Unity project, and then set this as the model property for the brain you are using.

Problems

Apparently I did not follow the default installation setup, so I was unable to access “mlagents-learn” from any directory. I found my ml-agents folder location and learned how to change my directory in Anaconda Prompt to get myself into the correct location. This then allowed the first step to properly process, which was running the line:

mlagents-learn config/trainer_config.yaml –run-id=firstRun –train

After resolving this step, I was getting a UnityTimeOutException error in Anaconda Prompt. This was just because Unity was unable to communicate with the Python process because I forget to check the Control checkbox from the tutorial.

Finally, when I went to add my newly trained model to the Learning Brain and play the scene, I got an error and the platforms did not move at all. I did not reopen the scene like stated in the tutorial notes, and determined a default value of the scene might have still been altered. It turned out I just needed to uncheck the Control check box in the Brain Hub, which makes sense since that determines if the platforms are run by the outside Python process or not. Turning this off allowed them to perform on their own with the designated model properly again.

NEXT STEPS

These are the next steps suggested by the end of this small setup tutorial:

Intro to Python Programming with Mosh – Pt. 02

Intro to Python Programming with Mosh – Pt. 02

March 14, 2019

Intro to Python Programming

Tutorial – 02

Youtube – Learn Python 3 for Machine Learning & Web Development [2019]

By: Programming with Mosh
Progress

End Time: 48:40

Next Part of Tutorial: Arithmetic Operations

NOTES

Strings

You can use single or double quotes for strings, but there is a difference for certain applications. For example, if you want an apostrophe in your string, you need to use double quotes to define the string. An example for the reverse is that you use single quotes to define the string if you want something to be in double quotes within the string.

Strings can also be defined with triple quotes. This allows you to create a multiline string.

You can call a character index of a string with brackets (i.e. string[0] will return the value of the first character in that string.). An interesting feature is that you can use negative indices to start at the end of the string and count backwards.

You can also call a chunk of characters with two values separated by a colon. If you don’t place a number before the colon, 0 will be assumed. If you don’t place a number after the colon, the length of the string is assumed. Using these together, you can perform a simple duplication of a string (i.e. another_string = string[:]).

The final check with this colon/index syntax was what would happen if you entered:
string[1:-1]
Where string was ‘Jennifer’. This returned ‘ennife’, which appears to indicate this syntax always returns values from left to right if possible, as well as showing that the beginning value is inclusive, while the final value is exclusive. To further test this, I tried string[3:1] and this did not return any value, which fit my thought on “left to right is possible”.

Formatted Strings

Formatted strings are used to make complex strings easier to visualize their output. Formatted strings are indicated with quotes starting with an f (i.e. f’text’). They then use curly brackets to create holes in the string where variables can be placed.

String Methods

The first basic method is len(). This returns the value of the number of characters in a string. This function is general purpose though, so it can count the number of objects in a list as well for example. The fact that it is general purpose is what makes it a function, as opposed to a method.

We looked into the find() method for strings. This takes an input of characters and returns the index of the first instance of those characters in the associated string. You can enter a single character or entire words to search for. Multiple characters will return the index of where those characters start.

The replace() method takes two inputs; the first input is what it searches for in the string, and the second input is what it replaces that with.

Next we used the “in” operator. Using the format of:
‘characters’ in string_variable
This returns a bool value of whether those characters are found within the string value indicated.

TERMINOLOGY

  • Method: in object oriented programming, a function that belongs to or is specific to some object

SUMMARY

The main difference between a function and a method is that a function is more general purpose, where as a method is something belonging to a specific type of object.

The string topics covered here gave me a lot of new information. I’m interested to see if there is any overlap with some of this in C# for Unity programming since there’s a lot of really helpful functions and methods covered. The formatted strings are especially nice to keep code nice and tidy instead of having those ugly string concatenation lines.

Intro to Python Programming with Mosh – Pt. 01

March 13, 2019

Intro to Python Programming

Tutorial – 01

Youtube – Learn Python 3 for Machine Learning & Web Development [2019]

By: Programming with Mosh
Progress

End Time: 29:35

Next Part of Tutorial: Strings

NOTES

This tutorial covers the complete basics of Python, starting with installing it, so it is as beginner friendly as you can get. The entire tutorial will use these basic foundational teachings to lead into creating projects to show how to use what you learn in a functional sense. These projects include a shopping site, an AI system for helping a user get music to match their preference, and a spreadsheet processing program.

Upon installation, it was important to “Add Python to PATH” for Windows (which I am using). I wasn’t sure if I did that since I had installed before, so I found that this references the Path in environment variables and just adds the path of your Python folder to this list. I added my Python path to this list in hopes that would resolve that issue. The tutorial says this is critical to follow it, so I will see if I get any errors.

Next we grabbed a code editor. The suggested one to use was PyCharm. There were no special installation features or plugins mentioned to download/install so I just installed the bare minimum.

In Python, you can define a string with single or double quotes. You can also multiply a string with a number to print that string that number of times (i.e. ‘*’ * 10 gives **********).

Standard variable types:

  • int: integer values
  • float: floating point values (those with decimal points)
  • string: words/text
  • bool: true/false
  • lists
  • objects

Next we finally got into receiving input from the user. This uses a Python function simply called Input(). The input from the user for this will also initially be created as a string variable, so make sure to convert this to int, float, etc. for your needs.

TERMINOLOGY

  • Expression: a piece of code that produces a value
  • Variable: allocation of memory for a specified value

SUMMARY

So far the basics seem very similar to what I’ve already learned in C++/C#, with the standard variable types and simple functions. I am speeding through these early parts, but don’t want to jump ahead since I want to make sure I don’t miss anything that does happen to differentiate from what I already know. This is also a good refresher for basic programming terminology and getting another view on the underlying basics of coding.

Coroutine Basics in Unity

March 12, 2019

Coroutines in Unity

Resources On Coroutines

Youtube – Coroutines – Unity Official Tutorials

By: Unity

Youtube – Introduction to Game Development (E21: coroutines)

By: Sebastian Lague

Youtube – Coroutines In Unity – What Are Coroutines And How To Use Them – Coroutines Unity Tutorial

By: Awesome Tuts

Youtube – Unity3D – 2 Ways to Start & Stop Coroutines (the good & bad ways)

By: Unity3d College

Coroutines are one of the tools I still don’t fully understand how to utilize in Unity so I wanted to gather some resources to really learn the basics. I am hoping this helps me use them more effectively and understand them better than as a method that lets me do something “after a while”.

The resources I’ve gathered cover a wide amount of information on coroutines. There are details on the terminology used around them with the most technical aspects of how they are made up to small examples on their different uses in Unity scripts. There are also different methods of starting/stopping them covered and how to properly control them.

Complete Beginners Python Tutorial by Programming with Mosh

March 11, 2019

Complete Beginners Python Tutorial

Youtube – Complete Python Tutorial for Beginners (2019)

By: Programming with Mosh

I wanted to try using Unity’s ml-agent toolkit and its initial setup uses a lot of Python so I got interested in learning the basics to better navigate the toolkit and its full potential. This was one of the first tutorials I came across and its size and recency made it an attractive choice to cover a lot of ground that shouldn’t be outdated for any reason. Its size is also a bit of a drawback at over 6 hours, so I will most likely break this up and cover it in the upcoming weeks.

Unity ML Agent Setup in Windows

March 11, 2019

Setting Up Using ML Agents in Unity

Windows 10 Setup

Unity – Machine Learning
Unity – Windows Installation

I was interested in trying out Unity’s machine learning agents toolkit so I started attempting to get everything setup and installed today. I have no prior experience with Python, so that took a bit of getting used to.

I had some trouble setting up initially as I followed the link in the documentation for the Python download which led me to get Python 3.7, but Python 3.6 is what is used in the installation notes. When I went to install the TensorFlow component, I couldn’t get that to work in 3.7. Afterward I went back and got Python 3.6 and setup a 3.6 environment and got the same error initially, but then got it to work after actually activating the ml-agents environment (so I may have been able to solve the error in Python 3.7 with this change).

Otherwise the setup went rather smoothly. The excessive use of Python encouraged me to look into some tutorials to start learning the basics to handle this Unity ml-agent system better.

The Windows installation also included an extra section for getting into GPU training for the ML-Agents. This seems like it adds a lot of extra complications so I am going to stick with the basic setup for now, but I may come back to this once I get a better grasp of Python and the ml-agent toolkit.

Unity Player Pref Editor

March 8, 2019

Unity Player Prefs Editor Script

Editor Script

Unity – Player Prefs Editor in Unity

By: Romejanic

As I was finishing my Unity tower defense tutorial, I wanted to look into deleting player pref values to do bug testing for the level unlocking system. When I searched how to do this, I came across this very helpful Unity editor script that gives a few very basic functionalities dealing with player prefs in Unity.

This tool lets you set or get the values assigned to player pref variables you’ve created. This can be useful to double check exactly what a player pref is set at currently. It also has an option to delete the value assigned to a specific player pref, or just delete all player pref values. This gave me the exact option I needed, as well as giving a nice option for checking how the game works for a new player just starting the game.

Tower Defense Tutorial – Brackeys – Ep. 28

March 8, 2019

Tower Defense Tutorial

Episode 28 – Winning Levels

Youtube – How to make a Tower Defense Game (E28 WINNING LEVELS) – Unity Tutorial

By: Brackeys
Ep. 28

This tutorial sets up the system for what happens when the player beats a level.

We began by creating a UI panel for all of the UI that should appear when the player completes a level.

Once we had that setup, we looked into creating some functionality for this screen. This started by creating a RoundsSurvived script to just place on any round counting objects (one in the game over and level won screen) to display the text properly. As an added effect, we wanted to animate the round counter to count up from 0 to give it more of an impact than simply displaying the number.

To get this round counter animation effect, we used an IEnumerator for its ability to WaitForSeconds. We created a while loop that would count from 0 to the number of rounds the player survived one at a time, with a WaitForSeconds of 0.05 each time. This provides the rapid counting effect we’re looking for to spice up the round counter.

The tutorial goes over a bug where enemies could die multiple times because of the fact that Destroy(gameObject) is not a very immediate process within Unity. Since our enemy script just checked if health reached 0 or less to determine if an enemy would call the Die method, which would then destroy it, sometimes this would allow it to call the Die method multiple times if it got shot repeatedly in a small time frame. To solve this, we just added a bool isDead, and have the check to call the Die method see if health is at/below 0 AND !isDead to ensure this is only called once (the Die method sets isDead to true).

PROBLEMS

As indicated in the comments for the tutorial video, there is an issue when selecting the Menu button upon completing a level. The Continue method is where the levelReached Player Pref is updated, so if the player simply selects the Menu button instead, the levelReached is never updated so the player will not be able to select the next level in the level selector.

SOLUTIONS

To keep the levelReached and levelToUnlock variable in the CompleteLevel script (as opposed to the Game Manager) and fix this issue in as clean a way as possible, the comment suggested moving these variable updates to an OnEnable method. This is nicer than just adding it to both methods, and keeps it within the same script which is helpful if I intend on making the GameManager into a prefab in the future.

SUMMARY

  • Rule of Thumb: “Bigger” highlight animations for bigger buttons
  • In Unity, if you want your button to be just text, you can also drag the Text element of it into the Target Graphic of the Button (script) so the text is the specifically clickable area
  • IEnumerators are used when you want a method that can be paused to continue at a later time (can be as small as a frame or two)
  • Destroy(gameObject) in Unity is SLOW. This is always a good piece of code to look around if you are having strange bugs/issues.