Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Grid Framework [scripting and editor plugins]

Discussion in 'Assets and Asset Store' started by hiphish, Jul 24, 2012.

  1. boni

    boni

    Joined:
    Jan 31, 2013
    Posts:
    4
    Nice! I'll just use my solution for now and adapt it when the next update comes out. :)
     
  2. Taryndactyl

    Taryndactyl

    Joined:
    Jan 26, 2013
    Posts:
    16
    This looks like some seriously awesome work! Although I do have a few questions.

    1. Can my units (hopefully an RTS) move around freely and upon arriving at their destination, then snap to the grid points?
    2. How would I go about setting up a system with this so multiple units could fit in one cell?
    2a. For example if I were to allow each gridbox to hold a value of 5 'GridUnits' (or whatever), and some units take up 2GU and others 3GU or 1GU... is that possible with this?

    Excellent work, I hope to hear from you and maybe look into purchasing!

    EDIT:
    Now that I've watched some of the posted videos I have one more question.

    3. It seems the objects snap to where the axii meet, which would be great in some cases but not in the one I'm thinking of.

    Should I just apply an offset to the location after the units snap, or is there a built-in way for objects to goto the middle of a 'Box/Face'?

    Thanks again.
     
    Last edited: Aug 29, 2013
  3. Devteam ACR

    Devteam ACR

    Joined:
    Aug 7, 2013
    Posts:
    1
    Hi, awesome work you've done here.

    I've a problem with the unit snapping scripts, every simple GameObject that I create, like a cube with just a BoxCollider, snaps just fine but when I try to snap something a bit more complex, a building from the Low Poly City asset for example, it snaps to the vertices instead of the center of the grid cell.

    It seems that I'm not the only one with this problem, is this intended? Then, why the results are different with different GameObjects?

    Thank you very much :)

    EDIT:

    I've tried the HexGrid and the PolarGrid and in both cases the snapping works great.

    I've also tried with an imported 3D model from SketchUp into the RectGrid and the problem remains.
     
    Last edited: Aug 29, 2013
  4. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    grid Framework is a framework, so a lot of things can be done, the questions is just how. I'll go over your individual questions.

    1) Sure, you move them around normally and when you want them to snap you call this:
    Code (csharp):
    1.  
    2. GFGrid myGrid; // the grid we use for reference
    3. myGrid.AlignTransform (trasnform);
    4.  
    There are also more low-level methods if you want control, AlignTransform is built upon those as a kind of common denominator. The point is, you don't have to make your entire game based on grids, just call the math when you need it.

    2) Grids are just a mathematical construct, they don't hold anything and they are infinitely large (as far as infinity is possible in unity of course), so they don't store anything themselves. What you need is some form data structure to hold the information you want, like an array or a list. You can use Grid Framework to build an array automatically:
    Code (csharp):
    1.  
    2. GFGrid myGrid;
    3. int x = Mathf.FloorToInt(myGrid.size.x);
    4. int y = Mathf.FloorToInt(myGrid.size.y);
    5. Type[,] array = new Type[x, y];
    6.  
    Your type would then hold a list of Transforms and a capacity counter. Every time you want to add an entry you do this:
    Code (csharp):
    1.  
    2. void AddEntry (Transform t, int size, int x, int y) {
    3.     if (array[x, y].capacity - size < 0)
    4.         return;
    5.     array[x, y].list.Add (t);
    6.     array.capacity -= size;
    7. }
    8.  
    To get the x and y position inside the array you can again use Grid Framework:
    Code (csharp):
    1.  
    2. int[] GetXY (Transform t) {
    3.     Vector3 gridPos = myGrid.WorldToGrid (t);
    4.     return new int[2] {Mathf.RoundToInt (gridPos.x), Mathf.RoundToInt (gridPos.y)};
    5. }
    6.  
    As you can see GridFramework is not a kit where you just add you idea and get an instant solution, but it's a framework to automatically do the math for converting between world space and grid space. What you can do with the math is limited by your imagination only.

    3) The dafault snapping is just a little convenience feature I built in, but you can build your own convenience features instead. If you want objects to always snap to the centre of a face you need the nearest face:
    Code (csharp):
    1.  
    2. transform.position = myGrid.NearestFaceW (transform.position, GRGrid.GridPlane.XY); // or whatever plane you want
    3.  
    There you go, your very own snapping method. If you know the exact grid coordinate you can also just use those and convert to world space without making use of snapping:
    Code (csharp):
    1.  
    2. transform.position = myGrid.GridToWorld (destination);
    3.  
    Sounds like an issue with size. The default snapping uses size and whether it's even or odd to determine how to snap an object. If a component is even that axis is on an edge (or vertex if both axes are even). If you want more control you can write your own snapping method:
    Code (csharp):
    1.  
    2. void SuperSnapping (Trasnform t, bool central = true) {
    3.     transform.position = central ? myGrid.NearestBoxW(transform.position) : myGrid.NearestVertexW(transform.position);
    4. }
    5.  
    You can throw out the extra check if you want or you can play more with various methods. This only applies to rectangualr grids, polar grids snap both on and between faces and hex grids snap only on faces.
     
  5. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    The Grid Align Panel cannot remember the Grid reference if changing scene. Also the setting is reset after restart the unity editor.
     
  6. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Yes, I know it's really annoying, but I haven't found a way for the panel to remember specific objects of scenes and settings when changing scenes. If anyone knows the relevant part of the API I would be very grateful.
     
  7. YorkshirePudding

    YorkshirePudding

    Joined:
    Apr 10, 2013
    Posts:
    18
    Hi,

    I am wanting a grid system in my game that will allow me to mark grid cells as hurt zones or healing zones from within the editor and read the values back at runtime. Is this possible with this system, can I add spurious attributes to the grid cells within the editor?

    So for instance, it would be good if I could select a cell then enter a string or integer value in the inspector, then at runtime I would iterate over the grid cells and based on the attributes setup some scripts to run when the player enters this grid cell. I don't want to attach behaviours to the cells just readable attributes from with the editor.
     
    Last edited: Sep 13, 2013
  8. LightSky

    LightSky

    Joined:
    Aug 12, 2012
    Posts:
    45
    Does this asset allow for multiple grids to be active at once?
    For example, I want to be able to place and move objects on only certain areas all over the map, so there will be "dead-zones" scattered about. Is there any performance hit(s) for doing it this way?

    Thanks,
    ~LightSky
     
  9. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Not without coding; a grid is just a mathematical construct, it is infinitely large and has certain properties like an origin and spacing (or radius for hex and polar girds). What exactly you do with this construct is up to you, you could use it for a board game or for ingame GUI. in your case you need some sort of structure of points, like a Vector3 array. It could be built something like this:
    Code (csharp):
    1.  
    2. GFGrid myGrid;
    3. Vector3[,] array = new Vector3 [(int)myGrid.size.x, (int)myGrid.size.y];
    4. for (int i = 0; i < (int)myGrid.size.x; i++) {
    5.     for (int i = 0; i < (int)myGrid.size.x; i++) {
    6.         array[i,j] = myGid.GridToWorld (new Vector3 (i, j, 0));
    7.     }
    8. }
    9.  
    Based on that you could then extend the editor with whatever custom features you want. There are also other structure which would perform better than a plain array, but that depends on your specific needs. What you need to keep in mind is that Grid Framework is a framework that does the math for you, you just place a grid somewhere in the scene and then reference it and its methods. However, it is not a solution where you just add water and get instant results. The downside is that you still have to do coding work, but the upside is that its possibilities are nearly limitless. You are not confined to just whatever I had in mind, like you would be with a "kit". It's similar to how Unity itself is a general purpose engine that can be used for nearly any type of game.

    You can have as many grids as you want, just keep in mind that actually rendering them all will affect performance, but their existance won't. One simple way around is to have one large grid to render and several invisible grids for game mechanics. If you want dead zones however it would be easier to work with just one grid and define "forbidden" areas:
    Code (csharp):
    1.  
    2. List<Vector3[,]> forbiddenAreas; // list of forbidden ranges
    3. bool CheckArea (Vector3 pos) {
    4.     bool valid = true;
    5.     foreach (Vector3[,] area in forbiddenAreas) {
    6.         if ( (area[0].x <= pos.x  pos.x <= area[1].x)  (area[0].y <= pos.y  pos.y <= area[1].y)
    7.             valid = false;
    8.     }
    9.     return valid;
    10. }
    11.  
    fobiddenAreas is a list of Vector3 pairs, the first one being the lower left corner of the area and the second one being the upper right corner. Then we check for each area if the target is inside and if not we return true. This is of course open for optimisation, for example there is no need to check all areas when your position is only inside a certain range, but as with the above answer, that depends on your specific case.
     
  10. LightSky

    LightSky

    Joined:
    Aug 12, 2012
    Posts:
    45
    Since you are the creator and know the code the best, would it be possible to simply create a list inside the custom editor for the Grid component to designate which areas (XYZ) are forbidden? If so, will that update in the editor to show which areas are disabled?
     
  11. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I think the easiest way would be to include the list in the grid class itself. Don't change my code, instead inherit from the grid class of your choice. I'll use rectangular grids as an example:
    Code (csharp):
    1.  
    2. public class ExtendedGFRectGrid : GFRectGrid {
    3.     public List<Vector3[,]> forbiddenAreas;
    4.     // extra methods for manipulating the list go here
    5. }
    6.  
    Now you can use the Grid Framework features and the list in one common class. Next thing we need is an inspector so you can see the list in the sidebar. Custom inspectors are created through custom classes, so you can just inherit from my existing class and add the extra inspector GUI code to make the list appear. I don't have it in my head right now, but it would look something like this:
    Code (csharp):
    1.  
    2. ExtendedGFRectGrid target;
    3. bool openFoldout = true;
    4. if (!openFoldout)
    5.     return; // foldout closed, nothing to show
    6. int numberOfEntries = target.forbiddenAreas.Length();
    7.  
    8. for (int i = 0; i < numberOfEntries; i++) {
    9.     // display two Vector3 fields
    10. }
    11.  
     
  12. hype261

    hype261

    Joined:
    May 30, 2013
    Posts:
    6
    All,

    I just purchased your grid framework and noticed that if I have my main camera in perspective mode that the grid will flicker and some lines won't be drawn depending upon the camera position. This is noticeable in the demos. Is there any work around for this issue.

    James
     
  13. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I havent's noticed anything like that. In which examples are you experiencing it? What are your camera settings? What is your screen resolution? What happens if you change the line width? What exactly does the flickering look like (screenshot)? The only "issue" I'm aware of is that if your camera is inside a grid some lines can overlap creating weird visual effects, but that's just how visuals work, nothing unnatural.

     
  14. hype261

    hype261

    Joined:
    May 30, 2013
    Posts:
    6
    Thanks for getting back to me. I have figured out the issue. The issue is Z Fighting. If you have both the grid and a plane on the same gameobject then they share the same depth when it comes time to be renderer, but the graphics card doesn't know which one should be visible so you get some weird artifacts. I fixed the issue by moving the plane and grid to different game objects and offseting the grid a tiny amount in the Y Axis.
     
  15. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    I'm having this message on console, while using debug sphere:

    Code (csharp):
    1. Descrepancy between true world and calculated world: (0.0, 0.0, 0.0) = (2.5, 1.3, -1.4) - (2.5, 1.3, -1.4)
    And without debugging, WorldToGrid and GridToWorld are resulting the same values
     
  16. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    That is as it's intended. Here is the code of the DebugGridToWorld method:
    Code (csharp):
    1.  
    2. Debug.Log("Descrepancy between true world and calculated world: " + (transform.position - theGrid.GridToWorld(theGrid.WorldToGrid(transform.position))) +" = " + transform.position + " - " + theGrid.GridToWorld(theGrid.WorldToGrid(transform.position)));
    3.  
    This method is there to detect if there is any discrepancy between the actual world coordinates (transform.position) and the result you get from converting to grid coordinates and then back to world coordinates (theGrid.GridToWorld(theGrid.WorldToGrid(transform.position)))).

    That happens if your grid has a spacing of (1, 1, 1,), a position of (0, 0, 0) and the identity rotation. In that casegrid coordinates and world coordinates overlap and both are the same.

    OK, that makes sense. Note that you don't have to move the grid to a separate GameObject, you can just add an origin offset, but I don't know if that will help with the Z-fighting.
     
  17. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    Yes I understand that, I noticed after posting it wasn't an error message.

    But, I have tested with my grid on other positions and rotation (haven't changed the scale) with same results. When debugin, I can see the WorldToGrid Vector3 on console, but the GridToWorld doesn't show any Vector3. Am I doing something wrong?
     
  18. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    No, you are doing everything right. The question is, what should I print? For WorldToGrid it's obvious, I print out the grid coordinates and if they match what you see in the scene everthing is alright. However, what should I print out for GridToWorld? I figured it would make sense to print the opposite of what WorldToGrid is printing, but it would be awkward for the user to shift eyes from the consoles to the inspector back and forth; most of the time you don't care about the actual value, you just want to know if there is a difference between the returned value (result of GridToWorld) and the true value (transform.position). That's why I decided to print the discrepancy instead. If the discrepancy is (0, 0, 0) everything is as it should be.

    Of course that's just my opinion, if you have a better idea what I should print, then let me know :)
     
  19. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    Maybe I am not using the whole potential of the plugin. Heres what I'm trying to do. Theres this isometric scene, the user clicks any square then I have to check the neighbours (with Physics Raycast). If there's an object I'll have everything I need with hit.collider.gameObject. If not it's a blank spot, like a montain where nothing should be there. That's why I needed the World Vector3 for the Raycasting...

    Any other way to accomplish this?

    Edit: Got it working, it was my mystaking with the RayCast()

     
    Last edited: Sep 20, 2013
  20. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Does that mean all your questions are answered now or is there still another problem? Just asking to be sure.
     
  21. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    Yes, everything answered! Thank you
     
  22. JohnnyRey

    JohnnyRey

    Joined:
    Jan 26, 2013
    Posts:
    16
    Hiphish,

    I'm having an issue with grid snapping - I'm unable to rotate objects. If I try to move a rotated cube, it automatically resets it's rotation and snaps them to the grid.

    Additionally, can anyone help me use the Movement w/ Forbidden tiles example for the XZ plane vs XY? I can't seem to figure out what needs to be changed, I suspect its in the ForbiddenTilesExample, it only seems to care about XY...but i'm unsure as to have it use XZ

    Thanks!
     
    Last edited: Oct 3, 2013
  23. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    The `GFGrid.AlignTransform` method looks like this:
    Code (csharp):
    1.  
    2. void GFGrid.AlignTransform (Transform theTransform, bool rotate, GFBoolVector3  ignoreAxis)
    3.  
    There are override variants that don't need the `rotate` and `ignoreAxis` parameters. The `rotate` parameter is what decides whether the object will keep it rotation or pick the grid's rotation. By default it is `true`, simply pass `false` in your script. If you want to use the align panel, then you'll have to change the panel's own source code. It's very straight forward and I will include it in the next update, I just hadn't thought of this before. Here is what you have to add: Go to Editor/Grid Framework/GFGridAlignPanel and add the following lines:
    Code (csharp):
    1.  
    2. // line 27, after includeChildren
    3. bool rotateTransform = true;
    4.  
    5. // line 45, after the LayerField method
    6. RotateOptions ();
    7.  
    8. // line 69, after the LayerField method
    9. void RotateOptions () {
    10.     rotateTransform = EditorGUILayout.Toggle ("Rotate to Grid", rotateTransform);
    11. }
    12.  
    13. // and change line 252 from
    14. AlignTransform (child, true);
    15. // to
    16. AlignTransform (child, rotateTransform);
    17.  
    I can send you the complete copy-pasted code if you want, if you don't want to make the changes manually. Once these changes have been applied a new flag fill appear in the panel allowing you to toggle auto-rotation on or off.

    I'll try to explain the idea first: you have a 2D array representing the squares of your grid and you have methods to map grid coordinates to matrix coordinates and matrix coordinates to grid coordinates. This mapping works by using the X and Y coordinates, for example in this method:
    Code (csharp):
    1.  
    2. private static int[] SetMatrixSize(){
    3.     int[] size = new int[2];
    4.     for(int i = 0; i < 2; i++){
    5.         //get the distance between both ends (in world units), divide it by the spacing (to get grid units) and round down to the nearest integer
    6.         size[i] = movementGrid.useCustomRenderRange? Mathf.FloorToInt(Mathf.Abs(movementGrid.renderFrom[i] - movementGrid.renderTo[i]) / movementGrid.spacing[i]):  2 * Mathf.FloorToInt(movementGrid.size[i] / movementGrid.spacing[i]);
    7.     }
    8.     return size;
    9. }
    10.  
    we use the first (X) and second (Y) component of the grid's size for the size of our matrix. In order to use the X and Z component we would need to change this:
    Code (csharp):
    1.  
    2. private static int[] SetMatrixSize(){
    3.     int[] size = new int[2];
    4.    
    5.     size[0] = movementGrid.useCustomRenderRange? Mathf.FloorToInt(Mathf.Abs(movementGrid.renderFrom[0] - movementGrid.renderTo[0]) / movementGrid.spacing[0]): 2 * Mathf.FloorToInt(movementGrid.size[0] / movementGrid.spacing[0]);
    6.     // EDIT: Fell into my own trap, it's supposed to be size[1], not size[2]; see below
    7.     size[1] = movementGrid.useCustomRenderRange? Mathf.FloorToInt(Mathf.Abs(movementGrid.renderFrom[2] - movementGrid.renderTo[2]) / movementGrid.spacing[2]): 2 * Mathf.FloorToInt(movementGrid.size[2] / movementGrid.spacing[2]);
    8.     return size;
    9. }
    10.  
    Now all you have to do is apply this to all methods. Just keep in mind to only change the second coordinate from Y to Z when dealing with the grid, not when dealing with the matrix. For example here:
    Code (csharp):
    1.  
    2. //build a default matrix
    3. allowedTiles = new bool[size[0], size[1]];
    4.  
    it would be wrong to turn the 1 into a 2, because the matrix does not have a third coordinate, its two-dimensional.
     
    Last edited: Oct 4, 2013
  24. JohnnyRey

    JohnnyRey

    Joined:
    Jan 26, 2013
    Posts:
    16
    Wow! What a fantastic answer! Thank you so much! This clears everything up. I really appreciate it.
     
  25. sti4thewin

    sti4thewin

    Joined:
    Apr 21, 2013
    Posts:
    31
    Is this something that i could use for a classic arcade snake game in which i would be able to have a cube move across the grid in certain increments and such?
     
  26. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Grid-based movement was one of the first examples I included, it can be done in different ways:
    Code (csharp):
    1.  
    2. GFRectGrid myGrid; // the grid reference
    3. Transform myCube; // the cube's Transform
    4.  
    5. // use a direction
    6. myCube.Translate (myGrid.right);
    7. // or use the grid coordiantes of a destination
    8. Vector3 targetCoords;
    9. myCube.position = myGrid.GridToWorld (targetCoords);
    10. // of course you will want to use smooth movement instead of just teleporting your cube, but let's keep things simple
    11.  
    You simply write your game logic in grid coordinates and Grid Framework translates it to world coordinates, either a point or a direction. You will probably want to limit how far your cube can be moved, this has to be done in code explicitly, because all grids are infinitely large. Here is a simple way:
    Code (csharp):
    1.  
    2. // bounds in grid coordinates
    3. Vector3 lowerGridBound;
    4. Vector3 upperGridBound;
    5. // bounds in world coordiantes
    6. Vector3 upperBound = myGrid.GridToWorld (upperGridBound);
    7. Vector3 lowerBound = myGrid.GridToWorld (lowerGridBound);
    8.  
    9. //clamp the position
    10. myCube.position = Vector3.Max (Vector3.Min (myCube.position, upperBound), lowerBound);
    11.  
    There are other ways as well, this is just a quick and simple demonstration.
     
  27. sti4thewin

    sti4thewin

    Joined:
    Apr 21, 2013
    Posts:
    31
    Ahhhhh exactly what I need. Thanks!
     
  28. sti4thewin

    sti4thewin

    Joined:
    Apr 21, 2013
    Posts:
    31
    I sent you a PM. I think I might of figured it out but would like your input.
     
  29. Mixality_KrankyBoy

    Mixality_KrankyBoy

    Joined:
    Mar 27, 2009
    Posts:
    737
    Hiphish,

    I am working on a Might and Magic type 1st person turn based (grid based) RPG. Would your tool help in the movement/pathfinding aspects of the game? Can it do avoidance for path selection and handle 3D grids (where the enemies/player move smoothly over the terrain (Y)?
     
  30. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I think what you mean is you want to have an uneven terrain with bumps and dents and then smoothly fit a grid on top of it, right? This is more complicated, because Grid Framework grids are flat grids placed on top of each other like layers (think like honeycombs in on of those bee boxes). It would be possible to place a grid somewhere onto the terrain and use it to get the X and Z coordinate and then derive the Y coordinate from the height of the terrain independently. The other problem is drawing the grid, this is outside of Grid Framework's scope. There are many topics on drawing a grid onto the terrain in the forums and on Unity Answers; Grid Framework can at least help you calculate the vertices of such a grid, but the rest is up to you. Here is an example:
    Code (csharp):
    1.  
    2. GFGrid myGrid; // the grid you want to use
    3. int width;
    4. int height;
    5. Vector3[] vertices = new Vector3[width * height];
    6.  
    7. int counter = 0;
    8. for (int i = 0; i < width; i ++) {
    9.     for (int j = 0; j < height; j ++) {
    10.         vertices[counter] = myGrid.GridToWorld (i, 0, j); // convert grid coordinates to world coordinates
    11.         counter ++;
    12.     }
    13. }
    14.  
    The rest is then up to you, I'm afraid. Pathfinding and aviodance are unfortunately not part of Grid Framework yet, I intend to deliver that feature eventually, but not yet, I'm currently working on Playmaker support. You'll have to use your own solution or a premade one, but at least Grid Framework can help you with finding the node coordinates of the grid, similarly to the above.
     
  31. Fuzzypup

    Fuzzypup

    Joined:
    Aug 13, 2013
    Posts:
    190
    Is there a way to email you? I work for a small game company going to mobile for its game and I am interested in your software. I need to know if it will work for what we do. We have a classic top down 2d large board strategy game that we are trying to implement in a certain way.
     
  32. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Hi, I prefer communication over the forums, either in this thread or via PM if you don't want information to be public. It is easier to talk about coding that way because the forum software will format and syntax highlight code snippets. Ask me your questions and I'll aswer them as best as I can.
     
  33. Fuzzypup

    Fuzzypup

    Joined:
    Aug 13, 2013
    Posts:
    190
    Ok. I am a game designer now asked to be programmer. I work for a company that makes old fashion top down 2d strategy games with LARGE maps of hexes. They want to move to mobile so I am learning Unity and picked up C#. With that said I am not an expert programmer.

    Some of our maps can be 512x256. What makes the game unique is that you can mod it. Its quite a good engine.

    So some of the Unity resources I found use 1 object per hex tile which wont work for us. I tried to do a single mesh per layer trying to insert our bitmaps per tile from a data stream, that didn't work because the transparent part of the hex time writes over a portion of previously created tiles due to the nature of how Unity inserts square textures. I need a mesh of hexes I can dump bitmaps of terrains, roads, rivers, cities, oil, mines, and units into. Most strategy games of this type basically put a bitmap map in the background of the play field. We are trying to avoid that and I know Unity has a limit on the size of a bitmap.

    So I have been looking at the products out there on the asset store and yours came up. I need a hex system that is a mesh that I can insert my bitmap image of my layers into.

    This is pre-alpha. The map is missing rivers, roads, rail, terrain, resources like cities mines and oil.
    http://www.google.com/imgres?imgurl...a=X&ei=XaJcUsziEKTAigLl54CoBA&ved=0CDIQ9QEwAg

    It pulls all the tiles from one large bitmap per type. I would be pulling game data from a game file and inserting the data onto the map one by one till its filled matching tile type to the bitmap. In unity I would hope to move the camera around the large board. I can use objects for pieces. I cant use single objects for the hex tiles because there are way too many hex tiles per map.

    I believe I will have to create several layered meshes in an orthographic camera for all the tile features.

    Can your software do what I need?
     
    Last edited: Oct 15, 2013
  34. DonJaket

    DonJaket

    Joined:
    Oct 14, 2013
    Posts:
    10
    Hey there,

    Your package looks really good!
    Does this follow the structure of the terrain in height? Moutains, valleys, etc?
    Is it possible to draw lines on the grid, "civilization" style?

    Thanks
     
  35. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I'll reply to each of you individually
    Let me first explain the core idea behind Grid Framework's design: instead of being a "kit" where you just add your own graphics and set a few variables it is a general purpose framework. This means you will still have to do programing work, but in return you are not limited to a specific purpose. Grid Framework has been used for gameplay, GUI, level design, rendering grids, an editor extension and even to replace Unity's built-in physics with something simpler and tighter. Grid Framework's main purpose is in doing the math for you. You don't have to worry about converting world coordinates to grid coordinates or designing your own coordinate systems, you simply use the API for it.

    First of all, the size of the grid is no issue as far as rendering is concerned. All grids are infinitely large and the rendering is just a visual representation of a certain area. A very large grid can be expensive to render because of all the vertices (end points of line segments), but you only need to render the area that's visible to the player. There is an example included where I use the camera's view port to calculate the bounds of the rendering. Here is the relevant snippet, it is really simple:
    Code (csharp):
    1.  
    2. //how much buffer do we want to use? More buffer means more to render each time, but less frequent recalculations
    3. public float buffer = 10.0f;
    4.  
    5. void Update () {
    6.         HandleMovement(); // first move the grid
    7.        
    8.         // if we exceeded the buffer limit let's recalculate the points for rendering
    9.         if (Mathf.Abs(_transform.position.x - _lastPosition.x) >= buffer || Mathf.Abs(_transform.position.y - _lastPosition.y) >= buffer)
    10.             ResizeGrid();
    11.     }
    12.    
    13.     void ResizeGrid () {
    14.         Vector3 rangeShift = Vector3.zero; // we can't manipulate the individual components of renderFrom/To directly so use a temp variable
    15.         for (int i = 0; i < 2; i++) {
    16.             rangeShift[i] += _transform.position[i] - _lastPosition[i]; // use the difference in positions for the shift
    17.         }
    18.        
    19.         myGrid.renderFrom += rangeShift; // now add the shift to both values
    20.         myGrid.renderTo += rangeShift;
    21.        
    22.         _lastPosition = _transform.position; // save this current position as the new last fixed point
    23.     }
    24.  
    Moving on, Grid Framework does not create meshes, instead a grid is just a component with certain properties (like for example a collider, which is just a set of coordinates). You can still use it to create a mesh, to get the vertices simply iterate over a vertain area:
    Code (csharp):
    1.  
    2. int[] lowerBound = new int[2];
    3. int[] upperBound = new int[2];
    4. Vector3[] vertices = new Vector3[ (upperBound[0] - lowerBound[0]) * (upperBound[1] - lowerBound[1]) ];
    5. GFHexGrid myGrid;
    6.  
    7. int counter = 0;
    8. for (int i = lowerBound[0]; i < upperBound[0]; i++) {
    9.     for (int j = lowerBound[0]; j < upperBound[0]; j++) {
    10.         vertices[counter] = transform.InverseTransformPoint(myGrid.GridToWorld( new Vector3 (i, j, 0) ) );
    11.         counter++;
    12.     }
    13. }
    14.  
    Creating a mesh for just one hex is even simpler, because the mesh is always the same and depends on the the radius of the grid's hexes:
    Code (csharp):
    1.  
    2. Vector3[] vertices = new Vector3[6];
    3. for (int i = 0; i < 6; i ++) {
    4.     vertices[i] = new Vector3 ( Mathf.Cos(60.0 * i) * myGrid.radius, Mathf.Sin(60.0 * i) * myGrid.radius ):
    5. }
    6.  
    However, keep in mind that such a mesh would be huge for such a large map. it gets even worse if you want each of the hexes to be its own mesh with its own material, because then the engine can't batch it into one draw call. it would be best to have a pool of tesxtures for the hexes and one large rectangualr mesh made out of only four vertices and two triangles for the playing field. The field would have only one large texture that is created by sticking the small hex textures onto it. Imagine a large piece of cardboard with stickers attached to it. What i think yu need to do in order to avoid the transparency overwriting neighbouring hexes is get the pixels of the area your sticker will cover (using GetPixels to get an array of colours), then get the pixels of the sticker (same method), then combine those two arrays into a new array where the new colour overwrite the old one only if its alpha is greater than 1:
    Code (csharp):
    1.  
    2. Color[] area;
    3. Color[] sticker;
    4. int length = area.Length; // same as sticker.Length
    5. Color[] patch = new Color[area.Length];
    6. for (int i = 0; i < length; i++) {
    7.     patch[i] = sticker[i].a == 1 ? sticker[i] : area[i];
    8. }
    9.  
    Then apply the patch to your board, not the sticker. There are probably more advanced methods out thate that can handle partial transparency as well. As for texture size limits, as far as i know the limit is 4096x4096 pixels, so one board might not be enough. Still, it's better to have several large boards than many more individual smaller hexes.

    Anyway, gameplay logic on the other hand should not be hampered by size. As I mentioned before, all grids are infinitely large, but they can't store anything inside them. What I would do is construct some sort of map structure for the game, like an array or something more fancy like a kd-tree, and do my game logic in that system and use Grid Framework to translate between model and world back and forth.
    Let's say we use a 2D array. The coordinate inside the array corresponds to a certain position in the grid, which corresponds to a position in the world. If we want to move a unit from position (2, 5) to (2, 6) the code would then look like this:
    Code (csharp):
    1.  
    2. Transform[] myObjects; // where you store the units
    3. int[] startCoordinate = new int[] {2, 5};
    4. int[] endCoordinate = new int[] {2, 5};
    5.  
    6. Vector3 startPos = myGird.GridToWorld( startCoordinate[0], startCoordinate[1] );
    7. Vector3 endPos = myGird.GridToWorld( endCoordinate[0], endCoordinate[1] );
    8. myObjects[index].Move (startPos, endPos);
    9.  
    This is a very simplified example, but it shows how Grid Framework acts as the "glue" between the game's simulation world and Unity's display world. You just concentrate on your game and let Grid Framework translate the result.

    I'm afraid it won't follow the smooth structure of terrain, if you look back a few posts, I gave a few ideas how this can be achieved, but it is outside the scope for Grid Framework, which aims to be a toll that does the math for you. I might come up with a concrete solution sone time in the future, but even then it will be just and example or an extra, not a core feature.
    I'm not sure what you mean with "lines on the grid", do you mean something like the red line in this screenshot?
    http://www.gallien.org/serendipity/uploads/civilization5.jpg
    That is possible, such a line is basically just a sequence of points. There is nothing built in for drawing, you will either have to write your own solution or use something like Vectrosity. Getting the points will take coding effort as well, you must somehow tell the computer hat points you want to use, but once you know the grid coordiantes it's easy to trasnlate them to world coordinates:
    Code (csharp):
    1.  
    2. GFGrid myGrid;
    3. Vector3[] gridCoordinates;
    4. int length = gridCoordinates.Length;
    5. Vector3[] worldCoordinates = new Vector3[length];
    6. for (int i = 0; i < length; i++) {
    7.     worldCoordinates[i] = myGrid.GridToWorld(gridCoordinates[i]);
    8. }
    9.  
     
  36. Reed

    Reed

    Joined:
    Jan 30, 2013
    Posts:
    3
    Hi hiphish,

    Great framework!

    I've been having problems with getting spacing to work with NearestBoxG(), though. When I have spacing x/y set to 1,1 it works perfectly. But when spacing x/y to 2,2 it doesn't return the correct box.

    Here's the code:
    Code (csharp):
    1.    
    2.     private void movePlayer(Vector3 dir) {
    3.                 Debug.Log (grid.WorldToGrid(cachedTransform.position + dir));
    4.         CheckForStructure(grid.WorldToGrid(cachedTransform.position + dir));
    5.  
    6.         if (OutsideRange(grid.WorldToGrid(cachedTransform.position + dir))) {
    7.             return;
    8.         }
    9.        
    10.         cachedTransform.position = cachedTransform.position + dir;
    11.     }
    12.    
    13.     private int[] GetSquare(Vector3 vec){
    14.         int[] square = new int [2];
    15.         for(int i = 0; i < 2; i++){
    16.             square[i] = Mathf.FloorToInt(grid.NearestBoxG(vec)[i]) - originSquare[i];
    17.         }
    18.         return square;
    19.     }
    20.    
    21.     private void CheckForStructure (Vector3 pos) {
    22.         int[] gridLoc = GetSquare(pos);
    23.                
    24.         Debug.Log (gridLoc[0]+","+gridLoc[1]);
    25.     }
    26.  
    Screenshots attached of the two versions running in Unity. Note that the WorldtoGrid coords (shown in the debug output) are the same in both versions, but the square that gets returned is different. When spacing is set to 2, I have to move two grid spaces before the NearestBoxG() changes. And the max x square/grid position it turns is 5 instead of 11.

    SPACING TO 1,1
    $spacing1.png
    Here the bottom right corner returns the square 11,0.

    SPACING TO 2,2
    $spacing2.png
    Here the bottom right corner returns the square 5,0.
     
    Last edited: Oct 15, 2013
  37. Fuzzypup

    Fuzzypup

    Joined:
    Aug 13, 2013
    Posts:
    190
    Your product seems to what I want because I like control, but I fear my Unity and programming skills are not up to the task.

    I will have to think about this one. Easy he says.
     
  38. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I think I've got it: NearestBoxG takes in a position in world coordinates, but what you passed to CheckForStructure was in grid coordinates. The documentation for NearestBoxG says:
    If your point is already in grid coordinates you simply need to round the idividual components:
    Code (csharp):
    1.  
    2. Vector3 gridPoint;
    3. Vector3 roundedPoint = new Vector3 (Mathf.FloorToInt(gridPoint.x), Mathf.FloorToInt(gridPoint.z), Mathf.FloorToInt(gridPoint.y));
    4.  
    or whatever other type of rounding you whish. NearestBoxG is intended if you have a point in world space and want to jump to grid space immediately and then round to the nearest box. It actually just combines the two steps into one.

    Well, it is easy if you already are a programer ;) This is something that mostly comes from experience and always learning new things. Grid Framework was mainly intended for people who already know how to program, but don't want to get into the math details behind grids. There are a few "kit" solutions out there, but I wanted my library to be different, not a kit but a framework, because with kits you are limited to what the designer intended. This is simply the price one has to pay for more control and freedom.
     
  39. Reed

    Reed

    Joined:
    Jan 30, 2013
    Posts:
    3
    Thanks! That was a big part of the problem. Another bug was that the SetOriginSquare() function from the "Movement with Walls" example wasn't taking spacing into account.

    From ForbiddenTilesExample.cs
    Code (csharp):
    1.  
    2.     public static void SetOriginSquare(){
    3.         //get the grid coordinates of the box (see GetBoxCoordinates in documentation); we get three coordinates, but we only use X and Y
    4.         //we add 0.1f * Vector3.one to avoid unexpected behaviour for edge cases dues to rounding and float (in)accuracy, we subtract 0.5f * Vector3.one to get whole numbers
    5.         Vector3 box = movementGrid.useCustomRenderRange? movementGrid.NearestBoxG(movementGrid.transform.position + movementGrid.renderFrom + 0.1f * Vector3.one) - 0.5f * Vector3.one:
    6.             movementGrid.NearestBoxG(movementGrid.transform.position - movementGrid.size + 0.1f * Vector3.one) - 0.5f * Vector3.one;
    7.         originSquare = new int[2]{Mathf.RoundToInt(box.x), Mathf.RoundToInt(box.y)};
    8.     }
    9.  
    I changed the last line to this, and that fixes it if the grid size uses even numbers.

    Code (csharp):
    1.  
    2.         originSquare = new int[2]{Mathf.RoundToInt(box.x * grid.spacing.x), Mathf.RoundToInt(box.y * grid.spacing.y)};
    3.  
    But there's still a problem if the grid size is changed to any odd number. 6x4, 4x4, etc works. But 5x4 or 6x3 doesn't. It also breaks if the grid is offset at all. How should I refactor this so the grid can be scaled and offset?
     
    Last edited: Oct 16, 2013
  40. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    The problem lies in that you are fixing the square, but not what the square is made of. You should change the box variable instead:
    Code (csharp):
    1.  
    2. Vector3 box = movementGrid.useCustomRenderRange ? movementGrid.NearestBoxG (movementGrid.transform.position + Vector3.Scale(movementGrid.renderFrom, movementGrid.spacing) + 0.1f * Vector3.one) - 0.5f * Vector3.one :
    3.  movementGrid.NearestBoxG (movementGrid.transform.position - Vector3.Scale(movementGrid.size, movementGrid.spacing) + 0.1f * Vector3.one) - 0.5f * Vector3.one;
    4.  
    This multiplies the size (or renderFrom, whichever you use) with the spacing, moving the box properly into the lower left corner. You should delete the part of the code you are not using, keep the code simple.
     
  41. Reed

    Reed

    Joined:
    Jan 30, 2013
    Posts:
    3
    Thanks again, that did the trick.

    And then to resolve the offset I just added + grid.originOffset to it:

    Code (csharp):
    1. grid.NearestBoxG(grid.transform.position + grid.originOffset - Vector3.Scale(grid.size, grid.spacing) + 0.1f * Vector3.one) - 0.5f * Vector3.one;
    Now it's working with any grid size, scale or offset!
     
  42. Geoquav

    Geoquav

    Joined:
    Nov 1, 2013
    Posts:
    2
    Hiphish,

    I see you mentioned getting Playmaker functionality was your current project you are working on. Can you give us an estimate when you think it will be available?
     
  43. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I don't like giving an ETA, but about the middle of November seems like a likely candidate. I never used Playmaker, so I don't know what kind of actions people would want to have. Obviously you'll want to set and get values and call the API methods, but is there anything else?
     
  44. Geoquav

    Geoquav

    Joined:
    Nov 1, 2013
    Posts:
    2
    I personally want to be able to do anything from Snapping to Movement through Playmaker. I am not much of a programmer and don't want to dive too far into the code, if at all. Is this feasible?
     
  45. CBMUN

    CBMUN

    Joined:
    Nov 8, 2013
    Posts:
    2
    hiphish

    Hi, I bought your grid framework
    I'm currently implementing mobile games, using your grid framework.

    And i have a problem - I make games, using "snapping example", and when I build it on mobile,

    there is no touch reaction.(driving me crazy!!)

    I modified GFGrid's AlignTransform for object rotation.I hope you to give advice how coding should be added on snapping example to solve this problem.

    Thank you

    PS. Please send full-source if you are ok. lovelycbm@naver.com
     
    Last edited: Nov 8, 2013
  46. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    If you take a look at the example you will see the following:
    Code (csharp):
    1.  
    2. void OnMouseDown(){
    3.     ...
    4. }
    5. void OnMouseUp(){
    6.     ...
    7. }
    8.  
    Since there is no mouse on touch devices these methods are never called. Here is the Unity documentation for OnMouseDown:
    http://docs.unity3d.com/Documentation/ScriptReference/MonoBehaviour.OnMouseDown.html
    These examples are not intended to be copy&paste ready solutions, they are just examples demonstrating how GridFramework can be used. I will usually use the easiest to write implementation for things that aren't related to Grid Framework, because that's not the focus of the example. I could have
    come up with some really cool universal input handler, but that would just clutter the code and draw attention away from the actual focus of the example: how to make the blocks snap.

    Please don't modify the code of Grid Framework. When I release an update all your changes will be overwritten and you'll have to apply them all over again. There is a chapter in the user manual about extending Grid Framework without changing the code, that way your custom method will remain preserved. What you need is an extension method: you write your method in a script and hook it up to Grid Framework, then you can use it as if it were part of the Grid Framework API.
     
  47. Carwashh

    Carwashh

    Joined:
    Jul 28, 2012
    Posts:
    760
    Hi Hiphish,

    I'm in need of your assistance again!

    I'm afraid I'm new to Unity and still learning lots, I've updated from GF 1.2.4-ish to the latest version on the Asset store (1.3.4) and I now get an error. What have I done wrong? :(

     
  48. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    The error "IndexOutOfRangeException: Array index is out of range." means that you are trying to access more entries of an array than it has. The GFBoolVector3 class is similar to Unity's Vector3, except instead of three float numbers it has three booleans. You will get that error if you try something like this:
    Code (csharp):
    1.  
    2. GFBoolVector3 vec = new GFBoolVector3.true; // an all-true vector
    3. Debug.Log (vec[3]); // print the fourth entry of the vector
    4.  
    In Grid Framework this class is used in order to toggle settings like which axes to render and which to ignore. In previous versions if you tried this your request would simply be ignored, which was wrong behaviour. Now an exception will be thrown, as it should. Chances are that there was something wrong in the code but the program simply ignored the bug instead of throwing the exception. If I were to take a blind guess your code could look something like this:
    Code (csharp):
    1.  
    2. for (int i = 0; i <= 3; i++)
    3.     DoSomething (vec[i]);
    4.  
    i.e. the loop does one iteration too much. Double-clicking the error message should take you right to the offending line of code; from the last line of the error it looks like the offender is an OnGUI method.
     
    Last edited: Nov 12, 2013
  49. Carwashh

    Carwashh

    Joined:
    Jul 28, 2012
    Posts:
    760
    Thanks for the help. Whilst following your help and trying to figure it out, I've found that the GFRect Grid component was missing everything under "Axis Colors" in the inspector. Removed it and added a new on, and that's fixed everything.

    Didn't think to check this after updating.

    thanks again.
     
    Last edited: Nov 12, 2013
  50. AndreyD

    AndreyD

    Joined:
    Oct 8, 2013
    Posts:
    8
    Hey hiphish,

    Great framework, love using it. It looks like a couple of the example scenes that are provided exhibit the array out of bounds exception. While it doesn't break things that we are creating, we can't use the examples in our code. Are you aware of these issues?

    Thanks a lot.