Search Unity

Random positions on hex grid around one vector

Discussion in '2D' started by Karwoch, Sep 16, 2014.

  1. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    I`m not so good at math as I would like to be, so I need a little help ;). What I need is to randomly generate positions (Vector2) around one position (also Vector2) in certain distance - four hexes around - as it is shown on this image:
    https://dl.dropboxusercontent.com/u/52159221/HexGridPaintedPrzykladNaForum.jpg

    For now I create a random array of Vector2 in non normalized hex grid, but in that case in corners objects lands far to far that I want. I appriciate any help :)
     
  2. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    If it didn't have to be a hex shape, I'd say just do a circle and then convert it to a tile... but to do hex shape I think I'd create a random number from 0 to how many tiles are within that area, then just convert that to a row/column number.
     
  3. secondbreakfast

    secondbreakfast

    Joined:
    Jan 5, 2013
    Posts:
    98
    It looks to me like you can just walk four cells in every direction systematically starting 0 left and 4 down, then 1 left and 3 down, then 2 left and 2 down etc. Grab all those cells and you should have your shape.
     
  4. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    *imaginaryhuman Yes, for now it is the only way known to me to do it, but I hoped it could be a little more universal - this method assumes 4 hex distance from center always, plus writing it will be somewhat long in codeing.

    *secondbreakfast, do You mean from 4,4, to 4,0 / from 4,4 to 8,0 etc. ? I have to admit - I don`t understand exacly what You mean :)
     
  5. secondbreakfast

    secondbreakfast

    Joined:
    Jan 5, 2013
    Posts:
    98
    I'll try to explain better. There will be multiple loops to go through. There are a few ways to systematically do it, but here is one way. We will cover the diamond of tiles to the left of the center, then the diamond to the right of the center, then the triangle on top, then the triangle on bottom.

    For the diamond shapes:
    Start at 4,4 and then we'll move left and up-left with a max of 4 collecting all the tiles along the way

    outer loop starts here
    Move left 1 times that leaves you at 4,3
    inner loop for moving up-left starts here
    Move up-left again that you at 3,3
    Move up-left again that you at 2,3
    Move up-left again that you at 1,3
    We're at the max of 4 now so we're done with the inner loop
    Continue at the position where we left before we started going up-left
    inner loop for moving down-left starts here
    ...do the same, but going downward. 5,2 then 6,1 then 7,0
    Continue at the position where we left before we started going down-left
    Move left 1 time that leaves you at 4,2
    inner loop for moving up-left starts here
    Move up-left again that you at 3,2
    Move up-left again that you at 2,2
    Continue at the position where we left before we started going up-left
    Move left 1 time that leaves you at 4,1
    Move up-left again that you at 3,1
    Continue at the position where we left before we started going up-left
    Move left 1 time that leaves you at 4,0

    The right side diamond would be the opposite.

    For the triangle shapes you want to move up-left starting at 4,4 then go up-right on each iteration similar to the diamond

    Here's some pseudocode for the left side diamond:
    //go left
    for (a=1; a <= 4; a++) {
    //go up-left
    for (b=0; b <= 4-a; b++) {
    get tile left "a" spaces and up-left "b" spaces
    }
    //go down-left
    for (b=1; b <= 4-a-1; b++) {
    get tile left "a" spaces and down-left "b" spaces
    }
    }

    Here's some pseudocode for the upper side triangle:
    //go up-left
    for (a=0; a <= 4; a++) {
    //go up-right
    for (b=0; b <= 4-a; b++) {
    get tile up-left "a" spaces and up-right "b" spaces
    }
    }


    //repeat those for the right diamond and bottom triangle and you have then walked over every tile
     
  6. SpacemanBoots

    SpacemanBoots

    Joined:
    Nov 27, 2012
    Posts:
    32
    I think an easy way would be to take a square that fits your hexagon, generate a vector2 in that square and then just regenerate if you fall in 1 of the 2 corners that don't fall in the hexagon.

    In the case of the image you posted your square would run from ( 0, 0 ) to ( 8, 8 ).

    So just normalize that and what you have is ( -diameter, -diameter ) to ( diameter, diameter ).

    So what you can do to see if your vector2 falls in one of the corners. You can add the coordinates and the result should be no smaller then -diameter and no bigger then +diameter.

    And that's it. Should be a tiny piece of code.
     
  7. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    Thank You very much :) Seconbreakefast I`ll try to build a code on this, as it is understable enought for me and easy to implement althought little time consumeing ;) But it should work perfectly! :)

    SpacemanBoots, there is a bit of problem with this - it is same as imaginaryhuman sad - to generate array of all hexes and from it (because You have to do it anyway to know witch ones aren`t on square) and than get random value.
     
  8. SpacemanBoots

    SpacemanBoots

    Joined:
    Nov 27, 2012
    Posts:
    32
    I don't know what this means... You don't have to generate an array.

    Like I said, you only have to generate a number that's in between ( -diameter, -diameter ) and ( diameter, diameter ).
    So that's something like:
    Code (CSharp):
    1. new Vector2( Random.Range( -diameter, diameter+1 ), Random.Range( -diameter, diameter+1 ) );
    There is no generating of arrays involved.
     
  9. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    Yes, but how will You know witch Vector2 are out of area? I mean without array :)
     
  10. SpacemanBoots

    SpacemanBoots

    Joined:
    Nov 27, 2012
    Posts:
    32
    So in the hex is, coord.x + coord.y <= diameter AND >= -diameter.
     
  11. emilianop

    emilianop

    Joined:
    Aug 16, 2014
    Posts:
    28
    Can you retrieve the center of each hex given it's x,y coordinates?
    If so I'd just write a small function that returns all the neighbouring cells, something pseudo-like this:

    Code (Pseudo):
    1. findNeighbours(x,y)
    2. {
    3.   return new int[12] {
    4.             x-1, y,
    5.             x-1, y+1,
    6.             x, y+1,
    7.             x+1, y,
    8.             x+1, y-1,
    9.             x, y-1};
    10. }
    11.  
    Where each n entry is the X of a cell and each n+1 is the Y index.
    Then iteratively call the function for how many "steps" you're allowed to travel (from your example it seems like it's 4) and append results to some main array.
    The final array (cleaned of duplicates) should encompass the area you're looking for, so you can just pick a random number in the range [0:array.Length/2].

    Makes sense?
     
  12. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    I finally did it - I`ve created method witch calculates all positions around point, if anyone need it, here it is:

    Code (CSharp):
    1.     public static List<Vector2> hexAroundPoint2d(Vector2 point,int distanceFromCenter)
    2.     {
    3.         List<Vector2> tablicaVec = new List<Vector2>();
    4.         for (int i = 0;i<=distanceFromCenter;i++)
    5.         {
    6.             for (int j = 1;j<= i;j++)
    7.             {
    8.                 tablicaVec.Add(new Vector2(point.x - i + j,point.y - j));
    9.             }
    10.         }
    11.  
    12.         for (int i = 1;i<=distanceFromCenter;i++)
    13.         {
    14.             for (int j = 1;j<= i;j++)
    15.             {
    16.                 tablicaVec.Add(new Vector2(point.x + j,point.y - i));
    17.             }
    18.         }
    19.  
    20.         for (int i = 1;i<=distanceFromCenter;i++)
    21.         {
    22.             for (int j = 1;j<= i;j++)
    23.             {
    24.                 tablicaVec.Add(new Vector2(point.x + i,point.y - i + j));
    25.             }
    26.         }
    27.  
    28.         for (int i = 1;i<=distanceFromCenter;i++)
    29.         {
    30.             for (int j = 1;j<= i;j++)
    31.             {
    32.                 tablicaVec.Add(new Vector2(point.x + i - j,point.y + j));
    33.             }
    34.         }
    35.  
    36.         for (int i = 1;i<=distanceFromCenter;i++)
    37.         {
    38.             for (int j = 1;j<= i;j++)
    39.             {
    40.                 tablicaVec.Add(new Vector2(point.x - j,point.y + i));
    41.             }
    42.         }
    43.  
    44.         for (int i = 1;i<=distanceFromCenter;i++)
    45.         {
    46.             for (int j = 1;j<= i;j++)
    47.             {
    48.                 tablicaVec.Add(new Vector2(point.x - i,point.y + i - j));
    49.             }
    50.         }
    51.  
    52.         return tablicaVec;
    53.     }
     
    Last edited: Oct 12, 2014
  13. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    It is very interesting solution! It works definetly, but it takes some of cpu time if numbers are higher. But it made me thinking, and finally I found right solution, so thank You :)
     
    emilianop likes this.
  14. SpacemanBoots

    SpacemanBoots

    Joined:
    Nov 27, 2012
    Posts:
    32
  15. Karwoch

    Karwoch

    Joined:
    Sep 16, 2014
    Posts:
    111
    Right, thank You, changes are done :)