- Home /
How do I make a list of references to a variable?
Hi there, I have an attributes script for each of my charactors, which contains a selection of attribute floats for that character, and a list containing all the affor mentioned floats. This looks something like this:
public class Attributes : MonoBehaviour {
public List<float> attributesList = new List<float> ();
public float attribute01;
public float attribute02;
public float attribute03;
void Start () {
attributesList.Add (attribute01);
attributesList.Add (attribute02);
attributesList.Add (attribute03);
}
}
The rest of my scripts often reference these attributes directly via the floats rather than the list (which is the way I want to keep it if I can to stop the code getting too messy) but there is one infrequent circumstance in which I need to randomly select an attribute via the list to alter it.
I have been trying it out as is, and currently altering a list entry doesn't alter the corresponding float, so it is clear that the list currently isn't a list of refernces. After some research through unity and c# documentation, I have tried inserting the word "ref" in places to see if that will help, but unity doesn't like what I have tried so far.
How then, can I build the list from references rather than the corresponding floats? As I said earlier, I would rather avoid having to use only the list throughout the game.
Thanks in advance,
Pete
you could use a dictionnary maybe (msdn doc) ? so you can access the attribute you want with its name.
C# (and dot-NET) doesn't allow references to basic types like floats (Hringdaks's answer is the official work-around.) You might be thinking: we have the technology, and C++ does it just fine -- but C# bans real references on purpose.
If all of your Stats really are floats, could put them in an array, to make random-choosing easy. Add a cut get/set float toughness { get { return Stats[3]; } set { Stats[3]=value; } }. Or, just hand-write the random stat code.
if(roll==1) strength++; ... `. I mean, why put stats in a list for one $$anonymous$$or game feature?
Answer by iron_attorney · Jul 02, 2015 at 03:58 PM
Ok, I finally solved this. What I did in the end was create a list of strings containing nothing more than the names of each of my attributes. For the most part, I just access the attributes directly in my code. Then for my small special section of code that needs to choose one attribute at random, I pick an entry from the list of names. Then I use the name of the attribute to locate it, get it and set it as needed. The code needed to use the string to do all this looks complicated and slightly messy, but seeing as it is only needed for a short section of code, I'm not too fussed by this. I can't speak however for how performace friendly this technique is. Below is a link to the forum post that gave me this information:
http://forum.unity3d.com/threads/access-variable-by-string-name.42487/
I think this forum post gives plenty of info on the subject, however if anyone is reading this and has any questions on how I implemented this, please ask. Hope this helps someone in the future! And thank you again for all the valuable input.
Pete
Answer by Hrungdak · Jun 23, 2015 at 12:02 PM
If you need float values as references encapsulate them in a class.
public class FloatRef
{
public float Value { get; set; }
public FloatRef(float value)
{
Value = value;
}
}
Usage:
List<FloatRef> floatList = new List<FloatRef>();
FloatRef one = new FloatRef(1);
FloatRef two = new FloatRef(2);
floatList.Add(one);
floatList.Add(one);
floatList.Add(two);
Ok, I've never done anything like this before, but maybe it's about time I learnt about this stuff. I've just researched the get; set; business, so I'll give that a shot and report back to say if it helps with what I need. Having said that though, isn't there a way of setting up a list so it only references the data that you're inputing rather than storing it? Like in C++ where you'd create an array of pointers?
Ok, I've deleted my last two comments, forget about them, I should've stopped being lazy and I should've tried the suggestion out before posting them, as I have now done.
I have altered all the attributes to this new system and altered all scripts referencing these attributes by adding ".Value" to the end of each (after making a backup of course!). This works fine to start with, all the charactors work as expected, untill a new charactor is instantiated. Then I start getting floods of errors that I wasn't experiencing before. Here's an example:
Rigidbody2D.mass assign attempt for 'Family 13(Clone)' is not valid. Input mass is { NaN }.
UnityEngine.Rigidbody2D:set_mass(Single)
AI:UseEnergy(Single) (at Assets/Script/AI.cs:120)
AI:Rotate(Vector3) (at Assets/Script/AI.cs:103)
AI:GoToSearch(Vector3) (at Assets/Script/AI.cs:77)
AI:IsThereTarget() (at Assets/Script/AI.cs:55)
AI:FixedUpdate() (at Assets/Script/AI.cs:28)
They all relate to mass and localScale being NaN. It looks to me like the new custom made attributes aren't copying to the clone on instantiate. It would be impracticle to manually code in copying the attributes over. I'm not sure where to go from here.
Is there really no way of just making a list of references? It would save my ass trumendously here.
edit:
Actually, it looks like it might be something to do with the way my new type of variable are declared. When I was using straight up floats, in the attributes script, they were all declared without a value. The value's are randomly generated in another script which only goes when the game is started. Then when any new charactors were instantiated during gameplay, they were copies of the originals. The idea is that I want copies of the originals but with a few random attributes changed (hence the list of attributes).
With this new method, using my custom made variables, I have to declare a value in the attributes script, which I was setting to 0 for each attribute just to allow me to declare it. I believe this may be the cause of my current problem.
If you are forced to use some weird stuff to make your program do things, you should overthink the whole architecture. There is something wrong at the base.
I don't know how you copy your objects, but yes: instantiated objects do not copy as easy as floats or ints. Normally the reference is copied, so that your copy points to the same memory as the original. At the best...
@Nerevar, I didn't see your comment earlier . I've had a gander at dictionaries already earlier today, did wonder myself if they might help. If I was to use them though, I guess I'd still have to change my whole code still so everything works off the dictionary, rather than most things run off the list and apart from my one special process, and I guess that would still make the code a bit messier, although I would atleast be able to use the names as you said, ins$$anonymous$$d of always having to refer to it by the index number. I'm struggling to find out if you can reference dictionary entries by either name or index number, d'you happen to know? That would definately make this a a good option.
@Owen Reynolds, fair enough if that is the official workaround, not quite the right solution for the task though. Still, props to Hringdak's for trying to help. If I went for an array, the random choosing would be easy, but referencing a specific attribute from the array would be a pain because I'd only have index numbers to work from. Also every time a new charactor is created, there's a chance there are different entries on the list, which would make the task at hand even more tricky. For this reason, I also can't hand write the stat code. In answer to your last question, it is probably the most important game feature in the game, it just isn't called too often.
@Hrungdak, I have been going over the code for a while to try and make sure it is as simple as it can be while being able to achieve the task at hand, but what I'm trying to do is slightly complex, so I always knew this wouldn't be a ride in the park. That said, up until this point, it's been much easier than I expected, this is my first major stumbling block. I so far haven't had to do anything weird until this particular problem, which I'm sure I can find a less weird soluton to. Going back to the objects though, is there anything I can add to the initial class creation that would allow me to declare the FloatRefs without giving a value? That might help it copy the original value. I played with the code a little to test it, and it definately does copy the attributes, but it just instantiates the new objects attributes with whatever value I gave in the declarations. So just so I'm being clear, can I make the FloatRef class so I can initialise the attributes without a value like this:
FloatRef one = new FloatRef();
FloatRef two = new FloatRef();
ins$$anonymous$$d of having to declare it with a value like this:
FloatRef one = new FloatRef(7);
FloatRef two = new FloatRef(10);
that might fix some of the problems I'm having with this method.
Thanks to all of you for your help so far.
Yes. You need an empty constructor:
public class FloatRef
{
public float Value { get; set; }
public FloatRef(float value)
{
Value = value;
}
public FloatRef()
{
Value = 0f;
}
}
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
Changing class data with a reference? 2 Answers
Problem with accessing static variables 1 Answer
Newly created scripts cannot be referenced 2 Answers
How Do I Access and Change Items in a List on Another Script? 2 Answers