Search Unity

Feedback Please

Discussion in 'Scripting' started by RoughSpaghetti3211, Mar 16, 2019.

  1. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    I have hex tile game system that contains a bunch of data for each tile. The data is on separate data objects depending on their type eg navigation data[] and say prefab data[]. I have a graph class that iterates over GraphComponents . All i have to do is assemble the desired data eg navigation data and say terrain type data onto a single object to pass to my graph iteration. I was hoping for some feedback on my attempt below. I feel like im recreating the data on Node for no good reason when it all already exists, im just cherry picking data I need. Thanks in advance

    Code (csharp):
    1.  
    2.     //
    3.     // Interface
    4.     public interface IHexVertex
    5.     {
    6.         HexVert HexVetrex { get; set; }
    7.  
    8.     }
    9.  
    10.     public interface IHexTriangle
    11.     {
    12.         HexTri HexTriangle { get; set; }
    13.  
    14.     }
    15.  
    16.     public interface ITile<T>
    17.     {
    18.         void AddTile(T t, int index);
    19.     }
    20.  
    21.     //
    22.     // Components
    23.     public class Tile : IHexVertex, IHexTriangle
    24.     {
    25.         private HexVert _hexVertex;
    26.         public HexVert HexVetrex
    27.         {
    28.             get{ return _hexVertex;}
    29.             set{ _hexVertex = value;}
    30.         }
    31.  
    32.         private HexTri _hexTriangle;
    33.         public HexTri HexTriangle
    34.         {
    35.             get { return _hexTriangle; }
    36.             set { _hexTriangle = value; }
    37.         }
    38.     }
    39.  
    40.     //
    41.     // Graph components
    42.     public class GraphComponents<T> : ITile<T>  where T : Tile
    43.     {
    44.         //
    45.         // Fields
    46.         protected Node[] nodeData;
    47.  
    48.         //
    49.         // Properties
    50.         public Node[] Components
    51.         {
    52.             get { return nodeData; }
    53.             set { nodeData = value; }
    54.         }
    55.  
    56.         //
    57.         // Sub Class
    58.         public class Node
    59.         {
    60.             private T data;
    61.  
    62.             public Node(T t)
    63.             {
    64.                 data = t;
    65.             }
    66.  
    67.             public T Data
    68.             {
    69.                 get { return data; }
    70.                 set { data = value; }
    71.             }
    72.         }
    73.  
    74.         //
    75.         // Interface implementation
    76.         public void AddTile(T t , int index)
    77.         {
    78.             Node n = new Node(t);
    79.             nodeData[index] = n;
    80.         }
    81.     }
    82.  
    83.  
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    The first thing I'd say, is there is some inherent danger in the
    GraphComponents
    interface. Line 53 accepts an array and line 79 just assumes all is well. Typically, a class should take care of its own internals. Relying on external code to know how to handle the internals of this class is inviting problems.

    I'm not exactly sure what you want, but could you not just have something like this? :-
    Code (CSharp):
    1. public class GraphComponents<T> where T : Tile
    2. {
    3.     public T this[int index]
    4.     {
    5.         get { return nodeData[index];  }
    6.         set { nodeData[index] = value; }
    7.     }
    8.  
    9.     public class Node
    10.     {
    11.         public Node(T t)
    12.         {
    13.             data = t;
    14.         }
    15.  
    16.         public T Data
    17.         {
    18.             get { return data; }
    19.             set { data = value; }
    20.         }
    21.  
    22.         T data;
    23.     }
    24.  
    25.     Dictionary<int, T> nodeData;
    26. }
    Incidentally, I have changed
    nodeData
    from protected to private. There is an argument that protected parameters are merely slightly restricted global variables (can be accessed directly just by inheriting from the class).
     
    RoughSpaghetti3211 likes this.
  3. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    This is much cleaner thanks so much. One last question. Is there an elegant way to populate the data in the GraphComponents<Tile> method with overloading constructor or implementing an interface for the type of data or should this be its own utill class.

    Basically what i need to achieve somewhere in constructors or interface or util?
    eg

    Code (csharp):
    1.  
    2. public HexVert[] hexVerticies;                                            
    3. public HexTri[] hexTriangles;                                            
    4.  
    5. ....
    6.  
    7. public GraphComponents<Tile> compTiles = new GraphComponents<Tile>();
    8.  
    9. for (int i = 0; i < max; i++)
    10. {
    11.     compTiles[i].HexTriangle = hexTriangles[i];
    12.     compTiles[i].HexVertex = hexVerticies[i];
    13. }
    14.  
     
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    That will very much depend on your code overall, there is no one right answer for that.

    From the sample that you have pasted, if you know
    max
    and the contents of both
    hexVerticies
    and
    hexTriangles
    at the point in time of instantiating an object, then having that code in the constructor should be fine. If not but the code can be abstracted (and will prove useful for other scenarios), then you could try the util / interface route.

    I think just go with what feels best. If things change over time, then you may find you have to revisit and rework your chosen option. But that's ok- it can't always be avoided.
     
  5. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Ok i will play around and see how it feels, thanks again for your help.
     
  6. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    One very last question, looking at implementing this as a constructor but im curious why people use properties to instantiate a class and could this be an elegant solution for my problem.

    .... MAYBE ? IDK
    Code (csharp):
    1.  
    2.         private static GraphComponents<T> _default;
    3.         public static GraphComponents<T> Default
    4.         {
    5.             get
    6.             {
    7.                 if (_default == null) _default = new GraphComponents<T>();
    8.                 return _default;
    9.             }
    10.         }
    11.  
    12.       // Maybe something like this.. I have no idea never done it this way
    13.       private static GraphComponents<T> _tile;
    14.         public static GraphComponents<T> TILE
    15.         {
    16.             get
    17.             {
    18.                 if (_tile == null) _tile= new GraphComponents<T>( HexTile th, HexTri htri);
    19.                 ... populate data
    20.                 return _tile;
    21.             }
    22.         }
    23.  
    24. [code]
     
  7. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    A property is really just a way to encapsulate read/ write access to class members. In OOP, this is basically good practice. Object creation (or class/ object instantiation), is the way of bringing about a new 'thing' into being that we can then call on. So, they are unconnected concepts.

    You can, of course, instantiate an object from within a property call. Likewise, you could access a property on an object from within a class constructor.

    The code you have given there is using a singleton pattern (here is another variation).

    This is a much used and familiar pattern; as to whether it is "elegant" or not comes down to personal preference as much as anything. Some people like its simplicity and ease of use, others feel it is little more than a 'glorified global variable'. It can also have limitations regarding polymorphic behaviour.

    By all means, have a play around with it and see how you get on. However, as you have a generic class, you may find that it is incompatible with your usage requirements.

    ---
    Purely out of interest, you may be interested in reading about a few more design patterns here.
     
  8. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Ok makes sense. This was never intended to be a singleton. Thanks again for the help
     
  9. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    OK took a holiday came back only to find this is not working anymore. Any addition eyes on this would be helpful, i can see it :( thanks in advanced

    Error Line 82
    NullReferenceException: Object reference not set to an instance of an objectSystem.Collections.Generic.Dictionary`2[System.Int32,Lightbringer.HexSphereGraphSystem.Tile].get_Item (Int32 key) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:139)

    Code (csharp):
    1.  
    2.     //
    3.     // Interface
    4.     public interface IHexVertex
    5.     {
    6.         HexVert HexVetrex { get; set; }
    7.     }
    8.  
    9.     public interface IHexTriangle
    10.     {
    11.         HexTri HexTriangle { get; set; }
    12.     }
    13.  
    14.  
    15.     //
    16.     // Components
    17.     public class Tile : IHexVertex, IHexTriangle
    18.     {
    19.         private HexVert _hexVertex;
    20.         public HexVert HexVetrex
    21.         {
    22.             get{ return _hexVertex;}
    23.             set{ _hexVertex = value;}
    24.         }
    25.  
    26.         private HexTri _hexTriangle;
    27.         public HexTri HexTriangle
    28.         {
    29.             get { return _hexTriangle; }
    30.             set { _hexTriangle = value; }
    31.         }
    32.     }
    33.  
    34.     //
    35.     //
    36.     public class GraphComponents<T> //where T : Tile
    37.     {
    38.         public T this[int index]
    39.         {
    40.             get { return nodeData[index]; }
    41.             set { nodeData[index] = value; }
    42.         }
    43.  
    44.         public int Count
    45.         {
    46.             get
    47.             {
    48.                 return nodeData.Count;
    49.             }
    50.         }
    51.  
    52.         public class Node
    53.         {
    54.             public Node(T t)
    55.             {
    56.                 data = t;
    57.             }
    58.  
    59.             public T Data
    60.             {
    61.                 get { return data; }
    62.                 set { data = value; }
    63.             }
    64.  
    65.             T data;
    66.         }
    67.  
    68.         Dictionary<int, T> nodeData;
    69.     }
    70.  
    71.   .....
    72.  
    73.     //
    74.     // TEST
    75.     private HexVert[] _hexVerts;  // This is set and working
    76.     ....
    77.    
    78.     GraphComponents<Tile> tl = new GraphComponents<Tile>();
    79.     int max = 10;
    80.     for (int i = 0; i<max; i++)
    81.     {
    82.         tl[i].HexVetrex = _hexVerts[i];
    83.     }
    84.  
    85. [code/]
     
  10. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    I guess _hexVerts is missing, did you debug.log something to find out?
     
  11. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Yea _hexVerts seems fine.
     
  12. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Seems like the problem is on line 40

    Why is
    Code (csharp):
    1.  
    2. tl[i].HexVetrex = _hexVerts[i];;
    3.  
    callng the get in property
    Code (csharp):
    1.  
    2. get { return nodeData[index]; }
    3.  


    should it not be calling the set
    Code (csharp):
    1.  
    2. set { nodeData[index] = value; }
    3.  
     
    Last edited: Apr 10, 2019
  13. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    We can break this into three parts (in order of execution) :-
    1. _hexVerts[i]
      : this is an index read (get) access on
      _hexVerts
      .
    2. tl[i]
      : this is an index read (get) access on
      tl
      .
    3. HexVetrex =
      : this is a write (set) access on
      HexVetrex
      .
     
  14. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Im a bit confused, when is Node instantiated then i run tll[0].HexVetrex =_hexVerts;

    1. //
    2. // Interface
    3. public interface IHexVertex
    4. {
    5. HexVert HexVetrex { get; set; }
    6. }

    7. public interface IHexTriangle
    8. {
    9. HexTri HexTriangle { get; set; }
    10. }


    11. //
    12. // Components
    13. public class Tile : IHexVertex, IHexTriangle
    14. {
    15. private HexVert _hexVertex;
    16. public HexVert HexVetrex
    17. {
    18. get{ return _hexVertex;}
    19. set{ _hexVertex = value;}
    20. }

    21. private HexTri _hexTriangle;
    22. public HexTri HexTriangle
    23. {
    24. get { return _hexTriangle; }
    25. set { _hexTriangle = value; }
    26. }
    27. }

    28. //
    29. //
    30. public class GraphComponents<T> //where T : Tile
    31. {
    32. public T this[int index]
    33. {
    34. get { return nodeData[index]; }
    35. set { nodeData[index] = value; }
    36. }

    37. public int Count
    38. {
    39. get
    40. {
    41. return nodeData.Count;
    42. }
    43. }

    44. public class Node
    45. {
    46. public Node(T t)
    47. {
    48. data = t;
    49. }

    50. public T Data
    51. {
    52. get { return data; }
    53. set { data = value; }
    54. }

    55. T data;
    56. }

    57. Dictionary<int, T> nodeData;
    58. }

    59. .....

    60. //
    61. // TEST
    62. private HexVert[] _hexVerts; // This is set and working
    63. ....
    64. GraphComponents<Tile> tl = new GraphComponents<Tile>();
    65. int max = 10;
    66. for (int i = 0; i<max; i++)
    67. {
    68. tl.HexVetrex = _hexVerts;
      [*] }
      [*]

      [*][code/]

     
    Last edited: Apr 11, 2019
  15. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Sorry, I'm not sure I understand the question, plus the code didn't paste cleanly. Can you restate the question and indicate the code line number(s) that you are referring to.
     
  16. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Sorry about bad post, here it is again in one file as test

    Output:
    52.57308
    UnityEngine.Debug:Log(Object)
    TEST:Start() (at Assets/Scripts/HexSphereGraphSystem/TEST/TEST.cs:39)

    NullReferenceException: Object reference not set to an instance of an object
    System.Collections.Generic.Dictionary`2[System.Int32,Tile].get_Item (Int32 key) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:139)
    GraphComponents`1[Tile].get_Item (Int32 index) (at Assets/Scripts/HexSphereGraphSystem/TEST/TEST.cs:83)
    TEST.Start () (at Assets/Scripts/HexSphereGraphSystem/TEST/TEST.cs:40)

    My question is how should Node class be instantiated (if this is in-face the reason for NullReferenceException), I dont know how this worked previously :( , im so confused

    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class TEST : MonoBehaviour
    7. {
    8.  
    9.  
    10.     private HexSphereBuildManager _hexSphereBuildManager;                
    11.     private HexSphereSystemBuild _hexSphereBuild;                        
    12.     private HexVert[] _hexVerts;                                          
    13.     private HexTri[] _hexTris;                                            
    14.     private int _subdivision;                                            
    15.  
    16.  
    17.     // Use this for initialization
    18.     void Start ()
    19.     {
    20.         //
    21.         // Get reference
    22.         _hexSphereBuildManager = GameObject.FindGameObjectWithTag("tagHexSphereBuildManagerObj").GetComponent<HexSphereBuildManager>();
    23.         if (_hexSphereBuildManager == null)
    24.             throw new InvalidOperationException("Did not find a reference");
    25.  
    26.         //
    27.         // Set data
    28.         _hexSphereBuild = _hexSphereBuildManager.hexSphere;
    29.         _hexVerts = _hexSphereBuild.hexVerticies;
    30.         _hexTris = _hexSphereBuild.hexTriangles;
    31.         _subdivision = _hexSphereBuildManager.subdivisionsCount;
    32.  
    33.         //
    34.         // TEST
    35.         GraphComponents<Tile> tll = new GraphComponents<Tile>();
    36.         int max = 10;
    37.         for (int i = 0; i < max; i++)
    38.         {
    39.             Debug.Log(_hexVerts[i].positionX);
    40.             tll[i].HexVetrex =_hexVerts[i];
    41.             Debug.Log(tll[i].HexVetrex);
    42.         }
    43.     }
    44.  
    45. }
    46.  
    47.  
    48. // Interface
    49. public interface IHexVertex
    50. {
    51.     HexVert HexVetrex { get; set; }
    52. }
    53.  
    54. public interface IHexTriangle
    55. {
    56.     HexTri HexTriangle { get; set; }
    57. }
    58.  
    59. // Components
    60. public class Tile : IHexVertex, IHexTriangle
    61. {
    62.     private HexVert _hexVertex;
    63.     public HexVert HexVetrex
    64.     {
    65.         get { return _hexVertex; }
    66.         set { _hexVertex = value; }
    67.     }
    68.  
    69.     private HexTri _hexTriangle;
    70.     public HexTri HexTriangle
    71.     {
    72.         get { return _hexTriangle; }
    73.         set { _hexTriangle = value; }
    74.     }
    75. }
    76.  
    77. // Method
    78. public class GraphComponents<T> //where T : Tile
    79. {
    80.     Dictionary<int, T> nodeData;
    81.     public T this[int index]
    82.     {
    83.         get { return nodeData[index]; }
    84.         set { nodeData[index] = value; }
    85.     }
    86.  
    87.     public class Node
    88.     {
    89.         public Node(T t)
    90.         {
    91.             data = t;
    92.         }
    93.  
    94.         public T Data
    95.         {
    96.             get { return data; }
    97.             set { data = value; }
    98.         }
    99.  
    100.         T data;
    101.     }
    102. }
    103.  
    104.  
     
  17. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    There is a missing initialisation here :
    Dictionary<int, T> nodeData = new Dictionary<int, T>();
    .

    Another thing I'd recommend is changing the initialisation of
    int max = 10;
    to be
    int max = _hexVerts.Length;
    . This will ensure that you do not run off the end of
    _hexVerts
    with an index out of range exception, or, under use it if it has more than 10 elements.
     
  18. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Thanks for the reply. Ok I fixed the nodeData initialization but im still seeing a KeyNotFoundException.

    KeyNotFoundException: The given key was not present in the dictionary.
    System.Collections.Generic.Dictionary`2[System.Int32,Tile].get_Item (Int32 key) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:150)
    GraphComponents`1[Tile].get_Item (Int32 index) (at Assets/Scripts/HexSphereGraphSystem/TEST/TEST.cs:83)
    TEST.Start () (at Assets/Scripts/HexSphereGraphSystem/TEST/TEST.cs:40)

    My question, is there a way to get
    Code (csharp):
    1.  
    2. tll[i].HexVetrex =_hexVerts[i];
    3.  
    working without adding an Add() . I feel i had this working but maybe not
     
  19. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    The problem is,
    tll
    is not having any values written to it prior to line 40. So the read from the dictionary inside
    GraphComponents
    is failing.
     
  20. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Im sorry I feel dump, I dont understand. Is tll.HexVetrex =_hexVerts; not doing this.
     
  21. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    That would do it but notice that is not the same as line 40. Line 40 has an index accessor on
    tll
    .

    Do you have Visual Studio installed? If not I'd recommend getting it (Community edition is free). Then you can step through this code to see what is happening (just make sure VS is configured to step into properties). That is a really powerful way to follow exactly what is happening and a great way to learn as well.
     
  22. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Im not able to write any values into tll . Ive tried every unholy syntax to man int my :(
     
  23. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    To restate my previous point, I was only suggesting that
    val = someValue;
    will set
    val
    whereas
    val[index].member = someValue;
    will not be setting anything directly on
    val
    but on a member of an object derived from reading an index accessor on
    val
    .

    At this point, maybe it is worth re-asking a couple of previous questions :
    1. Have you digested the meaning of my post at #13?
    2. Have you tried stepping your code through line-by-line in Visual Studio? This will help illustrate the previous point.
    I would strongly recommend trying those. Otherwise, maybe try to reduce the complexity of what you are attempting- you have quite a lot going on here: interfaces, generics, index accessors, dictionaries. Maybe just a simple dictionary, keyed on location Id with a single value type, could work initially? Then build up slowly from there.
     
  24. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    ok you are right Ive lost my way on this one. Ill go back and think about what I need here.

    I did get VS up and running on mac but I could not get the stepping working. But VS is way better that im old IDE thanks for the suggestion
     
    Doug_B likes this.
  25. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    All this stuff will make sense, just keep plugging away at it. I'm sure you'll devise a workable system that is pleasing and suits your needs.

    I use Windows, so afraid can't help you on the Mac front but if you can figure that out, you will find it really helpful and insightful to use. Have fun with it, :)
     
  26. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Ok went back and had a look at how I actually want this to work. I found that I was really trying to do is implement a composite design pattern.

    One thing that I need to do differently is also be able access the Dictionary<int, IComponent> _children without going through the Enumerator loop. Reason for this is I know when a specific tile need to be updated but I dont want to loop through the whole tree structure

    eg
    Code (csharp):
    1.  
    2.             foreach (Composite tilesType in world)
    3.             {
    4.                 foreach (Composite tile in tilesType)
    5.                 {
    6.                     foreach (TileData data in tile)
    7.                     {
    8.                         if(data.Name == "OldBob")data.Name = "Bob"
    9.                     }
    10.                 }
    11.             }
    12.  
    but more like

    Code (csharp):
    1.  
    2. world["TileTypeA"]["TileA0"][0].Name = "Bob";
    3.  
    line 60 // IF I CAN GET THIS TO WORK I WOULD BE HAPPY !!!Debug.Log( world["TileTypeA"]["TileA0"][0].Name ); // Should be TileA0Data0

    Code (csharp):
    1.  
    2. namespace test
    3. {
    4.     public class CompositeStructure : MonoBehaviour
    5.     {
    6.         void Start()
    7.         {
    8.  
    9.             Composite world = new Composite();
    10.             world.Name = "World";
    11.  
    12.             Composite tilesTypeA = new Composite();
    13.             tilesTypeA.Name = "TileTypeA";
    14.             world.Add(tilesTypeA);
    15.  
    16.             Composite tile0 = new Composite();
    17.             tile0.Name = "TileA0";
    18.             tilesTypeA.Add(tile0);
    19.  
    20.             TileData tileA0Data0 = new TileData();
    21.             tileA0Data0.Name = "TileA0Data0";
    22.             tile0.Add(tileA0Data0);
    23.  
    24.             TileData tileA0Data1 = new TileData();
    25.             tileA0Data1.Name = "TileA0Data1";
    26.             tile0.Add(tileA0Data1);
    27.  
    28.  
    29.             Composite tile1 = new Composite();
    30.             tile1.Name = "TileA1";
    31.             tilesTypeA.Add(tile1);
    32.  
    33.             TileData tileA1Data0 = new TileData();
    34.             tileA1Data0.Name = "TileA1Data0";
    35.             tile1.Add(tileA1Data0);
    36.  
    37.             TileData tileA1Data1 = new TileData();
    38.             tileA1Data1.Name = "TileA1Data1";
    39.             tile1.Add(tileA1Data1);
    40.  
    41.             world.Display(25);
    42.  
    43.             foreach (Composite tilesType in world)
    44.             {
    45.                 //Debug.Log(" {0}" + tilesType.Name);
    46.  
    47.                 foreach (Composite tile in tilesType)
    48.                 {
    49.                     //Debug.Log("  {0}" + tile.Name);
    50.  
    51.                     foreach (TileData data in tile)
    52.                     {
    53.                         //Debug.Log("  {0}" + data.Name);
    54.                     }
    55.                 }
    56.             }
    57.  
    58.             //
    59.             // IF I CAN GET THIS TO WORK I WOULD BE HAPPY !!!
    60.             Debug.Log(world["TileTypeA"]["TileA0"][0].Name); // Should be TileA0Data0
    61.  
    62.         }
    63.     }
    64.  
    65.     /// <summary>
    66.     /// Component Interface.
    67.     /// </summary>
    68.     public interface IComponent
    69.     {
    70.         string Name { get; set; }
    71.         void Display(int depth);
    72.  
    73.     }
    74.  
    75.     /// <summary>
    76.     /// Composite.
    77.     /// </summary>
    78.     public class Composite : IComponent, IEnumerable<IComponent>
    79.     {
    80.         #region Fields
    81.  
    82.         private Dictionary<int, IComponent> _children = new Dictionary<int, IComponent>();
    83.         private string _name;
    84.  
    85.         #endregion
    86.  
    87.         #region Properties
    88.  
    89.         public IComponent this[int index]
    90.         {
    91.             get { return _children[index]; }
    92.             set { _children[index] = value; }
    93.         }
    94.  
    95.         //public IComponent this[string name]
    96.         //{
    97.         //    get
    98.         //    {
    99.         //        foreach (var component in _children)
    100.         //        {
    101.         //            if (component.Value.Name == name) return component.Value;
    102.         //        }
    103.         //        return null;
    104.         //    }
    105.         //    //set { _name = value; }
    106.         //}
    107.  
    108.         public Dictionary<int, IComponent> this[string name]
    109.         {
    110.             get
    111.             {
    112.                 ////return this._children[name];
    113.                 //foreach (var component in _children)
    114.                 //{
    115.                 //    if (component.Value.Name == name) return this._children;
    116.                 //}
    117.  
    118.                 foreach (KeyValuePair<int, IComponent> kvp in _children)
    119.                 {
    120.                     if (kvp.Value.Name == name) return this._children ;
    121.                 }
    122.                 return null;
    123.             }
    124.             //set { _name = value; }
    125.         }
    126.  
    127.         public int Count
    128.         {
    129.             get { return _children.Count; }
    130.         }
    131.  
    132.         public string Name
    133.         {
    134.             get { return _name; }
    135.             set { _name = value; }
    136.         }
    137.  
    138.         //public Dictionary<int, IComponent> Children
    139.         //{
    140.         //    get { return _children; }
    141.         //    set { _children = value; }
    142.         //}
    143.  
    144.         #endregion
    145.  
    146.         #region Methods
    147.  
    148.         public void Add(IComponent component)
    149.         {
    150.             int numEntries = _children.Count;
    151.             if (numEntries == 0) { _children.Add(0, component); }
    152.             else { _children.Add(numEntries, component); }
    153.         }
    154.  
    155.         public void RemoveSubordinate(int index)
    156.         {
    157.             _children.Remove(index);
    158.         }
    159.  
    160.         public void Display(int depth)
    161.         {
    162.             Debug.Log(new String('-', depth) + Name);
    163.  
    164.             // Recursively display child nodes
    165.             //foreach (ILeaf component in _children)
    166.             //{
    167.             //    component.Display(depth + 2);
    168.             //}
    169.             foreach (var component in _children)
    170.             {
    171.                 component.Value.Display(depth + 2);
    172.             }
    173.         }
    174.  
    175.         #endregion
    176.  
    177.         #region IEnumerable Interface
    178.  
    179.         public IEnumerator<IComponent> GetEnumerator()
    180.         {
    181.             foreach (KeyValuePair<int, IComponent> kvp in _children)
    182.             {
    183.                 yield return kvp.Value;
    184.             }
    185.         }
    186.  
    187.         IEnumerator IEnumerable.GetEnumerator()
    188.         {
    189.             return GetEnumerator();
    190.         }
    191.  
    192.         #endregion
    193.  
    194.     }
    195.  
    196.     /// <summary>
    197.     /// Component
    198.     /// </summary>
    199.     public class TileData : IComponent
    200.     {
    201.         #region Fields
    202.  
    203.         private string _name;
    204.         public HexVert _hexVertex;
    205.  
    206.         #endregion
    207.  
    208.         #region Properties
    209.  
    210.         public string Name
    211.         {
    212.             get { return _name; }
    213.             set { _name = value; }
    214.         }
    215.         #endregion
    216.  
    217.         # region Methods
    218.  
    219.         public void Display(int depth)
    220.         {
    221.             Debug.Log(new String('-', depth) + Name);
    222.         }
    223.  
    224.         #endregion
    225.     }
    226. }
    227.  
    228.  
    229.  
    230.  
    231.  
     
  27. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    To give you the line you want, you could change your index accessors in
    Composite
    to :
    Code (CSharp):
    1.     public TileData this[int index]
    2.     {
    3.         get { return (TileData)_children[index]; }
    4.         set { _children[index] = value; }
    5.     }
    6.  
    7.     public Composite this[string name]
    8.     {
    9.         get
    10.         {
    11.             foreach (KeyValuePair<int, IComponent> kvp in _children)
    12.             {
    13.                 if (kvp.Value.Name == name) return (Composite)kvp.Value;
    14.             }
    15.             return null;
    16.         }
    17.     }
    However, note that you may experience problems with your implementation of
    void RemoveSubordinate(int index)
    . Think about this sequence:
    • Add new component to world (creates component with key '0')
    • Add new component to world (creates component with key '1')
    • RemoveSubordinate(0)
    • Add new component to world --- what key is generated? So, what should happen now?
     
    RoughSpaghetti3211 likes this.
  28. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Yea this is a disaster waiting to happen , let me go back and think about it