I have this script that get the properties by names from a shader :
At the bottom I'm changing one of the properties values by giving the property name: "Vector1_570450D5"
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.PlayerLoop;
public class ChangeShaders : MonoBehaviour
{
public Material material;
public float duration = 1;
private List<string> propertiesNames = new List<string>();
private void Awake()
{
material = GetComponent<Renderer>().material;
var propertiesCount = ShaderUtil.GetPropertyCount(material.shader);
for(int i = 0; i < propertiesCount; i++)
{
propertiesNames.Add(ShaderUtil.GetPropertyName(material.shader, i));
}
}
void Update()
{
var currentValue = Mathf.Lerp(-1, 1, Mathf.PingPong(Time.time / duration, 1));
material.SetFloat("Vector1_570450D5", currentValue);
}
}
but instead typing manual the property name I want to create a class for each property name so I will be able to type inside the SetFloat something like :
material.SetFloat(myProperties.Vector1_570450D5, currentValue);
In this case there are 5 properties so I want to be able to do :
material.SetFloat(myProperties.Vector1_570450D5, currentValue);
Or
material.SetFloat(myProperties.Color_50147CDB, currentValue);
So I thought to make this script with the attribute executeallways to create a editor script only for getting the properties and then to use the properties in this mono script like in the examples I gave.
Just to your title: You have a List<string>, not an array ;)
Before filling it with values you would need to initialize it. You can also do that together with the field declaration:
public List<string> names = new List<string>();
Even simpler would then be a proper constructor and e.g. using
public class MyClass
{
public List<string> names = new List<string>();
public MyClass(List<string> initialNames)
{
// This creates a new List<string> copying all elements of initialNames
names = new List<string>(initialNames);
}
}
And then use it like
var myClass = new MyClass(names);
If I understand correct you are further looking for a property like e.g.
public string this[int index] => names[i];
which would allow you to access a specific entry directly via
myClass[i];
instead of
myClass.names[i];
Related
I have a System.Serializable class
[System.Serializable]
public class _answersData
{
public string word;
public string wordmeaning;
public string wordmeaning2;
public GameObject result;
}
I then have a monobehaviour class where an array of _answerData class is declared
public class gamePlay : MonoBehaviour
{
public _answersData[] answersData;
}
I am then trying to add data to _answerData array from another script using below method
public class challengeScript: MonoBehaviour
{
void Start()
{
gameplayScript = gameObject.GetComponent<gamePlay>();
populate();
}
void populate()
{
answersCount = int.Parse(snapshot.Child("Answers").Child("Count").Value.ToString());
gameplayScript.answersData = new _answersData[answersCount];
for (int i = 0; i < answersCount; i++)
{
string positionNode = "Answer" + (i + 1).ToString();
string _word = snapshot.Child("Answers").Child(positionNode).Child("Word").Value.ToString();
gameplayScript.answersData[i].word = _word;
}
}
}
but I am getting NullReferenceException at 'gameplayScript.answersData[i].word = _word' line
Here's the error:
NullReferenceException: Object reference not set to an instance of an object
Can someone guide what I am doing wrong here?
Just because it is [Serializable] doesn't mean the elements are automatically created once you create the array. By default all reference type elements will still be null.
Only within Unity the Inspector itself automatically creates instances of [Serializable] types and initializes the array itself.
In code you have to actually create your element instances yourself like e.g.
var answerData = new _answerData();
answerData.word = _word;
gameplayScript.answersData[i] = answerData;
everyone!
Tried to make saver of my List with help of combination JSON and PlayerPrefs but stucked with the problem. It don't save my list and don't load. It only giving me my list with zero elements.
Code:
private List<Toggle> _listActiveToggles = new List<Toggle>();
public void Awake()
{
Load();
foreach (Toggle toggle in _listActiveToggles)
{
toggle.isOn = true;
}
}
public void ChooseUsableBuffs(Toggle toggle)
{
int level = PlayerPrefs.GetInt("HDD") / 10;
if (_listActiveToggles.Any(x => toggle))
{
_listActiveToggles.Remove(toggle);
Debug.Log(_listActiveToggles.Count);
return;
}
if (_listActiveToggles.Count >= level)
{
_listActiveToggles[0].isOn = false;
_listActiveToggles.RemoveAt(0);
}
_listActiveToggles.Add(toggle);
Save();
Debug.Log(_listActiveToggles.Count);
}
public void Save()
{
PlayerPrefs.SetString("Key" ,JsonUtility.ToJson(_listActiveToggles));
}
public void Load()
{
_listActiveToggles = JsonUtility.FromJson<List<Toggle>>(PlayerPrefs.GetString("Key"));
}
Tried to check what JSON contains and it showed only: {}
The JsonUtility can not directly serialized array and list types.
You rather need a wrapper class like
[Serializable]
public class ToggleData
{
public List<Toggle> _listActiveToggles = new List<Toggle>();
}
public ToggleData data;
Which now you can serialize
var json = JsonUtility.ToJson(Data);
and deserilialize
JsonUtility.FromJsonOverwrite(json, data);
However, in your specific case I guess it will not work anyway. UnityEngine.UI.Toggle is of type MonoBehaviour and you can not simply deserilialize these from JSON!
You can only store their settings and loading settings into existing toggles.
I guess actually it should be enough to store a list of bool to JSON and iterate over your toggles and the list and do e.g.
using System.Linq;
...
[Serializable]
public class ToggleData
{
public List<bool> ToggleStates = new List<book>();
}
public ToggleData data;
[SerializeField] private List<Toggle> _listActiveToggles = new List<Toggle>();
And then save via
data.ToggleStates = _listActiveToggles.Select(t => t.isOn).ToList();
var json = JsonUtility.ToJson(Data);
and deserilialize via
JsonUtility.FromJsonOverwrite(json, data);
for(var i = 0; i < Mathf.Min(data.ToggleStates.Count, _listActiveToggles.Count); i++)
{
_listActiveToggles[i].isOn = data.ToggleStates[i];
}
Note however that this means you should reference all Toggles you want to save the state for in your list via the Inspector and can not simply remove or add entries on runtime!
If you have made a list of Custom objects is it a must to have to do with Hashcodes if you wanna check that list to see if it contains a object before adding it, I mean so that you do not get duplicates in the list or is there an easier way basically I want to use the contains method on a custom object list to see if the object I want to add already exists in the list and if there then is an easier way then to have to deal with hashcodes?
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataConverter.Objects;
namespace DataConverter.Converters
{
class CategoryConverter
{
private Category category;
private SubCategory subCategory;
private ExcellObj excellObj;
public CategoryConverter(string path)
{
excellObj = new ExcellObj(path);
}
public List<Category> getCategoryListExcel()
{
List<Category> categories = new List<Category>();
List<string> ColumnNames = new List<string> { "Group1", "Group1Descr" };
List<int> CorrectColumn = new List<int>();
for(int i = 0; i < ColumnNames.Count; i++)
{
CorrectColumn.Add(excellObj.findColumn(ColumnNames[i]));
}
for(int i = 2; i < excellObj.allRows; i++)
{
categories.Add(category = new Category(excellObj.getValuesFromCell(i, CorrectColumn[1]), excellObj.getValuesFromCell(i, CorrectColumn[0]), "Home"));
}
return categories;
}
public List<List<SubCategory>> getSubCategory()
{
List<SubCategory> subCategories1 = new List<SubCategory>();
List<SubCategory> subCategories2 = new List<SubCategory>();
List<List<SubCategory>> subCategoriesList = new List<List<SubCategory>>();
List<string> ColumnNamesSubCategory1 = new List<string> { "Group2", "Group2Descr" };
List<string> ColumnNamesSubCategory2 = new List<string> { "Group3", "Group3Desc" };
List<int> CorrectColumn1 = new List<int>();
List<int> CorrectColumn2 = new List<int>();
for(int i = 0; i < ColumnNamesSubCategory1.Count; i++)
{
CorrectColumn1.Add(excellObj.findColumn(ColumnNamesSubCategory1[i]));
CorrectColumn2.Add(excellObj.findColumn(ColumnNamesSubCategory2[i]));
}
for(int i = 1; i < excellObj.allRows; i++)
{
subCategories1.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i, CorrectColumn1[1]),excellObj.getValuesFromCell(i,CorrectColumn1[0]), "Home"));
subCategories2.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i,CorrectColumn2[1]), excellObj.getValuesFromCell(i,CorrectColumn2[0]), "Home"));
}
subCategoriesList.Add(subCategories1);
subCategoriesList.Add(subCategories2);
return subCategoriesList;
}
public void finnishedUsingExcel()
{
excellObj.CloseApplication();
}
}
}
and what i whant to happen is that i whant to run a
if(categories.Contains(category) == false){
categories.add(category)
}
i do not understand this part in the documentation?
public Person(string lastName, string ssn)
{
if (Regex.IsMatch(ssn, #"\d{9}"))
uniqueSsn = $"{ssn.Substring(0, 3)}-{ssn.Substring(3, 2)}-{ssn.Substring(5, 4)}";
else if (Regex.IsMatch(ssn, #"\d{3}-\d{2}-\d{4}"))
uniqueSsn = ssn;
else
throw new FormatException("The social security number has an invalid format.");
this.LastName = lastName;
}
Assuming you have a code like this:
List<CustomObject> listOfCustomObjects = new List<CustomObject>();
Solution 1
If so, you can use listOfCustomObjects.Contains(customObject) to find out if customObject is in listOfCustomObjects. You should add using System.Linq; to the top of your code in order to use this method.
Solution 2
Another way to not have duplicates in your list is basically not using a List. You can use HashSet instead. With this method, duplicate objects won't be added to your list automatically. HashSet is also in LINQ Library, so you should add the line using System.Linq; for this solution too. Here's an example how to create a new HashSet with your CustomObject class:
HashSet<CustomObject> setOfCustomObjects = new HashSet<CustomObject>();
You really should have your class implement IEquatable if it's reasonable to do so and you're going to check for equality with any frequency, just so it does not bite you. The "Contains" method will work, but only to test that the exact same instance is present, not necessarily one that just shares matching properties. Consider the following code:
class Program
{
static void Main(string[] args)
{
var classInstance = new MySampleClass("testA", "testB");
var classList = new List<MySampleClass>();
classList.Add(classInstance);
if (classList.Contains(new MySampleClass("testA", "testB")))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
if (classList.Contains(classInstance))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
}
public class MySampleClass
{
public string SampleProperty1 { get; set; }
public string SampleProperty2 { get; set; }
public MySampleClass(string sampleProperty1, string sampleProperty2)
{
SampleProperty1 = sampleProperty1;
SampleProperty2 = sampleProperty2;
}
}
Even though we're checking for the presence of the class that has the exact same values as the one we previously added, they're still separate instances and you'll end up with duplicates in your list.
An alternative in the very limited case would be to use a LINQ method to check whether the list already contains an entry with a property that can be compared, such as an int ID or something:
yourList.Any(item => item.Id.Equals(otherItem.Id));
Again, if it's more than a one off, implement it the right way with IEquatable. See Microsoft's documentation
I am making a game. The movement of the player is a series of pre-defined stages. Because this principle is the backbone of my game and there are many NPCs at once, I try to make this as efficient as possible.
So I want to include the values of each stage by using constants.
At certain events (like a pressed button for the player) the stage switches to another stage. Because I can't refer to another nested class in a constant, I additionally want to set up an array that contains references to each stage.
The names of the classes are written in enums, and I refer by their integer value.
How do I do that? I want to include the solution at the given position in the code.
If there is a better way to do that by the way, I appreciate if you forward me to it.
enum TYPE
{
hum //and more
}
enum HUM
{
standF, stand_jumpF, stand_kneeF, stand_wanderF //and more
}
static class CONST
{
public static class hum
{
public static class standF
{
public const int duration = 1;
public const int actionLeft = (int)HUM.stand_jumpF;
public const int actionRight = (int)HUM.stand_kneeF;
public const int actionFaster = (int)HUM.stand_wanderF;
}
//and more
}
//and more
}
public static class REF
{
public static Type[][] CONST { get; }
static REF()
{
Type[][] REF = new Type[Enum.GetNames(typeof(TYPE)).Length][];
Type[TYPE.hum][] REF = new Type[Enum.GetNames(typeof(HUM)).Length];
for (int i = 0; i < Enum.GetNames(typeof(HUM)).Length; i++)
{
Type[TYPE.hum][i] = //what to do here?
}
}
}
After reading comparable questions about non-nested class I would have used this solution:
Type[TYPE.hum][i] = Type.GetType(Enum.GetName(typeof(HUM), i));
But it doesn't seem to do the trick.
You are messing up with array notations. Have a look at following question for more information: Multidimensional Array [][] vs [,]
I would suggest working with a dictionary (although I find your whole design weird to say the least), you'll need to add using System.Collections.Generic; to your usings.
public static class REF
{
public static Type[][] CONST { get; }
static REF()
{
Dictionary<Enum, List<Enum>> REF = new Dictionary<Enum, List<Enum>>();
REF.Add(TYPE.hum, new List<Enum>());
foreach (var item in Enum.GetValues(typeof(HUM)))
{
REF[TYPE.hum].Add((HUM)item);
}
// Demo code, print all values in TYPE.hum
foreach (var item in REF[TYPE.hum])
{
Console.WriteLine(item);
}
}
}
I am trying to create a class called Student which contains the members name, GPA and an array of objects called CourseRecord. I'm completely lost here, since I can't use for or while loops in my class to initialize the CourseRecord objects. This is the code I would like to use, but I'm not able to use the for loop:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Register
{
class StudentRecord
{
public string studentName;
public double studentGPA;
public CourseRecord[] grades = new CourseRecord[4];
public StudentRecord()
{
}
public StudentRecord(string name, double GPA)
{
studentName = name;
studentGPA = GPA;
}
for (int i = 0; i < CourseRecord.Length; i++;)
{
CourseRecord[i] = new CourseRecord;
CourseRecord[i].Read;
}
}
}
All this code is outside of a method body, which is causing the compiler error:
for (int i = 0; i < CourseRecord.Length; int++;)
{
CourseRecord[i] = new CourseRecord;
CourseRecord[i].Read;
}
Also, as a commenter said, you want i++, not int++;
Your code is not inside of a method. Also, you should use i++ and not int++, as it is the value of i you are increasing, not the value of int.
Also, I will assume that CourseRecord.Read is a method, in which case it should have parentheses after it in order to actually call the method.
public void ReadCourseRecords()
{
for (int i = 0; i < CourseRecord.Length; i++;)
{
CourseRecord[i] = new CourseRecord;
CourseRecord[i].Read();
}
}
If you add this method to your StudentRecord class, then when you call it, it should read the course records.