Retrieve all Animator States and set them manually in code - c#

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.

Related

Is there any way to get an array containing un-instantiated prefabs

I have a folder, Items, that contains prefabs with the class attached, what I want to do is make an array full of these prefabs in order to compare their ID numbers, a string inside the item class, with the ID numbers from a database to put these prefabs into an inventory array, I hope this is enough detail.
This is what you probably need.
public List<GameObject> prefabsWithClassOnThem;
public GameObject CheckTheID(string ID)
{
foreach (GameObject go in prefabsWithClassOnThem)
{
if(go.GetComponent<ItemClass>().getID() == ID){
return go;
}
}
return null;
}
prefabsWithClassOnThem - the name speaks for itself. It is the list of prefabs you will have to put manually into the list. Then you add your script to a script manager (or any object you feel like) this is how it will look like:
Click on the arrow, write in wanted size and put all the prefabs manually.
CheckTheID - method, which will check for a prefab with the ID you give for this method.
ItemClass - the class, you were mentioning in your question. The class which holds the ID of prefab, and has method GetID().
You will want to call this method in your addToInventory method or something like this.
If you want to check if object was instantiated before, just create additional boolean parameter in ItemClass which will hold true if it was instantiated (you will have to change it for the first time you instantiate one of the prefabs).
Every time you want to create unique item, just check the boolean and thats pretty much it.
Sorry for messy language.

Need to update list item and then put it in textfile

So I am doing this c# program which basically is a coffee machine. Asks the user to register and adds the instance in a textfile, then login, then asks which coffee he wants from a provided list, and finally increments a property named "coffee points". The problem is that I have no idea how I am going to update the coffee points inside my textfile. I can get the coffee points and increment them by 1 and then print them in console, however, I dont know how to update just the coffee points in my textfile of a certain user.
Below is the code I am using to retrieve the coffee points of the logged in user and increment them by 1, and store them in the variable "newCoffeePoints".
int newCoffeePoints = 0;
for (int i = 0; i < customerList.Count; i++)
{
if (customerList[i].iUsername == cu2.iUsername)
{
customerList[i].iCoffeePoints += 1;
newCoffeePoints = customerList[i].iCoffeePoints;
break;
}
}
Well, for this exact purpose we have so many different types of databases such as Mongo, SQL etc.
But if you're trying to serialize/deserialize object and save it to a file among other types of serialization you might want to consider JSON format. The libarary Newtonsoft.js is what we (C# developers) usually use for that.
You could create a virtual structure that reflects what you need.
Since we might want to find object by key a Dictionary<TKey, TValue> collection suits much better than List<T>.
Do whatever operation you need to do with users in a Dictionary<key, value> and then serialize it to JSON and save it to disc using the File.WriteAllText(json) method.
Whether to do it after each update (so that if app crashes all the data is saved) or do it once when the app is about to finish execution will depend on your needs.
The field with dictionary could be something along the lines of:
// CKeyType here is a type of customer's id field such as int, string etc.
private static readonly CustomerDict = new Dictionary<CKeyType, Customer>();
You can easily solve this problem by using JSON and Newtonsoft Library. (Fabjan mentioned above)
Here is a tutorial link from Microsoft Virtual Academy that you can follow.
https://mva.microsoft.com/en-US/training-courses/introduction-to-json-with-c-12742?l=xxtX274UB_8805494542

Getting Scene Names at Runtime/Creating Scenes at runtime

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

Using Form to dynamically generate buttons/panels for a Rule Engine

I'm writing my own Rule Engine, I've looked at a couple that existed but I'm looking for something else which I couldn't find examples to.
I'm looking for a similar application where I can dig into and learn how to do it.
Now, my question is REGARDLESS of the Rule Engine, more of a Form/Dynamic question, but if with your answer you can
relate to what I eventually want to do, that would be great.
Regarding the UI, I'm using Visual Form and the I'd like it to be like this:
http://i.imgur.com/5istREF.jpg
Now, once the user select on the final check box "And/Or" I want him to be able to enter another rule, exactly the same format as the first one.
http://i.imgur.com/N588sjj.jpg
Now the user can basically do it as many times as he wants, so I'm looking for a way to dynamically handle it and create buttons/pannels or even using the same ones (but every time he can enter different values).
Like I've said if you know any similar application/code that I can look into, regardless of rule engine, that will help as well.
Eventually I will take all the fields that he entered and turn it into code.
If I understand you correctly, what you can do is make a controller of your own which is defined in an additional form and then you can add it to your main form as much as you want.
You can define this new controller (meaning a new form) to hold only a single line of the comboBox and then add it to a location in your main form which is based on the location of the previous controller.
Here is an example which adds several control of a class called CNewControl to a tab called newControlsTab one after the other.
int controlHeight = 0;
foreach (CNewControl newControl in newControlList)
{
this.newControlsTab.Controls.Add(newControl );
newControl.Dock = DockStyle.Top;
newControl.Location = new System.Drawing.Point(40, 3 + controlHeight);
controlHeight += newControl .Size.Height;
}
You can of course change it to add your line only once when the user chooses the appropriate option in which a line should be added.

What to use instead ini in C#

There must be a program that should generate WORD document (but that's not the point). It generates a document by data that the user writes in the program. And sometimes there is need to close application and do some other work and user don't want to lose all progress. And here we must keep all the "changes" that user have entered. Previously, I have saved all .ini file (under the instruction http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C) it was enough for me for test, but in real cases ini was not enough, because if I save the textbox with multiline so record to inin file goes wrong, and when reading ini file - readed was only the first line and then only the first 255 characters.
Here is an example of what should be saved:
information about all checked checkboxes radiobuttons etc. (in
INI-expample I show it in CHECKOUTS and COMPARING sections)
the data from all textboxes on the main form (MAIN section)
most importantly, objects of 'implementation' and 'screens' class.
Now about class 'implementation': Each implementation may have a name, description, status, and a list of links to screenshots. To do this, I created a listbox with list of screenshots for each implementation (ScreenList) and a separate listbox for all implementations. Ie when I fill the data I store object in listbox, and then if I need I can just get access to it. And when I save a list of all implementations into ini I first of all write the number of all implementations to be able get access in loops (for, while etc) to each object (all in INI and CODE examples: Section IMPLEMENTATIONS, IMPLEMENTATION_n ...)
And the question is: how to save these Data? As I know Microsoft has abandoned ini and use the xml, but I can't google it correctly. Someone suggested I use serialization of data in xml, but as far as I could google - Serialization is used only for one object of class, and I have a lot of these objects are, othervide I still have and values ​​of all the checkboxes and more. Ie I need to save all the values ​​of controls , all the objects of classes implement and screen, and then read these values ​​and write them right back to where they were taken . How to do that?
Code examples:
//........save object to listbox
Implement imp = new Implement(impName.Text, impDescr.Text, impStatus.Text, ScreenList);
listBox1.Items.Add(imp);
//......
//in implement class, Screens is list of screenshots that is get from another listbox
private List<string> _Screens = new List<string>();
public Implement(string Name, string Description, string Status, ListBox Screen)
{
_Name = Name;
_Description = Description;
_Status = Status;
for(int i=0;i<Screen.Items.Count;i++)
{
_Screens.Add(Screen.Items[i].ToString());
}
}
//....getting access to implementation
Implement imp = (Implement)listBox1.SelectedItem;
....
Ini example:
[MAIN]
Languages=Polish
Comment=Comment lalarar larl alrlalrl
Status=Correct
[CHECKOUTS]
Enable=True
SLDoc=False
SLDocTab=True
SaveDoc=True
LoadDoc=False
SendDoc=False
Correctly=True
CorrNum=50
[COMPARING]
Enable=True
NoDif=False
Declar=True
UnDecl=False
UnDeclDESCR=
[IMPLEMENTATIONS]
COUNT=2
[IMPLEMENTATION_0]
Name=Implement 1 CORRECT
Descr=text text test text
Status=Correct
ScreenCount=2
Screen_0=C:\1.png
Screen_1=C:\2.png
[IMPLEMENTATION_1]
Name=IMPLEMENT 2 INCORRECT
Descr=lala
Status=Incorrect
ScreenCount=2
Screen_0=C:\2.png
Screen_1=C:\3.jpg
[SCREENS]
COUNT=2
[SCREEN_0]
Descr=Screen 1
Screen=C:\1.png
[SCREEN_1]
Descr=Screen 2
Screen=C:\1.png
If I understood you correctly you should take a look at settings mechanism in c#.
I hope that this chapter of MSDN will be useful.
What you have to do is create some kind of Settings object. This should be a class that either has a specific property (or class for nested values) for each setting you like (e.g. public string Language {get; set; }) or you take a more generic way by using two dictionaries Dictionary<string, string> (for simple values), Dictionary<string, Settings> (a recursive structure for complex types).
Then your form should be able to create such a settings object an fill it with the desired data it needs to recreate the current state and it should be able to take such a settings object and change its current state to this settings object by setting all inner variable to the values within this object.
The next step would be to make this object serializable by either using XML serialization or Data Contract or whatever you like. Then you can write/load this object to/from disk and afterwards push it into the class that needs this state.

Categories

Resources