Getting Scene Names at Runtime/Creating Scenes at runtime - c#

I want to build a RTS Game in Unity version 5.3.xxx.
I want to have a dropdown menu to select the level i want to play.
I dont want to hardcode it in so how do i get the scene names at runtime?
This is neccessary to add new Levels ingame.
Thats the next question then. How do i create new scenes and add them to build path at runtime to use them ingame? for example in an map editor?
I cant use the UnityEditor to go through all scenes with foreeach, because its a editor class and these dont get into the final build..
Thanks

As of Unity 5.x, there are much more robust options for managing scenes at runtime.
Getting the current scene name:
SceneManager.GetActiveScene().name
Getting a list of all scene names added to the SceneManager:
var numScenes = SceneManager.sceneCount;
List<string> sceneNames = new List<string>(numScenes);
for (int i=0; i < numScenes; ++i)
{
sceneNames.Add(StageManager.GetSceneAt(i).name);
}
Creating new scene at runtime:
var newScene = SceneManager.CreateScene(string sceneName);
Adding new scenes to the build path at runtime:
I'm fairly certain this is not possible nor recommended.
If you want the functionality of a level editor in your game, consider writing your own method of serializing a scene so that it can be deserialized into an empty scene at runtime.
See also:
SceneManagement.Scene
SceneManagement.SceneManager

As explained here on the Unity forums, SceneManager.GetSceneAt only works with currently active scenes.
For now, you need to use work-arounds to get all scenes in your build during run-time, using EditorBuildSettings.scenes. You are right, this is only available during editing, but you can simply make sure to cache them to a run-time asset or component before building.
Also note that the documentation example for EditorBuildSettings.scenes actually gives you a pretty powerful script to grab all scenes, including those that have not been added to the build settings (and even adds them to the build settings, using a single button click)! You can just use that to save all scene paths to a component or ScriptableObject which will then be available during run-time.

Old I know, but it matched my search, so I'm posting my solution. This seems to be possible at runtime now using SceneUtility.GetScenePathByBuildIndex
What I did:
var sceneNames = new List<string>();
var regex = new Regex(#"([^/]*/)*([\w\d\-]*)\.unity");
for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
{
var path = SceneUtility.GetScenePathByBuildIndex(i);
var name = regex.Replace(path, "$2");
sceneNames.Add(name);
}
Regex Credit

Related

Alexa skill relative path to JSON file

I have a little problem with my Alexa skill. I want to include display components in it, and I want to send an appropriate directive. For most of my code, I use custom classes from API, e.g.
Resources colorsDark = new Resources();
colorsDark.description = "Color for dark theme";
colorsDark.when = "${viewport.theme == 'dark'}";
However, for one part of my skill, I use only previously-created values, so there is no need to create new objects and assign values to them. Instead, I've created a .json file that includes all the necessary information.
I'd like to point my code to this file, but here I encountered an issue.
I'd like to make it look like this:
doc.Styles = [JSON_FILE]
However, when the function is executed, it can't find this file.
I'm using JObject from Newtonsoft.Json.
I tried to use only the relative path:
JObject jObject = JObject.Parse(File.ReadAllText(".\\AlexaPresentationLanguage\\Styles\\ListStyle.json"));
as well as some other solutions like
Path.GetCurrentDirectory
and
Path.Combine
From System.IO
So far nothing worked. Do you have any ideas what can I do?

Retrieve all Animator States and set them manually in code

I've stumbled upon something I never imagined to be a problem but... it is.
I am writing a visualiazion/simulation toolkit using unity 5.5.
The used model is already imported and animation clips are set via the editor. This is what my animation state controller lookes like:
I want to display the AnimationStates in a DropdownMenu. Whenever a user selects an entry, the current animation state should be set to the selected one.
e.G. User selected Autoplay: State set to clip Autoplay, after that to SimpleRotate, then to ComplexRotate and again to Autoplay (just a simple loop).
But if the user selects Idle, ComplexRotate 0 or SimpleRotate 0, the animation should play once and then stay at the end of the clip. (Just like I did it in the animation controller.
Heres a rather pseudo-version of what i want:
//Retrieve all states to populate the dropdown:
List<AnimationState> states = myAnimationController.GetAllStates();
foreach(AnimationState state in states)
Dropdown.add(state.name)
//callback
OnDropdownIndexChanged(int item)
{
string stateName = ..... //removed for simplicity
myAnimationController.setState(stateName)
}
On top of that it would be nice if I could check the transitions FROM and TO the states. (Autoplay is the only state that should be shown in the dropdown for the loop)
Can this be realized with a custom Animation Controller? Or did I miss something?
I see two options here. A rather simple one and a bit more complex, but robust, one.
Option One
You use the RuntimeAnimatorController. This will get you all the AnimationClips in the given Animator at runtime. You can play a State in an AnimatorController at any given time by using Animator.Play(StateNameOrHash). Unfortunately, for this option, this will only play a State by its Name or NameHash (as statet in the docs). Because we only have the AnimationClips and not the States from the Controller this option would involve to rename the States in the controller to the exact name of the Animation Clip. Then you could play a State like this:
myAnimator.Play(myAnimationClip.name);
This is a fast option to get you started but not a good option in the long run because it has essentially two drawbacks:
You could only use a flat hierarchy in your AnimatorController. No SubStateMachines/Blendtrees because they are not represented with an AnimationClip. Therefore you would not be able to retrief these States through the RuntimeAnimatorController because it only returns the AnimationClips
The AnimatorController could be hard to understand because the states are named like the AnimationClips. I dont know your situation here but it would be better to use descriptive names then the names from the AnimationClips for better understanding.
Option Two
This option is more complex. I will give you a quick overview of the Workflow and then explain the parts in more detail or give references to get you started!
[Editor Script] Generate a script with all the States from your AnimatorController. (Probably the "hardest" part)
Use the generated Script to fill your dropdown with the States
Play your state :)
Part 1:
Use an Editor Script to extract all the States from your AnimatorController. This link should give you an hint on how to achieve this. Short (not tested) example code:
private void writeAllStates()
{
AnimatorControllerLayer[] allLayer = controller.layers;
List<string> stateNames = new List<string>();
for (int i = 0; i < allLayer.Length; i++)
{
ChildAnimatorState[] states = allLayer[i].stateMachine.states;
for (int j = 0; j < states.Length; j++)
{
// you could do additional filtering here. like "would i like to add this state to my list because it has no exit transition" etc
if (shouldBeInserted(states[i]))
{
// add state to list
stateNames.Add(states[j].state.name);
}
}
}
// now generate a textfile to write all the states
FileGenerator.createFileForController(controller, stateNames);
}
Keep in mind: the used AnimatorController is within the UnityEditor.Animations namespace. This can be a public field in an EditorScript to easily give you access.
Part 2: Your scriptfile should create a class like this one:
public class AnimatorControllerStates
{
public List<string> states = new List<string>
{
"Idle",
"ComplexRotate 0",
"Autoplay",
...
}
}
Name the class somehow related to your AnimatorController you created it for. And make this class a field in your runtime script. Then you could get access to all your states like this:
myAnimatorControllerStates.states
This array can fill your dropdown. You would save the index of the dropdown and then can play the state by the index.
Part 3: Now it would be realy easy to just play your state in your script:
string state = myAnimatorControllerStates.states[mySelectedIndex];
myAnimatorController.Play(mySelectedIndex);
I dont know the scope of your project but to have a maintainable application I would prefer option two at any time.

Unity/C# Savegame Migration

I've written a SaveLoad class, which contains a Savegame class that has a bunch of ints, doubles, bools but also more complex things like an array of self-written class objects.
That savegame object is being created, serialized and AES encrypted on save and vice versa on load - so far, so good.
The problem I'm facing now is that if there are new variables (in a newer version of the game) that have to be stored and loaded, the game crashes on load, because the new variables can't be loaded correctly (because they are not contained in the old save file). E.g. ints and doubles contain the default 0 while an array is not initialized, thus null.
My current "solution": For each variable that is being loaded, check if it doesn't contain a specific value (which I set in the Savegame class).
For example: In Savegame I set
public int myInt = int.MinValue;
and when loading, I check:
if(savegame.myInt != int.MinValue){
//load successful
}else{
//load failed
};
This works so far for int and double, but once I hit the first bool, I realized, that for every variable I have to find a value that makes "no sense"(not reachable usually), thus was a failed load. => Shitty method for bools.
I could now go ahead and convert all bools to int, but this is getting ugly...
There must be a cleaner and/or smarter solution to this. Maybe some sort of savegame migrator? If there is a well done, free plugin for this, that would also be fine for me, but I'd prefer a code-solution, which may also be more helpful for other people with a similar problem.
Thanks in advance! :)
Your issue is poor implementation.
If you are going to be having changes like this, you should be following Extend, Deprecate, Delete (EDD).
In this case, you should be implementing new properties/fields as nullables until you can go through and data repair your old save files. This way, you can check first if the loaded field is null or has a value. If it has a value, you're good to go, if it's null, you don't have a value, you need to handle that some way.
e.g.
/*We deprecate the old one by marking it obsolete*/
[Obsolete("Use NewSaveGameFile instead")]
public class OldSaveGameFile
{
public int SomeInt { get; set; }
}
/*We extend by creating a new class with old one's fields*/
/*and the new one's fields as nullables*/
public class NewSaveGameFile
{
public int SomeInt { get; set; }
public bool? SomeNullableBool { get; set; }
}
public class FileLoader
{
public SavedGame LoadMyFile()
{
NewSaveGameFile newFile = GetFileFromDatabase(); // Code to load the file
if (newFile.SomeNullableBool.HasValue)
{
// You're good to go
}
else
{
// It's missing this property, so set it to a default value and save it
}
}
}
Then once everything has been data repaired, you can fully migrate to the NewSaveGameFile and remove the nullables (this would be the delete step)
So one solution would be to store the version of the save file system in the save file itself. So a property called version.
Then when initially opening the file, you can call the correct method to load the save game. It could be a different method, an interface which gets versioned, different classes, etc but then you would require one of these for each save file version you have.
After loading it in file's version, you could then code migration objects/methods that would populate the default values as it becomes a newer version in memory. Similar to your checks above, but you'd need to know which properties/values need to be set between each version and apply the default. This would give you the ability to migrate forward to each version of the save file, so a really old save could be updated to the newest version available.
I'm facing the same problem and trying to build a sustainable solution. Ideally someone should be able to open the game in 10 years and still access their save, even if the game has changed substantially.
I'm having a hard time finding a library that does this for me, so I may build my own (please let me know if you know of one!)
The way that changing schemas is generally handled in the world of web-engineering is through migrations-- if an old version of a file is found, we run it through sequential schema migrations until it's up-to-date.
I can think of two ways to do this:
Either you could save all saved files to the cloud, say, in MongoDB, then change their save data for them whenever they make updates or
You need to run old save data through standardized migrations on the client when they attempt to load an old version of the save file
If I wanted to make the client update stale saved states then, every time I need to change the structure of the save file (on a game that's been released):
Create a new SavablePlayerData0_0_0 where 0_0_0 is using semantic versioning
Make sure every SavablePlayerData includes public string version="0_0_0"
We'll maintain static Dictionary<string, SavedPlayerData> versionToType = {"0_0_0": typeof(SavablePlayerData0_0_0)} and a static string currentSavedDataVersion
We'll also maintain a list of migration methods which we NEVER get rid of, something like:
Something like
public SavablePlayerData0_0_1 Migration_0_0_0_to_next(SavablePlayerData0_0_0 oldFile)
{
return new SavablePlayerData0_0_1(attrA: oldFile.attrA, attrB: someDefault);
}
Then you'd figure out which version they were on from the file version, the run their save state through sequential migrations until it matches the latest, valid state.
Something like (total pseudocode)
public NewSavedDataVersion MigrateToCurrent(PrevSavedDataVersion savedData)
{
nextSavedData = MigrationManager.migrationDict[GetVersion(savedData)]
if (GetVersion(nextSavedData) != MigrationManager.currentVersion) {
return MigrateToCurrent(nextSavedData, /* You'd keep a counter to look up the next one */)
}
}
Finally, you'd want to make sure you use a type alias and [Obsolete] to quickly shift over your codebase to the new save version
It might all-in-all be easier to just work with save-file-in-the-cloud so you can control migration. If you do this, then when a user tries to open the game with an older version, you must block them and force them to update the game to match the saved version stored in the cloud.

GetComponent in Unity (C#)

So i try to access the script component in another GameObject, but to do it faster i have a Component variable.
Component map = GameObject.FindWithTag("Map").GetComponent<Map>();
Now when i want to reference a variable inside a map component
map.selected = true;
it gives me an error that
UnityEngine.Component does not contain a definition for selected".
Selected is a public bool in Map script, attached to the Map GameObject.
When i go with the long way
GameObject.FindWithTag("Map").GetComponent<Map>().selected = true;
everything works, but i'm looking for a way to shorten my code (this script uses variables from Map in many instances, so i want to write it the shorter way).
This happens because you are instanciating your variable map as a Component, so the compiler will be looking for the selected attribute in the Component class.
Try something like this:
MapScript map = GameObject.FindWithTag("Map").GetComponent<MapScript>();
(Replace MapScript with the actual name of that script.)
I'm not entirely sure if this exact syntax will work, and I have no way of testing this at the moment, so please try and see if it works. If it doesn't, I will look into that as soon as I'm home.

How to recreate XNA's SkinnedModelProcessor

I have a model that is rigged and skinned and I would like to be able to move the bones programmatically (as opposed to a preset animation stored int he fbx file)
I can load the model fine, and see that the bones have been loaded, but changing the bone transforms doesnt seem to affect the rendered model.
I am looking at the sample project here:
http://create.msdn.com/en-US/education/catalog/sample/skinned_model
It looks like it uses an extended ModelProcessor (aka SkinnedModelProcessor) to over the DefaultEffect and return a MaterialProcessorDefaultEffect.SkinnedEffect. I am guessing that somewhere along the lines this makes the renderer transform the mesh vertices using the model bones (with a vertex shader???)
I am having problems getting this SkinnedModelProcessor working in my own project. The sample uses the Microsoft.Xna.Framework.Content.Pipeline assembly. In my project I dont see the item in the regular list of .net references. So I added it manually from the filesystem.
The problem there is that as soon as I compile, visual studio says that it cant find that namespace, even though right up until I compile it shows everything working fine
How can I recreate the SkinnedModelProcessor from the sample in my own project
or
How can I get changes to bones reflect in my rendered model?
I've had the same issue and I'm in the works on creating my own simple Skinned Model Manipulator. For the time being the easiest way is to just create a new method in the AnimationPlayer class that will allow you to alter the boneTransforms.
I made something like this for your help:
public void SetPose(Matrix rootTransform, Matrix[] boneAlteration)
{
skinningDataValue.BindPose.CopyTo(boneTransforms, 0);
for (int i = 0; i < boneTransforms.Length; i++)
{
boneTransforms[i] = boneAlteration[i] * boneTransforms[i];
}
UpdateWorldTransforms(rootTransform);
UpdateSkinTransforms();
}
For this method the Matrix Array boneAlteration is simply an array of Identity Matrices for maintaining the original bindPose. Change any of the matrices before passing it into this method to rotate the bone for that corresponding index.
It appears the reason getting the reference to the pipeline assembly was such a problem is that you have to segregate that code into a separate special project using the XNA Content Pipeline Extension Library project template

Categories

Resources