Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Grids Pro: A library for hex, tri, polar and rect grids [New Dcoumentation for Grids 2]

Discussion in 'Assets and Asset Store' started by Herman-Tulleken, Jul 10, 2013.

  1. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,546
    OK I'm a little stumped.

    I'm trying to create the map in such a way that it will load data from a file. I've made my own serialized data for the map, which has an array of TileType. The array of TileType coming from the file corresponds to the array of my custom cell class, AreaScapeMapTile (derived from class TileCell) in the RectGrid.

    I just want to "hijack" the grid creation process so the cell dimensions, and the values of the cell classes in the array upon being created, will be set coming from my classes. Essentially, I mark which cells are passable and which aren't. And those values come from my own code.

    So from what I read, CustomGridBuilder was the way to go. I got to the point where it's creating the grid with my specified number of cells (i.e. height and width), but trying to edit each individual cell, it doesn't work. I can't seem to access it. Since it's of type TCell in the function, I try to cast it to the custom class I use (derived from TileCell), but it doesn't work.

    Here's the code:

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using DreamlordsDigital.Utility;
    5. using Gamelogic.Grids;
    6.  
    7. public class AreaScapeMapBuilder : CustomGridBuilder
    8. {
    9.     const int TILE_WORLD_SIZE = 1;
    10.  
    11.     AreaMapFile _mapFile;
    12.  
    13.     [SerializeField]
    14.     TextAsset _mapFileToLoad;
    15.  
    16.     public override IGrid<TCell, TPoint> MakeGrid<TCell, TPoint>()
    17.     {
    18.         BetterDebug.Assert(typeof(TPoint) == typeof(RectPoint), "AreaScapeMap requires RectPoint (we are using squares for the area scape map)");
    19.  
    20.         // loading values from file:
    21.         _mapFile = ResourceCreator.DefaultTextDataProvider.FromSerializedString<AreaMapFile>(_mapFileToLoad.text);
    22.  
    23.         RectGrid<TCell> grid = RectGrid<TCell>
    24.             .BeginShape()
    25.             .Rectangle(_mapFile.Width, _mapFile.Height)
    26.             .EndShape();
    27.      
    28.         BetterDebug.Assert(grid.Width == _mapFile.Width);
    29.         BetterDebug.Assert(grid.Height == _mapFile.Height);
    30.  
    31.         // doesn't seem to work, even though the cell prefab I use has a AreaScapeMapTile in it
    32.         IGrid<AreaScapeMapTile, RectPoint> gridWithCells = grid.CastValues<AreaScapeMapTile, RectPoint>();
    33.  
    34.  
    35.         int nX = 0;
    36.         int nY = 0;
    37.         for (int n = 0, len = _mapFile.NumberOfTiles; n < len; ++n)
    38.         {
    39.             BetterDebug.Log("for tile {0}: type is {1}", n, _mapFile.Tiles[n].TileType);
    40.  
    41.             // IsPassable is a bool in my custom cell class. I need to set it to the proper value, coming from an array in my map file
    42.             // that comes from _mapFile.Tiles[n].TileType, which already has the proper values at this point
    43.  
    44.  
    45.             // it seems gridWithCells is null
    46.             //gridWithCells[new RectPoint(nX, nY)].IsPassable = _mapFile.Tiles[n].TileType != "Inaccessible";
    47.  
    48.             // simple casting doesn't work, compile error
    49.             //((AreaScapeMapTile)grid[new RectPoint(nX, nY)]).IsPassable = _mapFile.Tiles[n].TileType != "Inaccessible";
    50.  
    51.             ++nX;
    52.             if (nX >= _mapFile.Width)
    53.             {
    54.                 nX = 0;
    55.                 ++nY;
    56.             }
    57.         }
    58.         BetterDebug.Assert(nY == grid.Height);
    59.  
    60.  
    61.         return (IGrid<TCell, TPoint>)grid;
    62.     }
    63. }
    64.  
    EDIT: Ok, from what I understand in the code, upon calling CustomGridBuilder.MakeGrid, the cell prefabs haven't been instantiated yet. So that could be why. I'm guessing I'm meant to edit the cell prefabs in a GridBehaviour instead?
     
    Last edited: Apr 20, 2015
  2. Jerome-P

    Jerome-P

    Joined:
    Apr 14, 2015
    Posts:
    34
    @Herman Tulleken I don't see any reference to "Sprite". UIImageCell does not have any, and BlockCell.cs does not have any either.
    Wouldn't it be quicker for everyone if you added a sample as suggested for us users who need that? I am a bit exhausted.
    That would be really nice. Thank you.
     
  3. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    Sorry I didn't read all 15 pages to see if this had already come up, but working alongside the tutorial in the "How to set up a grid in the editor (Using grids)" video, I find nothing happens when I turn on IsInteractive. There are no mouse hit visual indications like in your video. Any ideas what I might not have set up right?
     
  4. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    You need two classes.

    CustomGridBuilder is for dealing with a grid in some shape of your choosing. The grid builder uses this class to get an empty grid, then handle all the cell instantiation for you based on your selected prefab. (I realize now this is an important point to mention in the documentation!). At this stage, you should create a RectGrid<TileCell>. This class does not need to know anything about your particular cells.

    GridBehaviour is for doing further initialization on the cells (after they have been instantiated), and where you can set values. In this class it is useful to have a copy of the grid, since the Grid property is of type IGrid<TileCell, RectPoint>. This is also the typical place for your core game logic.

    I realize in your situation it is inconvenient, since you have the relevant data in in one file. I cannot really think of a non-hacky work-around. You will either need to read the file twice (not neat, but not a problem for small files), or cache the results and make sure you release resources once cells have been initialized. I will think about how we can deal better with this in the future.
     
    AnomalusUndrdog likes this.
  5. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Can you please paste your OnClick method? It's likely a small issue with that method.
     
  6. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Only for you ;)

    Attached is a package that is close to what you want.

    Everyone's games are quite different when it comes to cells. Your particular needs are quite unique. I say this, because it takes a long time to make these examples, and this one needs a lot of tweaking to work exactly the way you want. (Which is not abnormal - anything complicated takes some time to make).

    Since this particular example uses click to place the cells, I did not make the cells buttons. (If I had, the example would take too long). So you can either continue to use the OnClick in the grid code (potentially fire a message to the cell), or make the button instead, and adapt the clicking behaviour to your needs.

    The scaling is a bit mysterious; I did not have time to explore what is going on. I tested this with Unity 4, so it may behave slightly differently in Unity 5.
     

    Attached Files:

    Aggressor likes this.
  7. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Here is the code I run. Basically I want to highlight all movable possible positions.

    Code (csharp):
    1.  
    2. private static void ShowMovementRangeHighlight()
    3.     {
    4.         var moveRange = RangeFinder.GetPointsInRange(_unit.GetComponent<Unit>().gridPoint, _unit.GetComponent<UnitStats>().movement);
    5.         foreach(PointyHexPoint point in moveRange)
    6.         {
    7.             GameObject movementHighlight = Instantiate(_cellHighlight) as GameObject;
    8.             movementHighlight.transform.parent = GameGrid.grid[point].transform;
    9.             movementHighlight.transform.localPosition = new Vector3(0,0,0);
    10.             _cellHighlights.Add(movementHighlight);
    11.         }
    12.     }
    13.  
    Here is my GetPointsInRange

    Code (csharp):
    1.  
    2.     public static IEnumerable<PointyHexPoint> GetPointsInRange(PointyHexPoint startPoint, int range)
    3.     {
    4.         IEnumerable<PointyHexPoint> cellsInRange =
    5.             Algorithms.GetPointsInRange
    6.                 (GameGrid.grid,
    7.                 startPoint,
    8.                 (cell) => true,
    9.                 (p,q)=>1,
    10.                 range);
    11.  
    12.         return cellsInRange;
    13.     }
     
    Last edited: Apr 21, 2015
  8. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Also, side note, I upgraded to 1.13 and I get this error:
    Code (csharp):
    1.  
    2. Assets/Gamelogic/Plugins/Grids/Templates/FullLib/CompilerHints_GL.cs(19,29): error CS0101: The namespace `Gamelogic.Grids' already contains a definition for `__CompilerHintsGL'
     
  9. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    We moved the file :----/

    The correct file is in FullLib; you can safely delete the other one (that must have stayed behind from the previous version).
     
  10. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    I haven't edited anything, I was following your video tutorial with the (free) demo package downloaded and imported as it was. The video didn't say to edit or add any methods of our own at that stage.
     
  11. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,546
    @Herman Tulleken: Thanks for the reply! I was wondering, if I wanted to go the route of having a single mesh as the map (since I expect my maps to be very big), isn't having a cell prefab redundant? Having a game object per cell would also slow things down. I could handle everything in code, however I'm totally clueless since the grid builder classes seem to expect a cell prefab that it will instantiate. I saw the HexMesh example, but it doesn't seem to tie in with the Grid Builder, which I take it is the preferred way of building maps? I mean, if I were to use the HexMesh code, how will I connect that to my GridBehaviour class?
     
    Last edited: Apr 21, 2015
  12. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Question: Is your script attached to the Grid object that generates the grid?
     
    Last edited: Apr 21, 2015
  13. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    The video says to drag the pointyhexcell (sprite cell) script to the grid object which I did. I don't have any custom scripts yet, was just getting the feel for the gridbuilder by doing a tutorial in a new project with just this tool installed as a package. I thought the tutorial didn't assume we'd use anything other than what downloads with this tool?
     
  14. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Well you havent posted an images of your scene or your script so its hard to tell what you did wrong. I can tell you that it took me a while but I did get it working, so it does work. One more guess, and its a shot in the dark, is that you are using a gameobject from the scene instead of a prefab for the spritecell.
     
  15. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    Like I say, I didn't write a script so I wouldn't know what script to post. I was kind of thinking this question might be best aimed at the person who made the tutorial as he'd already be familiar with his script. But I'll double check whether I used the wrong type of game object for the cell, but I am pretty sure I did everything exactly as the video said, as I kept pausing it to make sure my actions matched what had been recorded.

    Since I originally posted my question I've built up a "grid" of tiles the long manual way, not using this grid utility, and scripted them to have a OnMouseEnter and that's working fine. I assumed that had already been set up in the GameLogic grids library, that's why I asked here rather than just diving in and writing my own event handler in order to continue with the tutorial
     
    Last edited: Apr 21, 2015
  16. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,546
    @Herman Tulleken: Ok, I figured things out on my own. Here I'm stress-testing it with a 100x100 square grid:



    Creating the map is expectedly slow as the mesh generation is taking a while. The framerate while viewing the map is not bad.

    It's the pathfinding that's slow. For a path about 30 or more squares long, the pathfinding starts to get slow.

    Unity actually crashed when I was trying to see the profiler while doing the pathfinding for the screenshot above (about 90 squares in length).

    Admittedly I'm not sure we'll ever need to pathfind something that long, I'm not even sure if we need a map that's 100x100 squares in size. I was only trying out how far it could go.

    I'm not putting in any heuristic estimate in there, which probably contributes to the slowness. However, the game I'm making requires the path to be the optimal shortest path (it's a game where characters can move up to a maximum of so and so number of squares per turn, so they need to take the path that eats up the least amount of that movement limit.

    I'll try to experiment a little more on this. If anyone has some tips on optimizing for my use case, please do point me in the right direction.
     
  17. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Hi,

    Sorry I haven't gotten back to you yet. I think the tutorial relies on old functionality of cells (they used to highight by default when you click on them). To get similar behaviour now you would need to do one of two things:

    Make your own cell script, and implement a OnClick() method that toggles the highlight. More information here:
    http://gamelogic.co.za/grids/documentation-contents/quick-start-tutorial/making-your-own-cells/

    Or

    Make your own grid behaviour, and implement a OnClick(PointyHexPoint point) method that does the highlight. More info here:
    http://gamelogic.co.za/grids/docume...k-start-tutorial/working-with-gridbehaviours/

    We removed the default behaviour because it was too specific. It was included in the first place to make examples easier, but in the end it caused confusion (because active steps had to be taken to remove the toggling|).

    (Definitely something we have to fix; thanks for letting us know!)
     
  18. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Just one note so far: remember the heuristic, as long as it follows the rule*, will not affect the quality of the path, it will only make the algorithm faster. (The idea is that the heuristic is used as a bound that allows the algorithm to quickly eliminate certain paths, instead of calculating their exact cost).

    *The rule is: the heuristic cost between nodes must not exceed the actual shortest distance between those two nodes.

    One easy heuristic is to use Euclidean distance (suitably scaled if your nodes have different costs), since that is always shorter than the actual distance. The closer your heuristic estimates the actual cost, the faster the algorithm will run. So the trick is to use knowledge about the game and your world to make a more accurate heuristic. For example, if you know that there is a choke point the units have to move through, you can use Euclidean distance from the start to this point plus Euclidean distance from this point to the node as the heuristic.

    Edit: Some more ideas:

    Another user managed to get his AStar to work in a separate Thread. Yet another approach would be to make the AStar into a coroutine and spread out the work over several frames.

    There is also the possibility to use a hierarchical scheme (make a graph of your space divided into bigger sections), or sample the grid and then first calculate the best sample path using AStar, and then use AStar on the actual grid as the unit move from section to section (or sample point to sample point). [This is not 100% accurate, of course].

    The above can also be used to make a lookup table for a very accurate heuristic, that could make the path-finding much faster. The smaller your sections (or the closer your samples), the faster you can make it, at the expensive of the extra memory.
     
    Last edited: Apr 22, 2015
  19. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    (From your other post I see that you figured it out, I just wanted to give some extra information). Indeed, you cannot directly use a single mesh with the GridBuilders. However, it's something that we really want to add, and the classes are designed with this addition in mind.

    For the moment, GridBuilders are the preferred way to work with grids as long as they do the job. Grids started out without them, and in many case constructing grids directly from the library gives a cleaner design, especially when using multiple grids, having a different way of rendering them (single mesh instead of tiles, for example), and the more so when you don't need to build things in the editor. GridBuilders cannot yet do everything the library is capable of. (It was out initial design philosophy to not make how grids get rendered as part of the library - grids where merely geometric data-structures. The demand for that aspect turned out to be quite high, so we changed it somewhat, but left all the flexibility there if it's needed.)
     
  20. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    That's fine, I can do that. Just wanted to be sure I hadn't simply misunderstood something :)
     
    Herman-Tulleken likes this.
  21. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,546
    Thanks Herman,

    I didn't know that about heuristics, thanks. I dabbled with my own A* code before, but I probably did it wrong cause the heuristics certainly affected the quality of the path on that one.

    It certainly did speed things up a lot when I added a DistanceFrom kind of heuristic.

    I also added the increased cost for diagonals to give the path less zig-zag effect. Instead of the magnitude (which I know uses square root), I even made my own check for diagonals:
    Code (CSharp):
    1.     bool AreRectPointsDiagonal(RectPoint a, RectPoint b)
    2.     {
    3.         if (
    4.             (a.X == (b.X-1) && a.Y == (b.Y+1)) ||
    5.             (a.X == (b.X-1) && a.Y == (b.Y-1)) ||
    6.             (a.X == (b.X+1) && a.Y == (b.Y+1)) ||
    7.             (a.X == (b.X-1) && a.Y == (b.Y-1))
    8.             )
    9.         {
    10.             return true;
    11.         }
    12.         return false;
    13.     }
    With the lambda being:
    Code (CSharp):
    1. (sta, end) => AreRectPointsDiagonal(sta, end) ? 1.44f : 1
    Thanks for all the help so far!



    One question: I used the HexMesh example as a template for my current code (I simply changed it so that it uses squares instead of hexes). The problem is, I can't access the created RectGrid I created from edit mode once the game starts. I tried turning those variables (i.e. the RectGrid and the IMap3D) into fields of the class and gave them [SerializeField], hoping they'd persist. They get values during edit time using the GenerateMesh method (just like in the HexMesh example) but they become null once you start the game. How do I solve this? I'm currently forced to call GenerateMesh every time the game starts.

    EDIT: Figured it out, I forgot to put System.Serializable on my cell class.
     
    Last edited: Apr 23, 2015
  22. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Updating to 1.13 fixed the pathfinding delay.

    My thanks!!!!
     
    Herman-Tulleken likes this.
  23. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Cool :)

    You can get a slightly faster diagonal test like this:

    Code (csharp):
    1. bool areNeighborsDiagonal = p.X != q.X && p.Y != q.Y;
    Two neighbors are diagonal only if they differ in both coordinates.

    (This is a micro optimization, and I am not sure that it will even have an effect, since the path finding is surely dominated by other aspects of the algorithm. But worth a test with the profiler.)
     
    Last edited: Apr 23, 2015
    AnomalusUndrdog likes this.
  24. MrMetraGnome

    MrMetraGnome

    Joined:
    Jul 16, 2014
    Posts:
    1
    Hello, this extension looks perfect for a few projects that I have in mind. Before I purchase the Grids Basic extension though, I need to be assured that it will function properly with Unity 5.
     
  25. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    It does work with Unity 5.
    You get a warning because we exported with Unity 4, and in the two 3D examples you have to select another shader for the prefabs. We saw recently it is now possible to upload separate packages for different versions of Unity, which we will do in the feature as long as we keep supporting Unity 4.
     
  26. DMeville

    DMeville

    Joined:
    May 5, 2013
    Posts:
    418
  27. Kelath

    Kelath

    Joined:
    Apr 2, 2015
    Posts:
    3
    Hello,

    Forgive me as I'm rather new to Unity, which doesn't help to begin with, but I purchased your basic grids package and am playing around with the StressTestHex scene... I've changed the camera prospective as follows:

    X: 2500
    Y: 4500
    Z: -800
    Rotation (X): 64
    Rotation (Z): 180
    Projection: Perspective

    And then I modified the code as follows, my problem is that the raycast isn't selecting the tile, I never get "here" to output and I'm wondering what I'm doing wrong... Most of your advance examples appear to be focused on the non-code side of your plug-in, which doesn't help me and my confused brain :)

    Code (CSharp):
    1. using Gamelogic;
    2. using Gamelogic.Grids;
    3. using System.Collections;
    4. using UnityEngine;
    5.  
    6. public class StressTestHex : GLMonoBehaviour
    7. {
    8.     public TileCell cellPrefab;
    9.     public int cellsPerIteration = 1000;
    10.     public Camera cam;
    11.     public int width = 500;
    12.     public int height = 500;
    13.  
    14.     private PointyHexGrid<TileCell> grid;
    15.     private IMap3D<PointyHexPoint> map;
    16.     private int totalCellCount;
    17.    
    18.     public void Start()
    19.     {
    20.         StartCoroutine(BuildGrid());
    21.     }
    22.    
    23.     public void OnGUI()
    24.     {
    25.         GUILayout.TextField("Hexes: " + totalCellCount);
    26.     }
    27.    
    28.     public void Update()
    29.     {      
    30.         if(Input.GetMouseButtonDown(0))
    31.         {
    32.             Debug.Log ("Mouse Down");
    33.        
    34.             var mousePosition = Input.mousePosition;
    35.             var ray = Camera.main.ScreenPointToRay(mousePosition);
    36.  
    37.             Debug.Log( ray );
    38.            
    39.             RaycastHit hitInfo;
    40.                        
    41.             if (Physics.Raycast(ray, out hitInfo))
    42.             {
    43.                 Debug.Log("here");
    44.             }
    45.  
    46.  
    47.         }  
    48.        
    49.         if(Input.GetKey(KeyCode.UpArrow))
    50.         {
    51.             cam.transform.position = cam.transform.position + Vector3.up * 10f;
    52.         }
    53.        
    54.         if(Input.GetKey(KeyCode.DownArrow))
    55.         {
    56.             cam.transform.position = cam.transform.position + Vector3.down * 10f;
    57.         }
    58.        
    59.         if(Input.GetKey(KeyCode.LeftArrow))
    60.         {
    61.             cam.transform.position = cam.transform.position + Vector3.left * 10f;
    62.         }
    63.        
    64.         if(Input.GetKey(KeyCode.RightArrow))
    65.         {
    66.             cam.transform.position = cam.transform.position + Vector3.right * 10f;
    67.         }
    68.     }
    69.    
    70.     public IEnumerator BuildGrid()
    71.     {
    72.  
    73.         totalCellCount = 0;
    74.         grid = PointyHexGrid<TileCell>.Rectangle(width, height);
    75.        
    76.         map = new PointyHexMap(new Vector2(69, 80)*3).To3DXY();
    77.        
    78.         int cellCount = 0;
    79.        
    80.         foreach(var point in grid)
    81.         {
    82.             var cell = Instantiate(cellPrefab);          
    83.             Vector3 worldPoint = map[point];
    84.  
    85.             cell.transform.localPosition = worldPoint;
    86.            
    87.             cellCount++;
    88.             totalCellCount++;
    89.            
    90.             grid[point] = cell;
    91.            
    92.             if(cellCount >= cellsPerIteration)
    93.             {
    94.                 cellCount = 0;
    95.                 yield return null;
    96.             }
    97.         }
    98.  
    99.     }
    100. }
    Any help would be appreciated, I'm just trying to click on the tiles currently, then I can play with it a bit more :)

    Thanks!
     
  28. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    DMeville likes this.
  29. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Do you have colliders on the cells?
     
  30. Kelath

    Kelath

    Joined:
    Apr 2, 2015
    Posts:
    3
    I do now and it works, thanks, sometimes its the simple things that are overlooked :)
     
  31. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Yup indeed. I have made the exact same mistake about 100 times. Glad it's working now :)
     
  32. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I have two hopefully quick questions. I'm wondering how dragging one tile to another tile position should be implemented. Right now I can move the tile with
    Code (csharp):
    1.  
    2. TileCell draggingCell;
    3.     void OnMouseDrag()
    4.     {
    5.         Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);
    6.         Vector3 curPosition = Managers.CAMERA.mainCamera.ScreenToWorldPoint(curScreenPoint) + offset;
    7.        
    8.         draggingCell.transform.position = curPosition;
    9.     }
    10.  
    11.     void OnMouseUp()
    12.     {
    13.         Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);
    14.         Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
    15.         Grid[MousePosition] = draggingCell;
    16.     }
    17.  
    18.  
    but doesn't put the dragging cell in the new location.
     
  33. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I'm guessing that I need to update the map somehow, but I'm not sure how to get the map in my inherited function.
    Code (csharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using Gamelogic.Grids;
    5. using Random = UnityEngine.Random;
    6.  
    7. public class LightsOutBehaviour : GridBehaviour<RectPoint>
    8. {
    9.     //private RectGrid<TileCell> rectGrid = (RectGrid<GPTileCell>)Grid;
    10.     private IGrid<GPTileCell, RectPoint> lightsOutGrid;
    11.     //RectGrid<GPTileCell> rectGridWithSpriteCells = (RectGrid<GPTileCell>)lightsOutGrid;
    12.     private Vector3 offset;
    13.     float delay = 0.1f;
    14.     private float clickTime = 0.0f;
    15.     GPTileCell draggingCell;
    16.     private IMap3D<RectPoint> map;
    17.  
    18.     // Use this for initialization
    19.     void Start ()
    20.     {
    21.         Input.simulateMouseWithTouches = true;
    22.     }
    23.      
    24.     override public void InitGrid()
    25.     {
    26.         lightsOutGrid = Grid.CastValues<GPTileCell, RectPoint>();
    27.        
    28.         foreach (var point in lightsOutGrid)
    29.         {
    30.             lightsOutGrid[point].IsOn = Random.Range(0, 1) == 1;
    31.         }
    32.     }
    33.  
    34.     void Update()
    35.     {
    36.         int touchCount = Input.touchCount;
    37.  
    38.         if (Input.GetMouseButtonDown(0))
    39.         {
    40.             clickTime = Time.time;
    41.             OnMouseDown();
    42.         }
    43.         if (Input.GetMouseButtonUp(0))
    44.         {
    45.             if (Time.time - clickTime <= delay)
    46.             {
    47.                 OnMouseUp();
    48.             }
    49.         }
    50.         if (Input.GetMouseButton(0))
    51.         {
    52.             if (Time.time - clickTime > delay)
    53.             {
    54.                 OnMouseDrag();
    55.             }
    56.         }        
    57.     }
    58.  
    59.     void OnMouseDown()
    60.     {
    61.  
    62.         //offset = gameObject.transform.position - Managers.CAMERA.mainCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
    63.         Grid[MousePosition].Color = Color.red;
    64.         draggingCell = lightsOutGrid[MousePosition];
    65.     }
    66.  
    67.     void OnMouseDrag()
    68.     {
    69.         Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);
    70.         Vector3 curPosition = Managers.CAMERA.mainCamera.ScreenToWorldPoint(curScreenPoint) + offset;
    71.        
    72.         draggingCell.transform.position = curPosition;
    73.     }
    74.  
    75.     void OnMouseUp()
    76.     {
    77.         Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane);
    78.         Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
    79.  
    80.         lightsOutGrid[MousePosition] = draggingCell;
    81.         //Grid[MousePosition] = draggingCell;
    82.         draggingCell = null;
    83.     }
    84. }
    85.  
    86.  
     
  34. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    It helps if you think of a Grid as a container (like an array), that just happens to contain game objects placed in positions calculated by the map. So just like swapping two game objects in an array won't change their screen positions, cells stay put regardless of their logical position in the grid. All you need to do is reset their positions as calculated by the map, using their new logical coordinates.

    So here is the normal pattern for swapping two cells in a grid:

    Code (csharp):
    1. //we swap the cells at rect points p1 and p2
    2.  
    3. //first, we swap them logically in the grid
    4. var tmp = grid[p1];
    5. grid[p1] = grid[p2];
    6. grid[p2] = cell;
    7.  
    8. //then, we update their physicall positions in the world to match:
    9. grid[p1].transform.localPosition = map[p1];
    10. grid[p2].transform.localPosition = map[p2];
     
  35. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    Great! I'm starting to understand the framework a little better now. I did notice that the numbers in the editor on the tiles aren't updating when they swap. Do I need to do something additional or can I just ignore that?
     
  36. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    Also sometimes when I build the grid all my images disappear, I'm not sure what's causing that.
     
  37. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    Yes, those are actually displaying the names of the cells. I find it useful when implementing tricky algorithms to see what exactly is happening. To make that work with swapping:

    Code (csharp):
    1. //we swap the cells at rect points p1 and p2
    2.  
    3. //first, we swap them logically in the grid
    4. var tmp = grid[p1];
    5. grid[p1] = grid[p2];
    6. grid[p2] = cell;
    7.  
    8. //then, we update their physicall positions in the world to match:
    9. grid[p1].transform.localPosition = map[p1];
    10. grid[p2].transform.localPosition = map[p2];
    11.  
    12. //and finally update the cells' names to reflect their new positions:
    13. grid[p1].name = p1.ToString();
    14. grid[p2].name = p2.ToString();
     
  38. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    How do you get them back? By just rebuilding the grid again?
     
  39. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    That's what happened last night but now I'm just having all the tiles go to white and not come back to the sprite. What dictates how the tiles are shown when you click build grid? I have set the sprite frame index in the custom sprite cell i'm using. Which is inherited from SpriteCell.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using Gamelogic;
    5. using Gamelogic.Grids;
    6.  
    7. public class GPTileCell: SpriteCell
    8. {
    9.     private bool isOn;
    10.     public bool IsOn
    11.     {
    12.         get { return isOn; }
    13.         set
    14.         {
    15.             isOn = value;
    16.             Color = Color.red;
    17.         }
    18.     }
    19.  
    20.     public void OnClicked()
    21.     {
    22.  
    23.     }
    24. }
    25.  
    26.  
     
  40. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I figured out that my GPTileCell was using the Square still
     
  41. CzarKirby

    CzarKirby

    Joined:
    Apr 20, 2015
    Posts:
    1
    I am fairly unskilled programmer but have been experimenting with your trial grid package to try and figure out how to recreate a rts style building placement. What i am looking for is when a player tries to place a building a ghost image will snap around the grid. the problem i am facing is that i want my buildings to be bigger than one grid, say a 4x4 grid size building but u can move the image around by 1x1 increments. think warcraft/starcraft.

    is there a way to manually give each grid an isBuildable flag so a texture can render on the fly with the ghost building and then only allow the building to be instanced if all grid areas under it are build-able any help would be much appreciated and would definitely convience me to purchase the package.
     
  42. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    So does using the right cell work now? Or do you still need help with this?
     
  43. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    What you want to do is indeed possible, but not without some programming.

    I'm breaking your question down into the various parts.

    Making cells with a ghost texture. Almost all games require you to define your own cells (this is normal best practice using Grids). In your case, you need to build a cell prefab with an extra layer for the cost texture. You then need to define a component in code to maintain the isBuildable bool, and handle displaying and coloring of the ghost texture. Something like this:

    Code (csharp):
    1. class MyCell : TileCell
    2. {
    3.    public gameObject ghost;
    4.    private bool isBuildable;
    5.  
    6.    public void ShowGhost()
    7.    {
    8.       ghost.SetActive(true);
    9.       ghost.GetComponent<Renderer>().material.color = red;
    10.    }
    11.  
    12.   //and a bit more code
    13. }
    Working with multiple cells. This part is a bit trickier. A few posts ago I posted an example with objects occupying multiple cells. It's not a lot of code, but it will be important to understand it well. The basic idea is when placing an object, to find out all the grid cells it occupies, and write references to the object into all the cells the object occupy. objects "know" which cells they will occupy if their anchor is placed at the origin, and you can use this to calculate the cells the object will occupy anywhere else. (This is all done in that example).

    Snapping. This is the easy part. Assuming you can access the map from where you do the snapping it will be something like this:

    Code (csharp):
    1. building.transform.localPosition = map[map[worldPosition]]
    (this converts the world point to a grid point, and then the grid point back to a Vcetor3 at the cells center (or corner, depending on your configuration).

    ----

    Let me know if you need some elaboration.
     
  44. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    Just to let you know the lite version of grids contains an error on iOS. In the polar grid file you have compiler hints for the more complicated layouts which don't exist, all you have to do is delete them and it's fine.
     
    Herman-Tulleken likes this.
  45. Testeria

    Testeria

    Joined:
    Aug 15, 2013
    Posts:
    18
    Hello,
    few questions about grids.
    1. If I buy light or basic for testing is there any upgrade/discount for full version of grids? As I understand there is nothing in lite that is absent from full version so they are basicly upgrades...
    2. Is it possible with grids to make risk-like grid placed on political map? Something like in Crusader Kings II game by Paradox.
    3. Is it possible to use grids on server-side to validate player input or it is unity/client side only?


    Thanks,
     
  46. Herman-Tulleken

    Herman-Tulleken

    Joined:
    Nov 20, 2009
    Posts:
    358
    1. Yes. Although we do not have an upgrade path available through the asset store, you can upgrade through our other store (Fast Spring). We effectively give you a discount voucher for the package you have already bought.

    2. I am not sure what aspect exactly you are referring to. If you mean, can you have grids with weird shapes (like countries), the answer is yes, although there are quite a few things you would need to implement. In such a case, Grids will mostly help you with algorithms that work on graphs or in other words, only depends on cell neighbors (path finding, range finding, aggregation, etc.). I am not sure that those games will benefit much, but perhaps you want to implement some interesting mechanics.

    3. I am not 100% sure, to be honest, since I am not sure how game code that interfaces with Unity is normally deployed on a server. The library itself is only very slightly dependent on Unity, if you ignore the editor functionality. It's basically limited to VectorX, Rect, Random, Debug (maybe). The cells may interface with more Unity components. If you know anything about how this normally works and explain it to me, I can give you a better answer.
     
  47. Deozaan

    Deozaan

    Joined:
    Oct 27, 2010
    Posts:
    707
    Your website is down.

     
    Herman-Tulleken likes this.
  48. TimK_personal

    TimK_personal

    Joined:
    Jul 30, 2014
    Posts:
    18
    Herman-Tulleken likes this.
  49. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I'm a bit confused again, what should my local map be? I'm currently using Map and it's working ok but I'm afraid of issues which may arise later.
    Code (csharp):
    1.  
    2. rectGrid = (RectGrid<TileCell>)Grid;
    3. IGrid<GPTileCell, RectPoint> gridWithSpriteCells = rectGrid.CastValues<GPTileCell, RectPoint>();
    4. rectGridWithSpriteCells = (RectGrid<GPTileCell>)gridWithSpriteCells;
    5.  
    Or is there any way to override it so that Map and Grid give me the proper casts?
     
  50. Aggressor

    Aggressor

    Joined:
    Aug 10, 2012
    Posts:
    62
    Howdy

    So for the pathfinding algorithm, the 5th parameter is TCell accessibility function. However, this to me seems a poor choice? Shouldn't it check if the TPoint is available instead since that what we are keeping track of?

    Is there a quick way I can get the point from a TCell object? I am noticing my IGrid object doesn't have the 2-way accessor that the Vector3 and Point map did.