Search Unity

Grid Framework [scripting and editor plugins]

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

  1. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Grid Framework version 1.3.0 has been approved by the Asset Store team. The biggest features of this release is the addition of polar grids. Check out the updated included examples to see them right in action. Notice how in the lights-out example the coordinates wrap around, maning that once you've exceeded the maximum angle it start from the beginning again without you having to worry about anything.
    Even if you prefer the good old rectangular- and hex grids you'll want to take a look at the updated API: You can now get the direction vectors for up, forwarad and right or north, north-east, east, south-east and so on just by calling one command. This will make grid-based movement much easier, since you don't have to convert back and forth between grid- and world space anymore.
    On top of that the lights-out and the runtime snapping example showcase how to dynamially generate meshes from grids. The tiles of the polar lights game are all individual meshes that fit exactly inside the idividual faces. When the game starts the attached script runs a loop that runs through the grid and creates the needed vertices and triangles and then assigns the proper materials.

    Here is the full changelog:

    • added up, right and forward members to rectangular grids
    • added sides, width and height members to hex grids
    • added the enum GFAngleMode {radians, degree} to specify an angle type; currently only used in methods of polar grids
    • added the enum HexDirection for cardinal directions (north, north-east, east, ...) in hex grids
    • added the GetDirection method to hex grids to convert a cardinal direction to a world space direction vector
    • hex grids and polar grids now both inherit from GFLayeredGrid, which in return inherits from GFGrid
    • the Lights Off example now features a polar grid as well
    • procedural mesh generation for grid faces in the Lights Off example
    • mouse handling in runtime snapping example changed because it was confusing a lot of users who just copy-pasted the code

    Please note that this version officially requires Unity 4, since that is what I was building with, but there is no new API used and the scripts will run just fine in Unity 3.
     
  2. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,462
    Wow,

    Many Thanks for the Fantastic Update. Been playing with the new PolarGrid and it's really Amazing work. Also very nice with new examples and particularly the Mesh Extrude using the Polar Grid. These kinds of example really help us to realize the Full-Power of this framework.

    Cheers.
     
  3. Trithilon

    Trithilon

    Joined:
    Aug 2, 2012
    Posts:
    30
    Hi HiPhish,
    So.... what's next on your cards for features?

    Cheers! :)
     
  4. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Three things are on the short-term list:
    1) Replace the hand-written documentation with a doxygen-generated one. I know how to comment code for doxygen, but I have to figure out how to make the documentation look nice, in it current form it's too bloated and full of stuff not meant for end-users.
    2) More coordinate systems for hex grids. The current coordinate system works, but the disadvantage is that "one unit to the right" means different things depending on whether we're currently in an odd- or even-numbered column. I'd like to offer different coordinate systems, just like how polar grids have two coordinate systems.
    3) Playmaker support.

    Doxygen is currently a low priority, but I'd like to figure it out eventually, writing the scripting reference by hand is a real pain.

    Funnily enough, not even I know the full power of the framework :) Sometimes I get an idea and then I challenge myself to see how it could be done using Grid Framework. The mesh construction came to my mind when I found Unity' standard primitives unsuitable, so I asked myself "how can I construct meshes that fit exactly in there?".
     
  5. MonkeyCrime

    MonkeyCrime

    Joined:
    Jun 13, 2013
    Posts:
    32
    Hello HiPhish,

    Do you have any thoughts on how I would implement click/drag/highlight of grid sections? Think of zoning a section of land in your favourite city builder or highlighting a section of dirt for cultivation in your favourite farm builder and you'll know what I mean. I'm sure the demos will show me most of what I want to know but I'm unclear on how to feedback to the user about the "selected area".

    Cheers
     
  6. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Hi

    I would do it this way: once the player clicks find the coresponding face (call NearestFaceW), and store its world-coordinates as point A. Then, as long as the player is dragging the mouse store the face the mouse is above as point B every frame. Once the player lets go off the mouse stop updating point B. Getting the point is what I do in the runtime snapping example, except you just want the point, you don't want to change any object positions.

    Now that you have two end points of a rectangle, the next question is how to display the area. There are many ways, you could create a rectangular mesh and give it a colour or use vector lines or quads to cover the surface. If you want to go that way take a look at Unity's low-level GL class
    http://docs.unity3d.com/Documentation/ScriptReference/GL.html

    The first step is always getting the end points, once you have those Grid Framework's job is done, then it's just a matter of finding a way to render the rectangle.
     
  7. Carwashh

    Carwashh

    Joined:
    Jul 28, 2012
    Posts:
    763
    Hey Hiphish,

    I'm glad I found your Grid Framework, your YouTube videos and documentation have helped me greatly so far - someone who is new to Unity and C#. I have many questions, but only two to ask at the moment (one of which may have been answered in your post above this).

    Some background info about the game:
    It's a turned based, tile/ grid game, where the player has to setup the path for their character to take, to get from A to B, then press go and watch the action unfold. I want the character to move along the grid, so in ONLY the X or Z axis, not X and Z at the same time.

    I've got the waypoints being set in the centre of the grid face when the mouse is clicked, and the character moving in turn between the waypoints. Next I'd like to get grid movement sorted.

    1- Assume the player is bottom left of the grid and they place a waypoint top right, the correct path should be up the left side -> along the top / along the bottom -> up the right side. However, my current setup will have the player go diagonally across the grid. Can Grid Framework be used to force the player to move along it? Or will I need some path finding plugin to achieve this?

    2- I'd like to highlight the path between A, each waypoint and B along the grid. I had no idea how to do this before, but I think I can use something similar to what you suggested above. Except without the mouse drag.


    Thanks in advance
     
  8. Dr9

    Dr9

    Joined:
    Jun 27, 2013
    Posts:
    3
    Looks great, 2 questions.

    1) I don't see any examples - but I assume it is easy to use this to overlay an existing 3d scene - correct?
    2) Is it possible to extrude the grid so grid lines are themselves 3d?
     
  9. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    A pathfinding solution is mostly for finding a path around obstacles, if you are looking for a straight path it's overkill. The easiest way I can think of is if you know how far apart the start and end point are to use the grid's right and up members:
    Code (csharp):
    1.  
    2. GFRectGrid myGrid;
    3. float x;
    4. float y;
    5. bol doneX;
    6.  
    7. if (!doneX)
    8.     move(myGrid.right * speed);
    9. else
    10.     move(myGrid.forward * speed);
    11.  
    The members right, up and forward give you the vectors of the corresponding directions in world space, depending on how your grid is positions and how large its spacing is. The idea is to break up movement into an X- and Z phase. You could calculate a third waypoint using this formula:
    Code (csharp):
    1.  
    2. Vector3 distance = endPoint - startPoint;
    3. Vector3 wayPoint = startPoint + distance.x * myGrid.transform.right;
    4.  
    Highlighting depends on how you want to accomplish it. In any case you would need the world coordinates of each tiles that's passed through. You must know how many tiles are between the start or end point and you helper waypoint. Just take the X and Z coordinates of the distance and divide it by the grid's spacing. Now we can start iterating over that number
    Code (csharp):
    1.  
    2. int steps = Mathf.RoundToInt(distance.x / myGrid.spacing.x);
    3. Vector3[] points = new Vectr3[steps];
    4. for (int i = 0; i < steps; i++) {
    5.     points[i] = startPoint + i * myGrid.right;
    6. }
    7.  
    Once you have the points you can start drawing a line, placing illuminated tiles on them or whatever you want. I only covered the X direction here, but the Z direction is similar.

    The examples are in the global GridFramework folder (in the Assets folder) under Examples. As for your second question, I don't really understand what you mean. Could you perhaps provide a sketch to illustrate?
     
  10. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Hi hipish,
    I'm likely to purchase this tomorrow, but the only thing that's giving me pause is the lack of PlayMaker support. I'll probably still get it, just figured I'd throw a "+1" onto the desire for PlayMaker support.
     
  11. flyingaudio

    flyingaudio

    Joined:
    Dec 3, 2010
    Posts:
    98
    This seems like a well thought out framework, but I am having an issue getting it going. In following the "Grid-Snapping during runtime" video, it doesn't show the collider setup, but in the SnappingUnits script it states a collider is needed on the grid.

    Since I am a noob to Unity, I am probably asking simple questions, but this seems quite strange at the moment.

    The video starts with adding the Grid first. But that doesn't work for me. The issue is the collider.
    1) If I add a plane child to the Grid (like the video shows) that collider is not used, because it is not on the Gird.
    The docs say the Grid needs a collider.
    2) If I add a box collider to the Grid and make sure it does not cover the cube, then the cube will snap to the first positive X row and I can only drag it along the row, it will not go up and down.
    3) If I add a mesh collider (like a plane would have) it will also snap to +1 on X, but is not draggable. Should I be able to do that?

    The Runtime Snapping scene shows a Grid containing a plane and it's mess collider, which works.
    Can a plane be adding to the Grid?

    The only thing that works for me, is to create a plane first, then add the script component to it. Is that the way it must be setup?
     
  12. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Ah, I'm sorry, but the video is outdated. A lot of users were just copy-pasting my code into scenarios where it wouldn't work and then they kept sending me support requests. That's why I changed the mouse input handling to a more versatile way.

    essentially, it works by using the camera to shot a ray (raycasting with Unity's physics) from the cursor into space. Using Collider.Raycast allows me to make the ray pass everything except that certain collider. Which collider? The collider that's attached as a component to the grid object, so matter what type exactly. Usually a flat plane is what I need, that's why I use the mesh collider. Then, when the ray hits the plane I use the resulting hot point as where the player wants to drag the object to.

    Ading a plane object as a child of the grid object won't do anything, because the collider has to belong to the grid object itself, not to a child.
     
  13. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Just a suggestion, but you can use YouTube's annotation feature to write a big scary annotation at telling the viewer about the outdated-ness and what the correct method is (or pointing them to somewhere with the correct method). Otherwise you'll probably just end up changing the type of support requests. ;-)
     
  14. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Thanks, you are right. I had pretty much forgotten about annotations since I turned that feature off. I've added it to the video and I added it to the description in case someone else has their annotations turned off ;) I'll need to make a new video eventually.
     
  15. flyingaudio

    flyingaudio

    Joined:
    Dec 3, 2010
    Posts:
    98
    Thanks for the information hiphish. Through experimentation this is what I found. First, I see if I add a mesh collider it extends along the z-plane. So, if I want a grid on one plan, I have to set it up for XZ and then rotate it to where I want. Is that how you do it?

    Box collider doesn't work by adding it to XY grid (Size: 3,3,0), but if I set up the grid with XZ (Size: 3,0,3) and add the box collider to that, it works. Seems odd. What do you think?
     
  16. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Hi Hiphish; Just brought this. There's a bug in the "movement" example - the sphere is able to leave the hex grid (I've seen it leave to the left and the top). I hadn't tweaked anything at all.
    Also, pedantic observation on that example - when the sphere translates a diagonal edge on the hex grid, it's not central between the two vertices. It tends to overlap one of the vertices.

    Maybe it's intentional, but the runtime snapping polar-grid example snaps to the edges and vertices as well as the faces. Conversely, it only snaps to the faces for the hex and square grid. Again, maybe intentional but I figured I'd flag it.

    Suggestion - The diagram in the user guide showing anatomy of a grid doesn't label an "edge".
     
  17. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I do it the following way: create a fresh grid (GameObject -> Create Grid -> Rectagular grid) or I add a grid component to an existing object (Component -> Grid Framework -> GRRectGrid), then I add a Mesh Filter and Mesh Renderer component as well. Now I can add a mesh to the mesh filter, the default plane mesh gets the job done. This is only for making the plane visible though, you don't need it. To make it clickable you have to add a Mesh Collider component and add the plane. If you look into my example you will see that there is nothing rotated in there. Of course you could also build your own mesh in a 3D modeling application or even through code. The round mesh on th polar grid has been created entirely through code.

    Or am I misunderstanding you and you want an XY grid instead of XZ? In that case, yes you would have to rotate, but it would be easier not to rate the grid and instead use your own mesh. Generating meshes from code is very easy, first you specify the vertices, then you define the triangles. For a flat plane rectangular four vertices and two triangles are enough:
    Code (csharp):
    1.  
    2. float width;
    3. float height;
    4. Vector3[] vertices = new Vector3[4] {new Vector3(-width, -height, 0), new Vector3(-width, height, 0), new Vector3(width, height, 0), new Vector3(width, -height, 0)};
    5. int[] triangles = new int[6] {0, 1, 2, 3, 4, 5};
    6.  
    7. Mesh myMesh = newMesh();
    8. myMesh.Clear();
    9. myMesh.vertices = vertices;
    10. myMesh.triangles = triangles;
    11.  
    The vertices are given as point in local coordinates and the triangles are the indices of the vertices in a clockwise direction. You can read more here:
    http://blog.nobel-joergensen.com/2010/12/25/procedural-generated-mesh-in-unity/
    (or just use a 3D modeling application)

    I will look into it. It has something to do with relativeSize, a member I introduced a while ago. Before it existed the example had worked fine.

    Yes, it only moves at multiples 45° angles. I'll look into it, and see if there is a reason I did it that way, but it's not really that important. The point of the example was to demonstrate how the same code can be used for different grids.

    Yes, that's intentional, snapping only really makes sense for rectangular shapes, so for hex and polar grids I did it that way. It's like trying to fit a square peg into a round hole, you can do it, but there is no real "right" way to do it. If you have suggestions I'm open for it.

    You'r right, but I don't mention edge specifially in my documentation or code, that's why I didn't label them. The best way to approach edges is simply as an array of two vertices.
    Code (csharp):
    1.  
    2. Vector3 edge = new Vector3[2] {startVertex, endVertex};
    3.  
     
  18. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Apologies for contradicting, but you mention them a couple of times (otherwise I wouldn't have known the term). i.e. from the bit directly above the picture:
    ----

    Another bug (this one is actually causing me issues because I'm using this script):
    In your Runtime Snapping example, the larger boxes (any that aren't 1x1) snap so part of them is dangling outside the grid.
    A test with a 3x3 indicates that AlignTransform is trying to ensure the centre is on the grid and is ignoring the edges.

    ----

    Finally, I'm not sure if this is a bug or just me having issues. I've been hitting my brain against it for an hour.
    AlignTransform seems to un-rotate things.
    So say I have a 2*1 "cube" rotated 90 degrees (or 270) on a square grid. When it comes to snapping time, it will rotate back to 0.

    The grid is a regular non-rotated affair.
     
  19. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Look at the scripting documentation for AlignTransform (page 20): the rotate parameter tells the function whether to rotate the object to the grid or not and it's set to true (yes) by default. Set it to false and your objects will keep their rotation.

    Yes, I am aware of it. The thing about the examples is that they are just that: examples. I want to focus on the bare basics to provide point you in the right direction, it's not meant to be a copy-paste instant solution. To that end I will often ignore edge cases that would just add clutter to the code. The focus of the example is to show how to achieve snapping at runtime.

    In your case what i would do is after applying the new position to check whether the box is dangling outside, and if it is reset back to the old position.
    Code (csharp):
    1.  
    2. GFRectGrid grid;
    3. Vector3 oldPosition = transform.position;
    4. transform.Position = RuntimeSnap(); // here goes the snapping
    5. if ( Mathf.Abs(transform.position.x - grid.position.x) > grid.spacing.x || Mathf.Abs(transform.position.y - grid.position.y) > grid.spacing.y)
    6.     tranform.position= oldPosition;
    7.  
    True, but I use the English term "edge", not the term edge in the sense of graph theory. The former is a generic term that simply means the edge of something, while the latter is a cleary defined mathematical term. There are no edges explicitly mentioned in any syntax, it's all implicit, therefore I didn't label it. I'll add a short note that the user can define edged as two vertices, but I will not add it to the illustration. The illustration is called "anatomy of a grid" and edges are not part of that anatomy, at least for now, it would just be information clutter.
     
  20. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Thanks for your reply and the clarification!
    Two things here:
    a) The help implies it's the other way around - "Setting doRotate makes the object take on the grid’s rotation." - that's why I didn't expect that to be the solution (though I did try it, though with "true" rather than "false" because I missed the default).

    b) When I set doRotate to false, while the item does retain its rotation, in its rotated state it does not align to the grid. Instead it aligns to the edges of the grid (so everything is offset by half a cell).
    Hence all the headbashing. ;-)


    This didn't work for me because GFRectGrid (nor GFGrid) has a "position" variable.
    I tried worldToGrid and NearestVertexG but they always gave the exact same position as transform.position. NearestBoxG gave a different value, but it couldn't be used because it also occured in a legitimate position.
    I'm not sure of a good way to do this (but then I'm still new to C#, Unity and this framework), but I guess it'd be possible if there was a reputable way to get the bounds of the grid.

    Thanks again!
     
  21. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I meant "setting" as in setting a flag, making it true. I'll change the wording to "setting doRotate to true" to avoid future confusion, that should be clear.

    Are the dimensions of your cubes even multiples of the grid's spacing? If so, that's intended behaviour. You can use AlignVector3 directly on the position instead:
    Code (csharp):
    1.  
    2. transform.position = myGrid.AlignVector3(transform.position);
    3.  
    This also bypasses the whole rotation thing and if you use only one parameter it will be trated as if it had a size of (1, 1, 1), makign it align to the centre of the box.

    Sorry, I meant
    Code (csharp):
    1.  
    2. myGrid.transform.position
    3.  
    The GFGrid class, from which all grids inherit, inherits from Unity's MonoBehaviour class, just like every other script. Anything that works for MonoBehaviour works for grids as well.
     
  22. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    No, the cubes can be an arbitrary number of grid cells in each dimension; they can be even or odd. Unfortunately the alignV3 only seems to work for evens.

    What I expected to happen with AlignTransform was that it wouldn't matter what the rotation of the cube was as long as it was a 90 degree increment. As it stands it only seems to work for items at 0 and 180 degrees.


    That does exist, but your script doesn't work; myGrid.transform.position never changes (it's always 0), which means that when active your script only allows me to use the middle 2*2.

    After a lot of trial and error, I ended up using the following which works fine for rotated and non-rotated objects:
    Code (csharp):
    1.  
    2. GFRectGrid this_grid;
    3.  
    4. Vector3 oldPosition = transform.position;
    5.  
    6.         //Here we're checking to see if the item is out of bounds of the grid.
    7.         //This relies on the rendered bounds of the item, which while slightly lossy, should be good enough for us.
    8.         if (Mathf.Round(Mathf.Abs(transform.position.x) + renderer.bounds.extents.x) > this_grid.size.x || Mathf.Round(Mathf.Abs(transform.position.z) + renderer.bounds.extents.z) > this_grid.size.z) {
    9.             transform.position= oldPosition;
    10.         }
     
    Last edited: Jun 30, 2013
  23. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    We can keep guessing all day like that, but we have to narrow down the source of your issue. Let's see if mouse input works properly first by attaching the following script to the grid object:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [RequireComponent(typeof(Collider))]
    6. [RequireComponent(typeof(GFGrid))]
    7. public class PointDebug : MonoBehaviour {
    8.  
    9.     bool debugPoints = false;
    10.     Vector3 point;
    11.  
    12.     private Collider col;
    13.     private GFGrid grid;
    14.  
    15.     void Awake () {
    16.         col = collider;
    17.         grid = GetComponent<GFGrid> ();
    18.     }
    19.  
    20.     void OnMouseDown () {
    21.         debugPoints = true;
    22.     }
    23.  
    24.     void OnMouseUp () {
    25.         debugPoints = false;
    26.     }
    27.  
    28.     void Update () {
    29.         if (!debugPoints)
    30.             return;
    31.        
    32.         RaycastHit hit;
    33.         col.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity);
    34.         point = hit.collider != null ? hit.point : transform.position;
    35.         //Debug.Log (point);
    36.     }
    37.  
    38.     void OnDrawGizmos () {
    39.         if (!debugPoints)
    40.             return;
    41.         Gizmos.color = Color.green;
    42.         Gizmos.DrawSphere (point, 0.3f);
    43.         Gizmos.color = Color.red;
    44.         Gizmos.DrawSphere (grid.AlignVector3(point, new Vector3(1,2,1)), 0.3f);
    45.     }
    46. }
    47.  
    Hit play, make sure Gizmos are turned on and drag the mouse over the grid. You can play with the second parameter of AlignVector3 to decide whether to be between edged or on edges. The camera perspective might distort what you see, so make sure you have scene view open at the same time from an easier to judge angle.
     
  24. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    As best I can tell, that script creates the gizmo's which are snapped to points. If a coordinate is even then it snaps to the vertex, if it is odd it snaps to the centre of two vertices (edge).

    After some experimenting with the AlignVector Scale variable in my own script, the odd/even problem is consistent here. I need to have the AlignVector3 Scale set to an even number if the transforms dimension is an odd number (all coordinates X,Z):

    If the box is:
    1,2

    (rotated 90 degrees, so visually it's 2,1)

    then the V3 scale needs to be: 0,1

    So the end result is that I've adjusted my script to this:
    Code (csharp):
    1.         if(transform.eulerAngles.y == 0f || transform.eulerAngles.y == 180f ){
    2.             //now align the object and snap it to the bottom.
    3.             this_grid.AlignTransform(transform, false);
    4.         } else {
    5.             transform.position = this_grid.AlignVector3(transform.position, new Vector3(transform.localScale.z,0,transform.localScale.x));
    6.         }
    Note that the Z is used to populated the X scale V3 and vice-versa; this is because transform.localScale doesn't rotate (I've got another thread open where I'm trying to find out how to get the actual width).

    Using this script, the snapping now works fine with arbitrarily sized cubes.

    You may want to implement something like this inside AlignTransform so the function works transparently with rotated features.

    Many thanks for your assist!
     
  25. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I'm afraid extensing AlignTransform in that way is not a good idea, what you suggest only makes sense if the rotation angles are a multiple of 90°. That's a too specific case to have in a general function, it would be easier to do it the way you did. Remember that you can use extension methods to encapulate your own functionality. The Lights-Out example is using an extension method where the way that a grid decides which tiles are adjecent is encapsulated in a method which can then be called by any grid as if it were part of GridFramework itself. In your case the extension method would look something like this:
    Code (csharp):
    1.  
    2. // name it whatever you want
    3. public static void AlignTransformX (this GFRectGrid grd, Transform trns) { // the first parameter is the class we extend
    4.     trns.position = grd.AlignVector3(trns.position, new Vector3(trns.localScale.z, 0, trns.localScale.x));
    5. }
    6.  
    Then you can call it just like any other method of Grid Framework, no copy-paste needed:
    Code (csharp):
    1.  
    2. if (transform.eulerAngles.y == 0f || transform.eulerAngles.y == 180f ) {
    3.     //now align the object and snap it to the bottom.
    4.     this_grid.AlignTransform(transform, false);
    5. } else {
    6.     this_grid.AlignTransformX(transform);
    7. }
    8.  
    That's the beaty of Unity's underlying .NET/Mono framework, if there is something specific you need you can just add it and it fits right in.
     
  26. random1

    random1

    Joined:
    Jun 19, 2013
    Posts:
    21
    Heh. You're assuming a level of competence with OOP that is at least several months away (if all goes well). :) Now procedural programming, that I can do. I'll keep this in mind, but for now the given solution (seems to) work.
    I figured that rotating by 90 degrees would be a fairly common use-case, at least on a square grid. But maybe its just me. And now there's a solution for anyone else who wants it. :)

    ---

    Oh yes, a update for the bounding box - to resolve the issue with rotated objects, rather than use "localScale" or "lossyScale", it turns out renderer.bounds is the way to go. So that function becomes as this (I'll update the original post too).

    Code (csharp):
    1.         //Here we're checking to see if the item is out of bounds of the grid.
    2.         //This relies on the rendered bounds of the item, which while slightly lossy, should be good enough for us.
    3.         if (Mathf.Round(Mathf.Abs(transform.position.x) + renderer.bounds.extents.x) > this_grid.size.x || Mathf.Round(Mathf.Abs(transform.position.z) + renderer.bounds.extents.z) > this_grid.size.z) {
    4.             transform.position= oldPosition;
    5.         }
     
  27. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Renderer.bounds returns an axis-aligned box, so it only fits your block if your rotation angles are multiples of 90°. If it was that easy I would have done it already :p

    Don't worry, as long as you have the will and persistance you can do it. A year ago I was still tinkering around with UnityScript and i couldn't even imagine writing my own framework for unity.
     
  28. Dr9

    Dr9

    Joined:
    Jun 27, 2013
    Posts:
    3
    I guess what I'm trying to figure out is are the lines just drawn in the scene - or is there some underlying geometry I can use for a mesh to make the otherwise 2 dimensional lines into a 3D rectangles.

    -edited for clarity. It looks like there is geometry, but the question is on how to render a grid in 3d space like the picture.

    This is sort of what I'm talking about.
    http://www.flickr.com/photos/dr9/9208730453/
     
    Last edited: Jul 4, 2013
  29. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    It's just plain lines using Unity's GL class, no geometry and no meshes, it's very flexible and fast that way. If you want to use a mesh you would need to calculate the lines' vertices and triangles yourself. You can use GetVectrosityPoints to get an array of end points. Those are meant to be used with Vectrosity, but an array is an array, you can do whatever you want with it. Then you could calculate the vertices relative to the end points, kind of like this:
    Code (csharp):
    1.  
    2. float thickness = 0.5f;
    3. Vector3[] points = myGrid.GetVectrosityPoints();
    4. // for each end point we need two vertices
    5. Vector3[] vertices = new Vector3[points.Length * 2];
    6.  
    7. int counter = 0;
    8. for (int i = 0; i < points.Length; i++) {
    9.     // vertices are in local space, so we need to transform points first, then add the extrusion
    10.     vertices[counter] = transform.InverseTransformPoint(points[i]) + new Vector3(0, thickness, 0);
    11.     vertices[counter + 1] = transform.InverseTransformPoint(points[i]) + new Vector3(0, -thickness, 0);
    12.     counter += 2;
    13. }
    14.  
    If you have Vectrosity you might be able to achieve the same effect (or even better) using Vectrosity's API. Here is a good link about generating meshes at runtime:
    http://blog.nobel-joergensen.com/2010/12/25/procedural-generated-mesh-in-unity/

    I have been workign on an example recenty where I use a plain text file as my height map and generate a SimCity-like terrain mesh from it. I know it's not really related to what you want, but it get's to show the possibilities with mesh generation.
     
  30. MonkeyCrime

    MonkeyCrime

    Joined:
    Jun 13, 2013
    Posts:
    32
    Does anyone have trouble with MonoDevelop and the various target framework options?

    I upgraded to Unity 4.5.1f1 when I purchased GridFramework. When I first build in MD I'll usually get a bunch of errors in GFGrid.cs about default parameter specifiers. That's fixed by changing the target framework to "Mono/.NET 4.0" (almost everytime I open MD, tedious beyond belief). Rebuilding again then gives me errors in GridDebugger.cs (type or namespace name 'GFGrid' could not be found). The behaviour seems to change across sessions of MD as well - sometimes I'll get failures in LevelTextParser.js for example, other times not.

    I know I can (and should) strip all of the examples etc out of my project, just wondering does anyone else have this or is it my environment?
     
  31. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    This looks like the answer to my dreams as far as generating runtime hex grids. Couple questions before I purchase:

    1) How do you handle pick events to cells, do they require individual colliders or can I grab a cell location from world coordinates?

    2) Does the hex grid matrix work with A* pathfinding?

    Thanks!
     
    Last edited: Jul 6, 2013
  32. Mister-D

    Mister-D

    Joined:
    Dec 6, 2011
    Posts:
    1,694
    hi, will your grid framework work with playmaker?
     
  33. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    1) Both actually. The method WorldToGrid will convert the world coordinates of a point into grid coordinates:
    Code (csharp):
    1.  
    2. GFGrid myGrid;
    3. Vector3 worldPosition;
    4. Vector3 gridPostition = myGrid.WorldToGrid(worldPosition);
    5. // or:
    6. gridPostition = myGrid.NearestFaceG(worldPosition); //the nearest centre of a hex in grid coordiantes
    7.  
    You can convert back and forth and if the grid has more than one coordinate system (currently only polar grids have two) you can convert between those as well. Colliders are needed only if you want to use collders to get the world coordinates. I find raycasting and colliders to be the simplest solution when it comes to clicking things, but colliders are just a way to get to the actual world coordiantes.

    2) There is no hex grid matrix. Grids in Grid Framework are not a collection of coordinates, they are grids in a mathematical sense, they are infintely large. Of course you can still use them to build a matrix (which I do in some of my examples):
    Code (csharp):
    1.  
    2. GFHexGrid myGrid;
    3. int width;
    4. int height;
    5. Vector3[] hexMatrix;
    6. void Awake () {
    7.     hexMatrix = new Vector3[width][height];
    8.     for (int i = 0; i < width; i++) {
    9.         for (int j = 0; i < height; j++) {
    10.             hexMatrix[i][j] = myGrid.GridToWorld(new Vector3 (i, j, 0));
    11.         }
    12.     }
    13. }
    14.  
    Unfortunately there is no pathfinding solution built in yet, but you could use that matrix for your own solution or try to hook it up to something existing.

    Yes and no. Yes in the sanse that you can hook it up to Playmaker, no in the sanse that there isn't anything out of the box yet. It is on my to-do list, but in the meantime another user has shared his Playmaker scripts for everyone to use:
    http://forum.unity3d.com/threads/144886-Grid-Framework-scripting-and-editor-plugins/page11

    I never experienced anything like that. If you get errors in the example scripts that means you scripts don't compile in the proper order. This is question better directed towards the Unity staff, since they know how the engine works.
     
  34. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    So if I understand you correctly I could use one large box collider for an entire level of a grid simply to get the world coords when user touches/clicks? If so that is perfect. I am thinking of having terrain on the "ground level" grid and sharing the same mesh instead of individual tile gameobjects at runtime for performance reasons and as long as I can still access the grid locations via world coords that should work fine.

    I'll play with A* a bit but I think if you can generate a list of neighbors A* should work fine with something like this.

    Thanks!
     
  35. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Exactly; that's the way I do it in the runtime snapping example. A flat plane collider with just two triangles should perform best, but the difference is probably negligible.
     
  36. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    Thanks, purchased :)
     
  37. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    No, I have to thank you ;)
     
  38. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    Small polish/nitpick feedback on the Vectrosity example scene.

    1) Vectrosity folder misnamed Vectorsity
    2) Need to explicitly call the namespace for Vectrosity for "VectorLine" or it throws errors in the example scripts, see attached screenshot. After I changed instances of "VectorLine" to "Vectrosity.VectorLine" it worked fine :)
     

    Attached Files:

  39. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Thanks, I corrected it. About explicitly calling the namespace, that depends on how you installed Vectrosity on your system (source code or DLL) and whether you called "using Vectrosity" at the beginning of your script. I changed it to explicit now, I'd expect most people would prefer to have one DLL instead of the whole source code in their project.
     
  40. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    Yep was no big deal, thanks.
     
  41. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,240
    Got my basic hexmap up and running! However it raised a couple more questions(of course):

    1) Best way to calculate distance from one hex to another in grid cells?
    2) Best way to calculate direction from one cell to another? I am sure I can hack a quick function together based on the two world coords of the hexes but this would probably be fairly useful to have standardized, ie. getDirection(hex1, hex2) returns string (NW,NE,E,W,S,SW,SE, etc.) This helps with correctly facing your units when moving them.
     
  42. Krileon

    Krileon

    Joined:
    Oct 30, 2012
    Posts:
    642
    DocSearch appears to be included with the latest release. Is this by mistake? Please don't include things like this that have no relevance to an assets functionality, it just adds to the clutter.
     
  43. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    1) the distance between two adjacent hexes is the same as a hex's height; you can access it as
    Code (csharp):
    1.  
    2. GFHexGrid myGrid;
    3. float d = myGrid.height;
    4.  
    2) use GetDirection:
    Code (csharp):
    1.  
    2. Vector3 ne = myGrid.GetDirection(GFHexGrid.HexDirection.NE);
    3.  
    This will give you a vector that points from one hex to the north-eastern hex.

    Sorry, that was a mistake, I wouldn't want to include anything that doesn't belong into Grid Framework. Just delete it, I'll be more careful in the future. (I just hope I don't one day include something commercial like Vectrosity accidentally)
     
  44. yuewahchan

    yuewahchan

    Joined:
    Jul 2, 2012
    Posts:
    309
    how to snap gameobject to terrain with height ( SimCity-like terrain mesh ) using GridFramework ?
     
    Last edited: Jul 10, 2013
  45. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    First snap it normally and then set the Y-coordinate individually. To get the height of the terrain you could for example perform a raycast:
    Code (csharp):
    1.  
    2. float objectHeight = myObject.transform.scale.y;
    3. Collider terrainCol;
    4. RaycastHit hit;
    5. Ray ray = new Ray(positionAboveObject, -Vector.up); // a ray facing straight down
    6.  
    7. terrainCol.Raycast (ray, out hit, 100);
    8. myObject.transform.position.y = hit.point.y + 0.5f * objectHeight;
    9.  
    Or you could store the height information in the representation of your map and avoid the use of physics. The idea is to leave the X and Y to Grid Framework and then "correct" the Y yourself.
     
  46. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Hello everyone, I decided to do a status update so you know what's going on and coming next.

    Two new examples
    The first example is something I wanted to do for quite a while, it generates a terrain mesh like the terrain in games like SimCity from a plain text file. You provide the numbers for the height of vertices and the mesh gets created. On top of that you can click a vertex to raise it and right-click to lower. All the vertices will be placed along the vertices of the grid, so the level designer doesn't have to wory about the layout of the scene.
    The other example is a rotary phone dial using polar grids, it's based on a suggestion by a customer (I always appreciate input, don't be shy ^^). You have a rotary dial, you click it and then it rotates like a real dial, depending on which number you clicked. It may no look very impressive on its own, but the template could be used for all kinds of cool UI displays and menus. It works by checking which sector of the grid was clicked and then multiplying that with the angle of the grid and then applying the rotation over time.
    Both examples are already done and will definitely be part of the next update.

    New hexagonal coordinate systems
    This is the main feature of the upcoming update. Up until now the only coordinate system hex grids had was the herringbone pattern. It's easy to understand, but when writing for it you often have to differentiate between odd and even X-coordinate, which is... stupid. The new coordinate systems don't have that problem, but they are harder to understand, so pick your poison ;)
    The first coordinate system is "rhombic", meaning the X-axis is rotated 30° upwards. This removes the need for the even/odd cases, but now moving south-west is actually moving west. The second coordinate system is "cubic", it uses three axes in two dimensions. To understand it remember the game Qbert, the game world is in 3D with cubes, but the actual graphics are in 2D and the cubes are actually hexagons. Finally, we have barycentric coordinates for the more mathematically inclined.
    I really want this feature to be done before going after playmaker support. I know you guys want Playmaker and I keep telling you "later", but this is more urgent. The good news is that these coordiante systems turned out to be much less painful to implement than I originally expected. I still need to give everything the final polish and make sure the systems are not only mathematically correct, but also make sense to a human being, so I'm about 90% done.

    New documentation with doxygen
    Up until now I have been writing the documentation in Pages and exporting it as PDF. It was an OK workflow and the results looked reasonably well, but as Grid Framework's API grew it became more and more of a pain to write the actual documentation with all the cross-references and unified layout and styles. I have now reached the point where it would be just madness to continue, so I decided to switch to Doxygen. When you use Doxygen you comment your source code in a specific manner, then Doxygen parses it and uses your comments to document all the methods for a human to read.
    The transition phase is ugly, I need to copy-paste or rewrite all my documentation, but once it's done any future updates will be much easier. This also means you will get documentation in both HTML and PDF format from now on.

    Vertex matrix gets the axe
    Finally, some not-so-good news. I have been thinking about this for a while, and the vertex matrix methods were never really good. The idea was to give you a quick and simple way to store some vertices of a grid in an array and be able to read them, but the way I did it is way too specific. It will only be useful in a handful of cases. This leaves me with two options: either expand on it, writing many variants of the method and on top of that doing the same thing for faces, boxes and edges, or just cut it out.
    I decided to cut it out, because there is no point in dragging all that code along, when most people will never use it and some will only use a fraction of it. It would be much easier and better if the users themselves wrote their own methods, it's less than ten lines of code anyway and you get full control over what you want. You don't have to drag along an array that's four times larger than you need. When looking at the examples I wrote, not even I used the vertex matrix methods once, because it was easier and cleaner just to roll it from scratch.
    Naturally this raises another concern, what about the people who were using this method? I can't just rip it out and tell them to write it themselves. This is where extension methods come into play: After I removed the methods I put them back into and extension method in a separate file, which I ZIPed. If you need the vertex matrix methods back just unzip it and you won't notice any difference. Of course if enough people actually want the vertex matrix to stay in place I'll put it back, but if no one objects this will be the way to go.
     
  47. NandusMasta

    NandusMasta

    Joined:
    Apr 9, 2011
    Posts:
    63
    That was an excellent status update hiphish! I've been dragging my feet to get this asset, but after this I will buy it for sure next time I open the store. I don't really need it for what I am working right now, but for my next project the asset will certainly be a lifesaver.
     
  48. MonkeyCrime

    MonkeyCrime

    Joined:
    Jun 13, 2013
    Posts:
    32
    Thanks for all your on-going efforts Hiphish, I'm looking forward to playing with the terrain mesh example.
     
  49. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,462
    Very nice update.. in the style of Hiphish. Completely Thorough and well communicated.

    Cheers.
     
  50. Tonmeister.

    Tonmeister.

    Joined:
    Mar 30, 2013
    Posts:
    27
    I am chomping at the bit for your next update, great work. Official Playmaker support would be great to