Search Unity

Grid game - best way to start

Discussion in '2D' started by mjmurray, Jul 24, 2014.

  1. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    Hi there,

    I'm an okish coder and I'm getting used to Unity. I have a great idea but I haven't got a clue as to the best way to start it. Could anyone point me in the right direction so I don't go down a bunch of dead ends.

    Imagine a grid 5 squares wide and 21 squares high. Imagine each square has a gem in it. I want to be able to slide only the middle row left and right and also be able to slide each row up and down.

    Any one have any ideas or tutorials which might point me in the right direction?
     
  2. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7


    Something a bit like this
     
  3. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    Don't know of any tutorials, but its not too complex to do. I just recently built a game prototype using that exact mechanic. Really all you need to do is make the gem draggable, and then just move the others at the same time. Presumably you are using a 2d array, so you just update all the row or column at the same time. The only minor challenge was accounting for the wrap around, since you will need to display the end gem in two places. What I did was make a "proxy" gem that contained a copy of all the sprites, and moved that to the ends, turning on/off the sprites I needed to display. Here is what it looked like:

     
    mjmurray and JayJennings like this.
  4. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    That is a thing of beauty ZombieGorilla! That is 99.9% of the game mechanics I need. I don't suppose you could give me any tips on how to start it? How did you go about getting the grid started? Is it best to do it in 2d or 3d? Did you code it off the top of your head or use any pre existing frameworks? It looks amazing!! It's really inspired me that my project can be done in unity.
     
  5. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    Thanks! It was fun to build. It was somewhere between a prototype/exploration and tech test. The idea was try fluid prototyping. Rather than create a full GDD & Design Doc, we started with a rough concept, 2 producers, 2 designers and a developer (me). We basically got together for 2 weeks and built/changed it on the fly. We would test ideas right in a game rather than on paper. The character and some of the backgrounds were put together by a concept artist, the rest I either created or grabbed from old games.

    It is more than just the match-3, it also has pet battles, pet training, a farming and crafting component and progression map, as well as animation and cut scenes.

    slant.jpg
    It is pretty much all scratch built, the only 3rd party things I used were HOTween and EasyFont. No framework was used but, it did become a framework itself, mostly for the animation and event sequencing. It was also a tech test, as I started it right after the Unity 2D features came out. So the whole thing uses the Unity 2D features.

    The match-3 part started as a traditional swapping game, then became one where you draw to connect gems, then the sliding version. All 3 are still part of the game, and can be switched on and off.

    I have done a couple of match3 games on other platforms, and generally speaking I do them like this:

    The 'gems' are fairly self-contained and contain many of their own methods for animation. The board uses a 2d array (Gems[,]), I then start with methods for

    Fill - this finds all the holes in the array and creates new gems for them.

    Check - this is called after the user makes a move or the board is filled. It uses a simple recursive method to walk the board and build an array of matches. It will return either null (no matches) or an array of killsets (an array of arrays of matches).
    - if there no matches it return control of the board to the user
    - if there are matches, it plays the animations to remove them and then...

    Compress - this just shifts all the gems downward to fill gaps. After compression, it goes back to Fill.

    That is the main loop: Fill, Check, Compress, Fill, Check, Compress, etc...

    I use HOTween (love it) sequences for most of the gem animation. For example, when I fill the board, for each gem I add, I add a tween of the drop to the sequence. When I have found all the holes I call sequence.Play(), and it has a single callback (OnComplete) that moves to the check method. The gem removal and compressions have their own sequences as well. Makes for a clean way to move from state to state.

    Hope that helps!
    ZG
     
  6. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    Thanks so much for pointing me in the right direction! The game really does look great and the gameplay looks very fluid. In a sea of match 3 type games its nice to see that you have done something different and taken it in a different direction. If my game turns out to look 10% as good as yours I'll be happy!

    Thanks again for taking the time to write such a detailed reply.
     
  7. smitchell

    smitchell

    Joined:
    Mar 12, 2012
    Posts:
    702
    Yeah as zombie gorilla stated it really won't be as hard as you're probably imagining in your head.

    say you stored your grid items in a array when the user is holding a gem just move all the gems with say the same x position vertically or with the same y position in the horizontal direction.

    I wouldn't actually use the exact x and y position since floating point precision will be a whore but when you create your grid if you give it a int value for x and y it'll work nicely. Then modify when your grid moves.
     
  8. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    I hope it turns out to be that easy Smitchell - My brain is one of those that takes an existing idea and makes it better. I love tweaking and improving things. Getting started is such an effort for me lol. Glad there is such a great community here for all my questions..

    I just didn't want to spend hours doing things the wrong way o_O
     
  9. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    The game is progressing quite nicely. It wasn't as hard as expected but there was definitely one or two headbanging moments...which leads me on to a question that has me stumped. How exactly did you do the wrap around gem? I'm using hotween (which is excellent as you say) and I can't for the life of me figure out how to smoothly make the gems wrap around....any tips or pointers would be a great help.
     
  10. smitchell

    smitchell

    Joined:
    Mar 12, 2012
    Posts:
    702
    What exactly do you mean by wrap around?
     
  11. mjmurray

    mjmurray

    Joined:
    Jul 24, 2014
    Posts:
    7
    well at the moment I press the space bar and all the gems on a row move to the left of the screen. I want the gem that is furthest on the left to smoothly wrap around and then come on to the right of the screen. If you look at zombie gorilla's demo the wrap around is very smooth.

    On his first post he mentions using a proxy gem, but I can't for the life of me work out how its done.
     
  12. smitchell

    smitchell

    Joined:
    Mar 12, 2012
    Posts:
    702
    it shouldn't be too hard.
    if the gem's x pos is less than your boundary, set it to the last gems position (in the opposite side) + gem distance.

    (pseudo code)
    foreach (Gem gem in GemsArray) {
    if(gem.x <= borderMax) {
    gem.x == GemsArray[GemsArray.length - 1].xPosition + gemDistance;
    }
    //And do the same for the other side, and vertical of course.
    }
     
  13. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    That's not what he is referring to, he is talking about the visual appearance when a gem is transitioning. When a gem is half way off of one side it appears on the other as well. (basically in two places at once).

    Hopefully this will clarify how I am using a proxy:
    proxy_explained.jpg
    So, in addition to the pool of gems I use on the grid, I have one additional gem that I use as a proxy for the transition, basically it is like the rest, I just hide it when not in use.
    A) The proxy gem is just turned off when not in use
    B) When the user starts to drag a row (or column), I move the proxy the opposite side of the direction it being moved in, and the color (style) is set to the same as the front side.
    C) It is moved along with rest of the row so it give the appearance that the gem is wrapping.
    D) As the front gem is moved past 100% of the width, the front gem is shifted to the back position and the proxy is bumped back and color changed to match the new front edge gem.

    The logic isn't overly complicated, I just bolted it onto the drag methods on the slider version of the logic. It really only amounts to a few additional lines on the drag and init drag and release drag.

    Hope that helps,
    ZG.
     
    Last edited: Aug 20, 2014
  14. anil4029

    anil4029

    Joined:
    Jun 2, 2015
    Posts:
    7
    hey I tried this but can you help me please...I am able to form grid and all gems are drag able but how can I move all objects of row and column in one direction..I am trying from 1 week but failed.
    @zombiegorilla
     
  15. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    What is going on specifically? What have you tried? Post the code you have so far, and we might be able to help.
     
  16. anil4029

    anil4029

    Joined:
    Jun 2, 2015
    Posts:
    7
    Thank you very much for reply :)
    I tried a grid of 6x6 each square has a gem in it. Now I want to slide only the row left and right and also be able to slide column up and down.

    I tried different approaches :

    First :
    • Formed grid
    • gems are move according to touch(touch or mouse position) along x and y axis.
    • to select row and column I made a prefab (empty gameobject with boxcollider like "+" sign) and deactivate it in scene.
    • when I touch I set this prefab active and once I start drag I deactivate it. So when it's active I selected gems which collide with it.
    • Now when I drag in any direction x or y. I keep track of start position of touch and last one to check in which direction player is dragging and block other direction so player can drag in only one direction.
    Second :
    Little bit similar to 1st but in this I tried to select gems with raycast and make them child of dragable gameobject which only drag able along x or y axis. and once touch-up I detach them from parent gameobject.
    Third :
    I tried your approach to form grid and make gems dragable but I still don't know how to select and update all row and column gems position in particular direction smoothly.​


    I tried this tutorial of 3 match type game






     
  17. anil4029

    anil4029

    Joined:
    Jun 2, 2015
    Posts:
    7
    @zombiegorilla can you please give me any hint or suggestions on how to select and move all gems in row and column.
     
  18. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    Apply the transform position (offset) to all the gems in the row or col, from the one you are dragging. You don't need use colliders or parent them, just update their positions when you are dragging.
     
  19. anil4029

    anil4029

    Joined:
    Jun 2, 2015
    Posts:
    7
    But how do I know which one is dragging.


    These are my scripts :

    To form Grid :

    Code (CSharp):
    1. public class Tile
    2. {
    3.     public GameObject tileObj;
    4.     public string type;
    5.     public Tile(GameObject obj,string t)
    6.     {
    7.         tileObj = obj;
    8.         type = t;
    9.     }
    10. }
    11.  
    12. public class GridFormation : MonoBehaviour {
    13.  
    14.     public GameObject tile;
    15.     private static int row = 6;
    16.     private static int cols = 6;
    17.     private Tile[,] tiles = new Tile[cols, row];
    18.  
    19.  
    20.     private void Start()
    21.     {
    22.         for(int r = 0; r < row; r++)
    23.         {
    24.             for(int c = 0; c < cols; c++)
    25.             {
    26.                 Vector3 tilePos = new Vector3(c, r, 0);
    27.                 GameObject go = (GameObject)Instantiate(tile, tilePos, tile.transform.rotation);
    28.                 tiles[c, r] = new Tile(go, go.name);
    29.             }
    30.         }
    31.     }
    32. }
    To Hold Movement along x or y axis :

    Code (CSharp):
    1. public class HoldMovement : MonoBehaviour {
    2.  
    3.    
    4.     private bool startHodling;
    5.     private Vector3 startPos = Vector3.zero;
    6.     private float holdDis = 1;
    7.    
    8.  
    9.     void Update () {
    10.  
    11.         // to hold direction along x or y axis
    12.         SelectDirection();
    13.     }
    14.    
    15.  
    16.     private void SelectDirection()
    17.     {
    18.         if (Input.GetMouseButtonDown(0))
    19.         {
    20.             startPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
    21.  
    22.         }
    23.  
    24.  
    25.         if (startHodling == false && Input.GetMouseButton(0))
    26.         {
    27.             Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
    28.            
    29.             if (startPos.x - curScreenPoint.x > holdDis || startPos.x - curScreenPoint.x < -holdDis)
    30.             {
    31.                 Draging.dragX=true;
    32.                 startHodling = true;
    33.             }else if (startPos.y - curScreenPoint.y > holdDis || startPos.y - curScreenPoint.y < -holdDis)
    34.             {
    35.                 Draging.dragY = true;
    36.                 startHodling = true;
    37.             }
    38.            
    39.         }
    40.        
    41.  
    42.         if (Input.GetMouseButtonUp(0))
    43.         {
    44.             startHodling = false;
    45.         }
    46.     }
    47. }
    For Dragging :
    Code (CSharp):
    1. public class Draging : MonoBehaviour
    2. {
    3.     private Vector3 screenPoint;
    4.     private Vector3 offset;
    5.     public static bool dragX, dragY;
    6.  
    7.  
    8.    
    9.     void OnMouseDown()
    10.     {
    11.         Vector3 pos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
    12.         offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(pos);
    13.     }
    14.  
    15.     void OnMouseDrag()
    16.     {
    17.        
    18.      
    19.         if (dragX)
    20.         {
    21.             // to move along x axis only
    22.             Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
    23.             Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
    24.             Vector3 pos = transform.position;
    25.             pos.x = curPosition.x;
    26.             transform.position = pos;
    27.         }
    28.         else if (dragY)
    29.         {
    30.             // to move along y axis only
    31.             Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
    32.             Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
    33.             Vector3 pos = transform.position;
    34.             pos.y = curPosition.y;
    35.             transform.position = pos;
    36.  
    37.         }
    38.        
    39.     }
    40.  
    41.     private void OnMouseUp()
    42.     {
    43.         dragY  = false;
    44.         dragX = false;
    45.     }
    46.  
    47. }
     
  20. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    Several different ways. You can set row/col on the object (how I typically do it), or you could just calculate it from the position.
     
  21. anil4029

    anil4029

    Joined:
    Jun 2, 2015
    Posts:
    7
    can you please explain in detail. on which object should I set or how can I calculate from position ??
     
  22. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    You can add a row and col var to your Tile class, and set/update it when you move it. Then when go to drag it, you can see what col or row it is in, and move the others with the same col/row. If you want to get it by position, you can just divide the or x or y by the grid size.