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);
}
}
}
Related
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!
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];
Dunno if I'm going the right way about this? The contents of the structure below is defined elsewhere. when I run the code it is just outputting a list of 4 zeros. any help would be greatly appreciated.....
public class NativeMethods
{
public struct FT_DEVICE_LIST_INFO_NODE
{
public uint ID;
public uint LocId;
public string SerialNumber;
public string Description;
}
[DllImportAttribute(#"C:\Users\Brendan\Documents\libMPSSE.dll", EntryPoint = "SPI_GetNumChannels")]
public static extern uint SPI_GetChannelInfo(uint index, ref FT_DEVICE_LIST_INFO_NODE chanInfo);
}
public partial class Form1 : Form
{
List<uint> items = new List<uint>();
public Form1()
{
InitializeComponent();
NativeMethods.FT_DEVICE_LIST_INFO_NODE devlist = new NativeMethods.FT_DEVICE_LIST_INFO_NODE();
for(uint x=0;x<4;x++)
{
index = 0;
items.Add(NativeMethods.SPI_GetChannelInfo(index, ref devlist));
}
listBox.DataSource = items;
}
}
Since you wrote that your structure is defined elsewhere I asume you can't change it.
The usual way to get a custom made display string is to wrap your structure in a minimal class, maybe like this:
class FT_DEVICE_wrapper
{
public FT_DEVICE_LIST_INFO_NODE INFO_NODE { get; set; }
public FT_DEVICE_wrapper(FT_DEVICE_LIST_INFO_NODE data_)
{ INFO_NODE = data_; }
public override string ToString()
{
return string.Format("ID = {0} LocID = {1} SNr = {2} ({3}) ",
INFO_NODE.ID, INFO_NODE.LocId, INFO_NODE.SerialNumber, INFO_NODE.Description);
}
}
Now you can add instances of the wrapper like this:
private void button1_Click(object sender, EventArgs e)
{
FT_DEVICE_LIST_INFO_NODE N1 = new FT_DEVICE_LIST_INFO_NODE();
N1.ID = 1;
N1.LocId = 1001;
N1.SerialNumber = "123-456-00";
N1.Description = "test 01";
FT_DEVICE_wrapper W1 = new FT_DEVICE_wrapper(N1);
listBox1.Items.Add(W1);
}
As you can see the structure's data are displayed in whichever way you format the output string.
And you can access the structure by casting the Items like this
Console.WriteLine( ((FT_DEVICE_wrapper) listBox1.Items[0]).INFO_NODE.Description );
Or, imo a little better like this:
FT_DEVICE_LIST_INFO_NODE node = ((FT_DEVICE_wrapper)listBox1.Items[0]).INFO_NODE;
Console.WriteLine(node.SerialNumber);
You may want to consider looking into ListViews, which support columns; here the way to add the structure would be quite different as you would want to put some of the date fields into separate columns.
If you want to use DataBinding you start by creating a proper List:
List<FT_DEVICE_wrapper> items = new List<FT_DEVICE_wrapper>();
and then replace
listBox1.Items.Add(W1);
by
items.Add(W1);
listBox1.DataSource = items;
Note: By simply adding a ToString method to the original structure you cold also make the structure display fine in the ListBox without being wrapped..
I want to retrieve data from a list I created that contains class objects via a foreach but I'm not able to.
Can somebody please tell me what's missing in my code?
I have a class Recipes.cs that contains the following code:
public class Recipe
{
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
public Recipe(string overskrift, int recipe_id, string opskrift,int kcal)
{
_oveskrift = overskrift;
_recipe_id = recipe_id;
_opskrift = opskrift;
_kcal = kcal;
}
}
public class Recipes
{
public List<Recipe> CreateRecipeList()
{
Recipe opskrift1 = new Recipe("Cornflakes med Chili",1,"4 kg cornflakes bages", 420);
Recipe opskrift2 = new Recipe("Oksemørbrad",2,"Oksemørbrad steges i baconfedt", 680);
Recipe opskrift3 = new Recipe("Tun i vand",3,"Dåsen åbnes og tunen spises", 120);
List<Recipe> Recipelist = new List<Recipe>();
Recipelist.Add(opskrift1);
Recipelist.Add(opskrift2);
Recipelist.Add(opskrift3);
return Recipelist;
}
}
I call CreateRecipeList() from another class calculator.cs and the code looks like this:
private int FindRecipes()
{
List<Recipe> Rlist = new List<Recipe>();
// CREATE THE CLASS AND ADD DATA TO THE LIST
Recipes r = new Recipes();
Rlist = r.CreateRecipeList();
int test = 0; // used only for test purposes
foreach(var rec in Rlist)
{
rec.????
test++;
}
return test;
}
I would presume that I should be able to dot my way into rec."the class object name"."the value"
But nothing happens!.
All I get is the option to rec.Equals, rec.GetHashcod ect. which is clearly wrong.
For the record I have also tried:
foreach(Recipe rec in Rlist)
{
rec.????
test++;
}
But that doesn't work either.
The Int test are only there for test purposes.. and it return 3.. so the list does contain the correct information.
Please show us the code for the Recipe class. Besides that, you're most of the way there...
foreach(Recipe rec in Rlist)
{
string str = rec.<PropertyName>;
}
You need to set the proper access modifiers for the members in your Recipe class.
public : Access is not restricted.
protected : Access is limited to the containing class or types derived from the containing class.
Internal : Access is limited to the current assembly.
protected internal: Access is limited to the current assembly or types derived from the containing class.
private : Access is limited to the containing type.
By default, the members of your Recipe class will have the private access modifier.
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
is:
private string _oveskrift;
private int _recipe_id;
private string _opskrift;
private int _kcal;
Maybe you want to modify your member access as follows, in order to set the values of the members only inside the class code. Any attempt to set their values outside the Recipe class will fail, as the set is private. The get remains public, which makes the value available for reading.
public class Recipe
{
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
public string Oveskrift
{
get
{
return _oveskrift;
}
private set
{
_oveskrift=value;
}
}
public int RecipeId
{
get
{
return _recipe_id;
}
private set
{
_recipe_id = value;
}
}
public string Opskrift
{
get
{
return _opskrift;
}
private set
{
_opskrift = value;
}
}
public int Kcal
{
get
{
return _kcal;
}
private set
{
_kcal = value;
}
}
public Recipe(string overskrift, int recipe_id, string opskrift, int kcal)
{
_oveskrift = overskrift;
_recipe_id = recipe_id;
_opskrift = opskrift;
_kcal = kcal;
}
}
Also, please read as soon as possible the following MSDN article: Capitalization Conventions. And also, this one: C# Coding Conventions (C# Programming Guide).
How to pass by ref different types of objects that have the same properties inside and populate them without interface.
In my app there are totally different types which have some properties in common.
Let's say this properties are double arrays.
double[] samples;
Now I have to populate these samples for 20 objects.
I don't have any access to the class definition of this object, so I can't make interface, or make them inherit from a base class.
How can use one method which I call and this method to populate all my properties.
I want to have one method like this:
private static void FillSamples(ref WhoKnowsWhat dataType, MyObject theSamples)
{
for (int i = 0; i < sampleCount; i++)
{
dataType.SampleLength[i] = MyObject.X[i];
dataType.SampleValue[i] = MyObject.y[i];
}
}
And call this with totally different types.
FillSamples(ref BigStruct.OneTypeMine, theSamples);
FillSamples(ref BigStruct.AnotherTypeMine, theSamples);
FillSamples(ref BigStruct.HisType12345, theSamples);
Then the big struct should have these samples filled in the end.
Is there a way in C#?
Thanks!
You can use the dynamic keyword:
private static void FillSamples(dynamic dataType, MyObject theSamples)
{
for (int i = 0; i < sampleCount; i++)
{
dataType.SampleLength[i] = MyObject.X[i];
dataType.SampleValue[i] = MyObject.y[i];
}
}
Edit:
Using reflection (if you don't use .Net 4.0 or higher):
private static void FillSamples(object dataType, MyObject theSamples)
{
Type t = dataType.GetType();
var px = t.GetProperty("SampleLength");
var py = t.GetProperty("SampleValue");
for (int i = 0; i < sampleCount; i++)
{
px.SetValue(dataType, MyObject.X[i], null);
py.SetValue(dataType, MyObject.Y[i], null);
}
}
Don't know if it helps you any, but you can use reflection to find out what properties (and fields, methods etc.) an object supports at runtime. Check out http://www.csharp-examples.net/reflection-property-names/ for example, if you're interested in learning more.
You can use dynamic objects. You should be careful when targeting fields of a dynamic object since they cannot be checked at compile time. See my example below:
[TestFixture]
public class DynamicObjects
{
[Test]
public void Dynamic_Call()
{
dynamic obj1 = new Apple();
obj1.Weight = 100;
obj1.Color = "Red";
dynamic obj2 = new Orange();
obj2.Weight = 200;
obj2.Width = 10;
Assert.IsTrue(obj1.Weight < obj2.Weight);
}
}
public class Apple
{
public int Weight { get; set; }
public string Color { get; set; }
}
public class Orange
{
public int Weight { get; set; }
public int Width { get; set; }
}