using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationCamera : MonoBehaviour
{
public Camera animationCamera;
public Camera mainCamera;
Animator _anim;
List<string> animations = new List<string>();
private void Start()
{
animationCamera.enabled = false;
mainCamera.enabled = true;
_anim = GetComponent<Animator>();
foreach (AnimationClip ac in _anim.runtimeAnimatorController.animationClips)
{
animations.Add(ac.name + " " + ac.length.ToString());
}
int cliptoplay = animations[0].IndexOf(" ");
string clip = animations[0].Substring(0, cliptoplay);
}
In the end in the variable string clip i'm getting the name.
And in the List animations i have the length of each clip.
But i wonder if i could do something like that if i will type in visual studio in the code only: clip.
And after the point(clip.) i will have a list of options of each clip name and it's length. For example if i type today animations. i get a list of properties like: animations.Add or animations.Insert or animations.IndexOf
What i want to do is to create some so if i will type Clip. i will get a list of all clips names and the length for example: Clip.anim_001_length_10 or Clip.myanim_length_21
So if i want to use it later it will be easier to find the clip you want to use.
Hopefully I understood you correctly, but why not just use a list of AnimationClip instead of doing the string manipulation?
List<AnimationClip> animations = new List<AnimationClip>();
Then later you can populate it by creating new AnimationClip objects and copying the properties from the controller's collection:
foreach (AnimationClip ac in _anim.runtimeAnimatorController.animationClips)
{
animations.Add(new AnimationClip {name = ac.name, length = ac.length});
}
Now if you want to get a list of all clip names, you can do something like:
List<string> clipNames = animations.Select(clip => clip.name).ToList();
Or if you want all clips with a length < 30:
List<AnimationClip> shortClips = animations.Where(clip => clip.length < 30).ToList();
Related
The objects are being set to out of the canvas
The objective of setting them is to show the user inventory with only the items that the user have
It's setting them active normally, and in the order that the user got it, but in wrong positioning
No error messages were sent
Before setting the positions array, i checked what were the positions in the scene to put it right on the array
But the objects are setting in the wrong place
I put this debug logs to try to see the problem
But it says the positions that i set
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class Filters
: MonoBehaviour
{
[Header("Items")]
public GameObject doubleSpeed;
public GameObject doubleJump;
public GameObject superForce;
public GameObject noGravity;
public GameObject noHit;
public GameObject apple;
private GameObject[] items;
public int index = 0;
public float[] position = new float[6] { -125.8f, -78.6f, -24.1f, 23.1f, 80.69913f, 36.3375f };
private float x;
// Update is called once per frame
void Update()
{
Player player = FindObjectOfType<Player>();
Filter(doubleJump, player.doubleJumps);
Filter(doubleSpeed, player.doubleSpeeds);
Filter(superForce, player.superForces);
Filter(noGravity, player.noGravitys);
Filter(noHit, player.noHits);
Filter(apple, player.apples);
items = GameObject.FindGameObjectsWithTag("Have");
if(items.Length != 0)
{
for(int i = 0; i < items.Length; i++)
{
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
items[i].SetActive(true);
Debug.Log("Changed the position and set active new position:" + items[i].transform.position);
}
}
}
void Filter(GameObject item, int quantity)
{
if(quantity < 1)
{
item.SetActive(false);
Debug.Log("less than 1");
}
else
{
item.SetActive(true);
Debug.Log("set active");
item.tag = "Have";
Debug.Log("set the tag");
}
}
}
In general there is a difference between the localPosition - the position relative to the parent object and usually the one displayed in the Unity Inspector - and the absolute world space position you are setting in
items[i].transform.position = new Vector3(position[i], 52.8f , 1f);
Further there is an even bigger difference when dealing with a RectTransform. What you see and edit in the Inspector is the RectTransform.anchoredPosition which is relative to the parents RectTransform and additionally takes the Anchors and Pivot settings into account.
So try this instead
items[i].GetComponent<RectTransform>().anchoredPosition3D = new Vector3(position[i], 52.8f , 1f);
anchoredPosition3D is basically the same as anchoredPosition but additionally allows to set the delta in the Z axis
In general for your usecase I would recommend to use a HorizontalLayoutGroup and rather let the UI handle the placement itself. You would then simply use SetActive to hide and show items.
Is there a way to bulk create tile assets of this type https://docs.unity3d.com/Manual/Tilemap-TileAsset.html
From a collection of of 2D sprites before runtime? I suspect there might be a way to do it using an editor script like this:
https://docs.unity3d.com/ScriptReference/AssetDatabase.CreateAsset.html
It would be a huge time saver rather than having to individually duplicate tiles in the project folder and selecting default images for new tiles one by one.
In this case I'd rather avoid the usual drag + drop into tile palettes because the tiles generated by that process can't really be accessed individually via code unless I instantiate a tilemap prefab, which I don't want to do.
Here's the answer I was looking for.
using UnityEngine;
using UnityEditor;
using UnityEngine.Tilemaps;
public class TileParser : MonoBehaviour
{
private const string inputPath = "Tilesets";
private const string outputPath = "Assets/Tiles/";
[MenuItem("Pre Production/Parse Tiles")]
public static void ParseTiles()
{
var sprites = Resources.LoadAll<Sprite>(inputPath);
foreach(var sprite in sprites)
{
Tile t = ScriptableObject.CreateInstance<Tile>();
t.name = sprite.name;
t.sprite = sprite;
AssetDatabase.CreateAsset(t, string.Format("{0}{1}.asset", outputPath, t.name));
}
Debug.Log(sprites.Length + " tiles created at " + outputPath);
}
}
I'm stuck on a c# scripting problem in Unity that I would like to solve.
This is what I want to achieve:
Enter a name on an InputField
Get Characters from the Input field
For each Character: set the 3D GameObject of the Character already created in the Hierarchy
SetCharacterPosition next to each other so they can create a name
SetMaterial in this order (Blue, Green,Red,Yellow) and start over
View the given input name in a 3D Colored way on the screen
This is what I have done so far:
Created 3D Prefabs of each Character and loaded into Hierarchy
Created the GUI with an InputField and a Button (+Script)
Create a Button Script (button_scr) in order to get the name and split into Characters
GUI
SCRIPT button_scr
public class button_scr : MonoBehaviour
{
public Button myButton;
public InputField un;
public GameObject go;
void Start ()
{
myButton = GetComponent<Button>();
myButton.onClick.AddListener(ProcessText);
}
void ProcessText()
{
Debug.Log("Your name is : "+un.text);
getCharacters(un.text);
}
void getCharacters(string text)
{
foreach (char c in text)
{
go = GameObject.Find(""+char.ToUpper(c));
go.SetActive (true);
// setPosicionNext2EachOther
// setColoredMaterial(Blue,Green,Red,Yellow) in this order
Debug.Log("GameObject name Log: "+go.name);
}
}
}
Some considerations:
Names can have some repeated Characters
Names can have accent marks on vowels (Á, É,Í,Ó,Ú)
Names can have "ñ" character
This is where I would like to get some orientation in order to solve the problem:
I have considered creating and filling a GameObject Array with all
the references of each character like so:
GameObject[0] = A 3D Character prefab
GameObject[1] = B 3D Character prefab
Then create a for loop to find the name character in the GameObject Array and make a copy in order to setup in the game
Set 3D character position
Set Material to 3D character in a sequential order (Blue,Green,Red,Yellow)
Is there any easier way to do this that I'm missing?
I would like to get some orientation/advice or some sample code where I can check similar issue solving.
this is a quick solution. not tested. i dont have unity installed. just for you to have an idea.
Yes. is better to assign all the letters in a array for optimization. Also deactivate all the letters in Awake()
public Material materials[]; // assign the materials in the order you want
public void getCharacters (string name)
{
int materialIndex = 0;
for (int i = 0; i < text.lenght; i++)
{
char c = char.ToUpper(text[i]);
GameObject go = GameObject.Find("" + c);
go.SetActive (true);
go.transform.position = new Vector3(i, 0, 0); // place the letters in the x axis separated by one meter
// change the material
go.GetCOmponent<Renderer>().sharedMaterial = materials[materialIndex];
materialIndex = (materialIndex + 1) % materials.length; // cycle the materials
// setPosicionNext2EachOther
// setColoredMaterial(Blue,Green,Red,Yellow) in this order
//Debug.Log("GameObject name Log: "+go.name);
}
}
I'm trying to create a search interface similar to Facebook's. That is, you type in all or part of a name, and the matches are displayed in a list below.
I know how to extract the input from the InputField (SearchBar) but I don't know how to display the matching results in the panel below during runtime.
Create a new label/button for each match and append to... the panel?
What container should I use?
How do I actually "add/append"?
Any help would be much appreciated.
Here is my scene:
And here is my code:
using UnityEngine;
using UnityEngine.UI;
using System;
public class SearchScript : MonoBehaviour {
public InputField SearchBar;
public GameObject Panel;
public List<String> myList;
public void Start() {
myList = new List <String>();
myList.Add("Andre");
myList.Add("Angela");
myList.Add("Temi");
myList.Add("Tupac");
myList.Add("Graham");
myList.Add("Grandpa");
myList.Add("Michael");
myList.Add("Miguel");
SearchBar.onValueChanged.AddListener(delegate {ValueChangeCheck(myList); });
}
public void ValueChangeCheck(List<string> myList) {
string contents = SearchBar.text;
List<String> outList = new List <String> ();
for (int i = 0; i < myList.Count; i++) {
if (myList [i].Contains (contents)) {
outList.Add (myList [i]);
}
}
for (int i = 0; i < outList.Count; i++) {
>>HELP<<
}
}
}
This page in the Unity manual describes what you'll need to do in general terms. The first thing you'll want to do is (in the editor) make a blank button/label or whatever it is you want your final product to look like. For this example, I'm going to act like it's going to be a button. Once you've got the button looking the way you want, set the position to (0,0) and make it a prefab. Make a public field in your MonoBehaviour and drag the prefab into it in the editor. That will look like this:
public GameObject ButtonPrefab;
Next, in your loop, you'll need to instantiate each button, making sure that you parent the new object to your canvas (which is your SearchBar's parent, so we have an easy way to get at it). Then assign your text and shift it down and you'll be golden!
for (int i = 0; i < outList.Count; i++) {
var newButton = Instantiate(ButtonPrefab,SearchBar.transform.parent,false) as GameObject;
// This assumes you have a Text component in your prefab
newButton.GetComponent<Text>().text = outList[i];
// You'll just have to experiment to find the value that works for you here
newButton.transform.position += Vector2.down * 20 * (i + 1);
}
I am trying to make an easy to use button inside the Unity Editor for Character and Item creation.
I will throw out a little extra info here to help explain my issue.
My game is structured like this;
Game Controller >> Character Script >> (PlayerName)Script
A character object has both the character script and a script named after it, on it.
I want to be able to click "Create New Character" in the Unity editor and it do the following;
1) Prompt for a Name to use.
2) Create Empty Game Object named Name from whatever the user typed in.
3) Create a new C# Script named the same, and add it to the object.
-I want the generated script to have some pre-determined "Character Template" code in it.
4) Attach the new Script to the new empty game object, and attach a "Character Script" to it as well.
Thanks in advance.
One last sub-question.
Would it be better to Access the PlayerNamedScript from the GameController by a public monobehaviour on the Character Script?
Or can the CharacterScript Dynamically extend the PlayerNamedScript, sibling.
I hope that is clear. Thanks again.
Try this out
Put the CharacterCreatorEditor.cs in a folder named Editor somewhere in your project.
CharacterCreatorEditor.cs
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions;
public class CharacterCreatorEditor : EditorWindow {
#region Character Fields
//Add as many character specific fields / variables you want here.
//Remember to update the same thing in the "CharacterTemplate.txt"!
public string characterName = "John Doe";
public float characterHealth = 10;
public int characterCost = 1000;
public bool isBadGuy = false;
#endregion
private bool needToAttach = false; //A boolean that checks whether a newly created script has to be attached
private float waitForCompile = 1; //Counter for compile
GameObject tempCharacter; //A temporary GameObject that we assign the new chracter to.
//A Menu Item when clicked will bring up the Editor Window
[MenuItem ("AxS/Create New Character")]
public static void CreateNewChar () {
EditorWindow.GetWindow(typeof(CharacterCreatorEditor));
}
void OnGUI () {
GUILayout.Label("Here's a sample Editor Window. Put in more variables as you need below.");
GUILayout.Space(10);
//Note on adding more fields
//The code below is broken into groups, one group per variable
//While it's relatively long, it keeps the Editor Window clean
//Most of the code should be fairly obvious
GUILayout.BeginHorizontal();
GUILayout.Label("Character Name", new GUILayoutOption[0]);
characterName = EditorGUILayout.TextField(characterName, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Health", new GUILayoutOption[0]);
characterHealth = EditorGUILayout.FloatField(characterHealth, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Cost", new GUILayoutOption[0]);
characterCost = EditorGUILayout.IntField(characterCost, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label(string.Format("Is {0} a Bad Guy?", new object[] { characterName }), new GUILayoutOption[0]);
isBadGuy = EditorGUILayout.Toggle(isBadGuy, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUI.color = Color.green;
//If we click on the "Done!" button, let's create a new character
if(GUILayout.Button("Done!", new GUILayoutOption[0]))
CreateANewCharacter();
}
void Update () {
//We created a new script below (See the last few lines of CreateANewCharacter() )
if(needToAttach) {
//Some counter we just keep reducing, so we can give the
//EditorApplication.isCompiling to kick in
waitForCompile -= 0.01f;
//So a few frames later, we can assume that the Editor has enough
//time to "catch up" and EditorApplication.isCompiling will now be true
//so, we wait for the newly created script to compile
if(waitForCompile <= 0) {
//The newly created script is done compiling
if(!EditorApplication.isCompiling) {
//Lets add the script
//Here we add the script using the name as a string rather than
//it's type in Angled braces (As done below)
tempCharacter.AddComponent(characterName.Replace(" ", ""));
//Reset the control variables for attaching these scripts.
needToAttach = false;
waitForCompile = 1;
}
}
}
}
private void CreateANewCharacter () {
//Instantiate a new GameObject
tempCharacter = new GameObject();
//Name it the same as the Character Name
tempCharacter.name = characterName;
//Add the ChracterScript component. Note the use of angle braces over quotes
tempCharacter.AddComponent<CharacterScript>();
//Loading the template text file which has some code already in it.
//Note that the text file is stored in the path PROJECT_NAME/Assets/CharacterTemplate.txt
TextAsset templateTextFile = AssetDatabase.LoadAssetAtPath("Assets/CharacterTemplate.txt",
typeof(TextAsset)) as TextAsset;
string contents = "";
//If the text file is available, lets get the text in it
//And start replacing the place holder data in it with the
//options we created in the editor window
if(templateTextFile != null) {
contents = templateTextFile.text;
contents = contents.Replace("CHARACTERCLASS_NAME_HERE", characterName.Replace(" ", ""));
contents = contents.Replace("CHARACTER_NAME_HERE", characterName);
contents = contents.Replace("CHARACTER_HEALTH_HERE", characterHealth.ToString());
contents = contents.Replace("CHARACTER_COST_HERE", characterCost.ToString());
contents = contents.Replace("CHARACTER_BAD_GUY_HERE", isBadGuy.ToString().ToLower());
}
else {
Debug.LogError("Can't find the CharacterTemplate.txt file! Is it at the path YOUR_PROJECT/Assets/CharacterTemplate.txt?");
}
//Let's create a new Script named "CHARACTERNAME.cs"
using(StreamWriter sw = new StreamWriter(string.Format(Application.dataPath + "/{0}.cs",
new object[] { characterName.Replace(" ", "") }))) {
sw.Write(contents);
}
//Refresh the Asset Database
AssetDatabase.Refresh();
//Now we need to attach the newly created script
//We can use EditorApplication.isCompiling, but it doesn't seem to kick in
//after a few frames after creating the script. So, I've created a roundabout way
//to do so. Please see the Update function
needToAttach = true;
}
}
Put the below text file into the path "YOUR_PROJECT/Assets/CharacterTemplate.txt" If you don't, the code WON'T WORK!
CharacterTemplate.txt
using UnityEngine;
using System.Collections;
public class CHARACTERCLASS_NAME_HERE : MonoBehaviour {
public string characterName = "CHARACTER_NAME_HERE";
public float characterHealth = CHARACTER_HEALTH_HERE;
public int characterCost = CHARACTER_COST_HERE;
public bool isBadGuy = CHARACTER_BAD_GUY_HERE;
public void SomeMethod () {
}
}
Explanation of the code
First, the editor script takes all the input variables (should be fairly obvious what they are)
Once you click the done button, the following happen
A new GameObject is Instantiated
The instantiated GameObject is named the same as the Character Name in the Editor (eg. John Doe)
The CharacterScript (your common script) is attached
The template text file ("CharacterTemplate.txt") is read, and all the data is replaced with the data you entered in the Editor Window
This is then written to a new script file
We refresh the Asset Database, and wait until the newly created script is compiled (eg. JohnDoe.cs)
Lastly attach the script to the GameObject instantiated in Step 1
For your second question, what you'll need to do is to have all your PlayerNamedClass extend the same base class. This way, you can type the variable you'll expose in CharacterScript
So, for example, if you call the base class "NamedCharacterScripts"
In JohnDoe.cs
public class JohnDoe : NamedCharacterScripts
In JaneDoe.cs
public class JaneDoe : NamedCharacterScripts
In CharacterScript.cs
public NamedCharacterScripts namedCharacterScript;
void Awake () {
//This will assign JohnDoe.cs for the GameObject named "John Doe" &
//JaneDoe.cs to the GameObject named "Jane Doe"
namedCharacterScript = GetComponent<NamedCharacterScripts>();
}
Hope this answers your questions. If you have trouble, just leave a comment
My script is not production-ready like Venkat's answer, but it should be easier to understand for educational purposes.
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
[ExecuteInEditMode]
public class CharacterTools : MonoBehaviour
{
[SerializeField, HideInInspector]
private string className;
private bool waitForCompile = false;
private void Update()
{
if (string.IsNullOrEmpty(className))
return;
if (waitForCompile && EditorApplication.isCompiling)
waitForCompile = false;
if (!waitForCompile && !EditorApplication.isCompiling)
{
var gameObject = new GameObject(className);
Debug.Log("Attempting to add " + className);
var c = gameObject.AddComponent(className);
className = null;
}
}
[ContextMenu("Create character")]
private void CreateCharacter()
{
string name = "Number" + Random.Range(0, 100).ToString();
string nameTemplate = "{0}Character";
string contentTemplate = #"using UnityEngine;
public class {0} : MonoBehaviour
{{
}}
";
var className = string.Format(nameTemplate, name);
var path = Application.dataPath + "/" + className + ".cs";
var scriptFile = new StreamWriter(path);
scriptFile.Write(string.Format(contentTemplate, className));
scriptFile.Close();
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport);
AssetDatabase.Refresh();
this.className = className;
this.waitForCompile = true;
}
}
Usage:
Add this script to any object on scene.
Right click on just added component in inspector.
Choose “Create character”.
Wait few seconds.