Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Phantom arrays...

Discussion in 'Scripting' started by MrDude, Oct 3, 2006.

  1. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Hi people.

    I try to make a two dimensional array but somehow it manages to create a 3 dimensional array. First of all, where does this extra dimension come from, secondly, how can every index contain all the indexes including the ones made after it and lastly, how do I get this fixed?

    Please inspect the following code:
    This is in File1 which is attached to the main playing board:
    Code (csharp):
    1.  
    2. var homeBaseBoard       : HomeBaseCode;    //image players stand on at start
    3. private var homeBase    = new Array();
    4.  
    5. function Start ()
    6. {
    7.     if (players < 2) players = 2;               //always at least 2 opponents to pit against each other
    8.     if (segments == 0) segments = 16;           //just to have some segments
    9.     while (segments % players > 0) segments++;  //equal segment count per player
    10.  
    11.     homeBase.length = players;
    12.      
    13.     initMarkers();
    14. }
    15.  
    16. function initMarkers()
    17. {
    18.     for (i=0; i < players; i++)
    19.     {
    20.         initHomeBase(i, rotateHomeBaseBy * i);
    21.     }
    22. }
    23.  
    24. function initHomeBase(base, rotation)
    25. {
    26.     homeBase[base] = Instantiate(homeBaseBoard);    
    27.     homeBase[base].initAvatars(base, rotation);
    28. }
    29.  
    30.  
    31.  
    Now, the rest is inside the file HomeBaseCode which is attached to the prefab that is instantiated in the initHomeBase function:
    Code (csharp):
    1.  
    2. private var avatars             = new Array();
    3. var maxPieces                   : int = 3;
    4.  
    5. class Avatar
    6. {
    7.     var shape       :   moveToSegment;
    8.     var current     :   int;
    9.     var next        :   int;
    10.     var canMoveIn   :   int;
    11.     var goal        :   int;
    12. }
    13.    
    14. function initAvatars(PC, rotation)
    15. {
    16.     avatars.length = maxPieces;
    17.    
    18.     for (i = 0; i < maxPieces; i++)
    19.     {
    20.         avatars[i] = new Avatar();
    21.         var newPiece : Avatar = avatars[i];
    22.         newPiece.shape = Instantiate(playerPiece, transform.position,transform.rotation);
    23.         newPiece.shape.transform.Rotate(0,180,0);
    24.         newPiece.shape.name = "Player" + PC + "Avatar"+i;
    25.     }
    26. }
    27.  
    Alright, now, what I intended was to get this structure:
    Code (csharp):
    1.  
    2. homeBase[amtOfPlayers].avatars[amtOfAvatars].someDetail
    3.  
    so could someone please explain to me why I get this structure:
    Code (csharp):
    1.  
    2. homeBase[amtOfPlayers].avatars[amtOfAvatars][amtOfAvatars].someDetail
    3.  
    For every avatar each player has, only 1 model gets created in the inspector, so the code obviously creates the correct amount of play pieces, BUT (and here is the kicker) if you inspect the code carefully, you will notice that every play piece has a unique name. Well, in the inspector they show up as:
    Code (csharp):
    1.  
    2. Player0Avatar0
    3. Player0Avatar1
    4. Player0Avatar2
    5. Player1Avatar0
    6. Player1Avatar1
    7. Player1Avatar2
    8.  
    but in this code
    Code (csharp):
    1.  
    2. for (a=0; a < homeBase.length; a++)
    3. for (b=0; b < homeBase[a].avatars.length; b++)
    4. for (c=0; c < homeBase[a].avatars[b].length; c++)
    5. textarea.text += homeBase[a].avatars[b][c].shape.name + "\n";
    6.  
    they appear as
    Code (csharp):
    1.  
    2. Player0Avatar0
    3. Player0Avatar1
    4. Player0Avatar2
    5. Player0Avatar0
    6. Player0Avatar1
    7. Player0Avatar2
    8. Player0Avatar0
    9. Player0Avatar1
    10. Player0Avatar2
    11. Player1Avatar0
    12. Player1Avatar1
    13. Player1Avatar2
    14. Player1Avatar0
    15. Player1Avatar1
    16. Player1Avatar2
    17. Player1Avatar0
    18. Player1Avatar1
    19. Player1Avatar2
    20.  
    So it would appear that for every avatar created, a new array was created containing that avatar and each and every other avatar crated after that. How in the world is that possible???

    The only thing I can think of is the fact that Unity doesn't like using class vars that are not staticly typed so Joachim suggested I do this:
    Code (csharp):
    1.  
    2.         avatars[i] = new Avatar();
    3.         var newPiece : Avatar = avatars[i];
    4.         newPiece.shape = Instantiate(playerPiece, transform.position,transform.rotation);
    5.  
    Is it possible that this line of code does NOT make newPiece act as a pointer but in fact creates new arrays? I can't see this as being possible because then the array of 4 items would have an array of 1 item followed by an array of 2 items followed by an array of 3 etc, but in my sample code above it clearly shows that all array indexes have the total length of the final array so how in the world is this phantom array index created???

    Any input?
     
  2. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    just to add to the confusion:
    This code works:
    Code (csharp):
    1.  
    2.      var boo = homeBase[whosTurn].avatars;
    3.  selectionAvatar.transform.position = boo[curAvatar].shape.transform.position;
    4.    
    Notice the way I access the shape...

    Now the follwing code gives me a runtime error saying it cannot find the variable.
    Code (csharp):
    1.  
    2. homeBase[whosTurn].avatars[curAvatar].goal;
    3.  
    This works if I use it like this:
    Code (csharp):
    1.  
    2. homeBase[whosTurn].avatars[curAvatar][0].goal;
    3.  
    So why can I access the shape without the phantom index, yet another varialbe inside the same class is unaccesable?????
     
  3. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Some further info for your head scratching...

    Even though every index contains all the indexes including the ones created after it, by indexing it properly and then just appending 0 at the end will always index the first item (which technically make sense) but the correct way of accessing the array is by adding a 0 to the mid of the index i.e.:
    Code (csharp):
    1.  
    2.  
    3. homeBase[curPlayer].avatar.length = 3;
    4. for(i = 0 ; i< 3; i++)
    5. homeBase[curPlayer].avatar[i] = new Avatar();
    6.  
    7. //this then needs to be accessed as:
    8. homeBase[curPlayer].avatar[0][selectedAvatar];
    9. //or if you like
    10. homeBase[curPlayer].avatar[selectedAvatar][selectedAvatar];
    11.  
    What i find really amazing is this:
    Code (csharp):
    1.  
    2. print(homeBase.length);               // 3
    3. print(homeBase[0].avatars);         // Avatar, Avatar, Avatar
    4. print(homeBase[0].avatars[0]);     // Avatar, Avatar, Avatar
    5. print(homeBase[0].avatars[1]);     // Avatar, Avatar, Avatar
    6. print(homeBase[0].avatars[2]);     // Avatar, Avatar, Avatar
    7. print(homeBase[0].avatars[0][0]); // Avatar
    8.  
    The second line prints all elements and says there is only 3 Avatars.
    The third line accesses one individual Avatar but it returns the same value as line 2. This should not be unless the Avatar class contains itself 3 times but as line 6 shows, this is not the case.

    I get my code to work because I hack it using the code [curAvatar][curAvatar] so I can get the game to work, but I am coding code that doesn't make sense.

    Someone please help!
     
  4. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    What is printed when you run this?
    Code (csharp):
    1.  
    2. print(homeBase[0].length);
    3. print(homeBase[0].avatars.GetType());        
    4. print(homeBase[0].avatars[0].GetType());
    5. print(homeBase[0].avatars[1].GetType());
    6. print(homeBase[0].avatars[2].GetType());
    7. print(homeBase[0].avatars[0][0].GetType());
    8.  
    And is the result same if you use push to append new the new Avarars onto the array instead of setting the size upfront?
    Code (csharp):
    1.  
    2. homeBase[curPlayer].avatar = new Array();
    3. for(i = 0 ; i< 3; i++)
    4.     homeBase[curPlayer].avatar.push( new Avatar() );
    5.  
    6.  
     
  5. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    The ones I set as Avatars are also seen as Arrays.
    Only homeBase[].avatars[][] is seen as Avatars.

    I will try the push method now and let you know what happens...

    It's my birthday today. My guests are arriving within the next hour and I am sitting on the PC while the wife is working on the party... Now how is that for dedication to your craft?

    I love trying to make games.
    That and I hate cleaning the house for guests... He he he
     
  6. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Code (csharp):
    1.  
    2. function initAvatars(PC, rotation)
    3. {
    4. //    avatars.length = maxPieces;
    5.    
    6.     var newPiece : Avatar;
    7.    
    8.     for (i = 0; i < maxPieces; i++)
    9.     {
    10. //        avatars[i] = new Avatar();
    11. //        newPiece = avatars[i];
    12.         newPiece = new Avatar();
    13.         newPiece.shape = Instantiate(playerPiece, transform.position,transform.rotation);
    14.         newPiece.shape.transform.Rotate(0,180,0);
    15.         newPiece.shape.name = "Player" + PC + "Avatar"+i;
    16.         avatars.push(newPiece);
    17. //        avatars[i] = newPiece;
    18.     }
    19. }
    20.  
    Just tried it. Still get the same:
    UNITYSCRIPT.LANG.ARRAY
     
  7. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Also try creating the Array object at the same time. (In case some other data had snuck into it before calling the function.)

    Code (csharp):
    1.  
    2. function initAvatars(PC, rotation)
    3. {
    4. //    avatars.length = maxPieces;
    5.     avatars = new Array();  // <--- clears the array
    6.     var newPiece : Avatar;
    7.    
    8.     for (i = 0; i < maxPieces; i++)
    9.     {
    10. //        avatars[i] = new Avatar();
    11. //        newPiece = avatars[i];
    12.         newPiece = new Avatar();
    13.         newPiece.shape = Instantiate(playerPiece, transform.position,transform.rotation);
    14.         newPiece.shape.transform.Rotate(0,180,0);
    15.         newPiece.shape.name = "Player" + PC + "Avatar"+i;
    16.         avatars.push(newPiece);
    17. //        avatars[i] = newPiece;
    18.     }
    19. }
    20.  
    .... although I am slowly beginning to suspect this is a compiler error...

    PS. Happy birthday.
     
  8. pete

    pete

    Joined:
    Jul 21, 2005
    Posts:
    1,647
    tg4u that someone finally said happy b-day dude! i wanted to earlier but this is way over my head and well... i'd be ot. so now i can say it... happy b-day dude!
     
  9. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Thanks for the happy bdays, mates. :)

    Had a real nice time. Rather not tell you what I did cause you might think of my as a real lame ass old f*rt...but I enjoyed it, none the less :D Thanks again

    Anyway, back to the problem at hand, I realized after reading the above suggestion, that I made the same mistake as before. I created the Array as a var in the script, attached it to the prefab and then simply started assigning to it before actually calling the "new Array" on the var. I then did that and expected all my problems to be solved, but I still get exactly the same problem. Funny that!

    I have decided that since nobody seems able to solve this little problem, and since I have managed to hack my way into getting it to work, I will leave it as is for now and perhaps see if I can change the imprementation somehow later on. As it is I have 1 week left of the current trial and I really want to see exactly how far I can get with this game before my trial runs out so since I have already wasted 3 days trying to correct a flaw that I can hack my way around has been enough time wasted, yes/no?

    I also have one more problem I need to address. Every time I change any script and then run the game I always get a "index out of range" error and the game quite. As soon as I hit the play button again it worls fine every other time. It is just the first time I hit play after changing a script. How wierd is that?

    I have tried to find the problem but have come up stumped thus far. Well, this is another problem. Thanks for your help with this one. If anyone thinks of anything else I could try, please feel free to drop a thought :)
     
  10. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Hi again.

    Okay, so I have discoverred it is indeed a bug and I have sent in a bug report.

    Remember I said I will try a different implementation? Well, I now finally have all the understanding of how Unity scripting works to enable me to start using it properly. So, in keeping with a previous suggestion, I moved all my vars out of the class I made and added them to one of the scripts my shapes use, i.e. my AICar.js script. Since all my avatars are going to use this script, I then filled my array with an instance of AICar prefab instead of my own class and still I got this same problem. For every AICar I add to the array, the array is filled with a new array containing all the AICars.

    Now, like I said before, this to me seemed physically impossible, but I think I figured out how this happens. I think the problem is a compiler error, like you said. I think the Unity code for handling arrays has an error in the [] operator. Instead of the [] operator returning a subscript of the array, it simply returns the array. This way, each element can contain all other elements, including those that were made after the element was created.

    The only problem with this idea of mine is this:
    If the [] operator returns the complete array due to a simple bug in the Unity code, then when I try to access the sub array element, surely it should cause the same bug???? Thus myArray[][][][][][][][][][] should still return a pointer to myArray. So why does myArray[] return myArray but myArray[][] returns myArray[]? This I leave to the very smart people behind Unity to figure out :)

    Hmmm.... I wonder if myArray[][][] will return myArray[][] and if myArray[][][][] will return myArray[][][]... Does anyone else see the pattern here?

    Thanks for all your help guys and gals. I am off now to get some sleep before work. Fun and games are over, now back to the harsh world of trying to earn bucks BEFORE becomming an established indie.... He he he...
     
  11. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Hmmm... I tried reproducing your problem last night without luck. I tried different combinations of duktyped arrays vs. non-ducktyped arrays and everything worked as it should.

    What version of Unity are you using? If it's a bug in Unity it might have been fixed already in the latest version.
     
  12. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    joachim said I shoud try upgrading to 1.5.1 too.
    I am currently using 1.5.0.

    I also had a wnother wierd problem. When I run the game after changing a script, it doesn't use the updated script. Only the second time. Also, the first time I get it to work, my variables get messed up. I do tests at every step of the way and get my initialized vars value as 4. I then call another function that uses those global vars andit tells me the vars have not been initialized. Go figure. Also, I create my waypoints in code and place them in an array so I can access them easily. When I hit the play button, everything works finee. I then stop the game with the play button then start it again with the play buttun. Now it complains that the item i created has been destroyed but I still try to use it. All I then have to do is open any script, hit the space bar, hit the backspace, hit apple-s and then hit the play button. Voila the game objects are created again. Go figure.

    Anyway, just to test, I then compiled the game to PPC and webGame and they all work fine. It is just in Unity itself that it does this. Well, as long as I know how to get around the problem, who cares, right? Just upgrade to 1.5.1.

    anyway, you said you tried to recreate my problem with no luck. Allow me to explain step by step what I did:
    Take a model, save it as a prefab (avatar)
    Create a script that contains a class which has the model as a field.
    Now in that same file, create a global array.
    Now take another object and add this script to it before saving it as a prefab as well.(home base)
    Now create a third object and add a global array to it.
    Now create an instantiation of the second object in each element of the array. (Please note, this array functions perfectly). Now the object that you instantiated has a Start function that initializes it's own array with a few instances of the first item. Now THIS array does not work.

    If you are interrested, I am willing to upload the game to my webspace for you to download if you wish. I have a 100M download limit and the folder is 35M so I cannot make it available for EVERYONE to download unfortunately, but if you want to have a look at it for yourself, feel free to let me know...

    Actually, I have just hacked it into working and am now past this whole thing. It never really posed a problem, just a lot of head scratching. I believe that computers are stupid and the first rule of programming is simply:
    "A computer will never ever do what you want it to do, but it will ALWAYS do what you tell it to do".

    So when I tell it to make a two dimentional array and it works in one function but not in the next. This is like a miracle. Then when one function can access an array element as array[][] but the function just above it needs to refer to the same element as array[][][]... This seems miraculous to me! I desperately wanted to knwo if I was doing something wrong, wether Unity has a ghost in the machine or wether the fine people at OTEE are absolute geniuses who are able to code a piece of software that can think for itself... :p
     
  13. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    Make sure your scripts are done compiling before starting (little spinning symbol in lower right corner of the editro). In 1.5.1 this is not an issue because the game will not start until your scripts are done compiling.

    With you variables, it sounds like you may have either timing or scope issues. I would try to stay away from global variables if possible. If you really need some global stuff, have them in a script and have the script maintain the variables and other scripts just request the values. I would first see if the globals were really needed and see if I could restructure some scripts so the globals could be eliminated.
     
  14. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    The only vars that caused the problem mentioned is the whosTurn and homeBase vars.

    The homeBase var is an array to index the individual player and his vars and the whosTurn var...well, that is pretty obvious.

    The problem I have is this:

    Code (csharp):
    1.  
    2. homeBase = new Array();
    3.  
    4. function initHomeBase(with:HomeBaseCode)
    5. {
    6. var bla : HomeBaseCode;
    7.   for(i = 0; i < 4, i++)
    8.   {
    9.      bla = Instantiate(with,position,rotation);
    10.      homeBase.push(bla);
    11.   }
    12. }
    13.  
    14. function func1()
    15. {
    16. print (homeBase.length); // 4
    17. func2();
    18. }
    19.  
    20. function func2()
    21. {
    22. print(homeBase.length); //0
    23. }
    A filled array returns it's size and in the very next line it is no longer defined. I then hit the play button twice and then it works perfectly. I assume this little glitch will be fixed in 1.5.1 as mentioned above. I just found it fascinating, s'all
     
  15. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    Worked for me, however, I had to put var in front of homebase = new Array(); in order for the script to compile. Here is the script I used
    Code (csharp):
    1.  
    2. var theObj : GameObject;
    3. var homeBase = new Array();
    4.  
    5. function initHomeBase(with:GameObject)
    6. {
    7.     //var bla : GameObject;
    8.   for(i = 0; i < 4; i++)
    9.   {
    10.      bla = Instantiate(with,with.transform.position,with.transform.rotation);
    11.      homeBase.push(bla);
    12.   }
    13. }
    14.  
    15. function func1()
    16. {
    17. print (homeBase.length); // 4
    18. func2();
    19. }
    20.  
    21. function func2()
    22. {
    23. print(homeBase.length); //0
    24. }
    25.  
    26. function Update() {
    27.     if (Input.GetKeyDown("u"))
    28.     {
    29.         initHomeBase(theObj);
    30.         func1();
    31.     }
    32. }
    33.  
     
  16. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    i installed 1.5.1 and the problem was sorted.

    now i just have to figure out why my applied forces no longer move my vehicles. always something, isn't there? :p