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
  4. Dismiss Notice

in game snap to grid

Discussion in 'Scripting' started by pat_sommer, Feb 7, 2011.

  1. pat_sommer

    pat_sommer

    Joined:
    Jun 28, 2010
    Posts:
    586
    hey everyone,

    how can i go about making an object have a snap to grid feature while in game?

    my current solution is to space apart empty game objects evenly around the level where snap is needed, but this can come out to be A LOT of points.

    say i need the object to be able to be snapped every 1 unit, is there a more code efficient way to go about this?

    thanks
     
    yossigor likes this.
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Code (csharp):
    1. var currentPos = transform.position;
    2. transform.position = Vector3(Mathf.Round(currentPos.x),
    3.                              Mathf.Round(currentPos.y),
    4.                              Mathf.Round(currentPos.z));
    --Eric
     
  3. Kokumo

    Kokumo

    Joined:
    Jul 23, 2010
    Posts:
    416
    Impressive.
     
    Last edited: Feb 7, 2011
  4. pat_sommer

    pat_sommer

    Joined:
    Jun 28, 2010
    Posts:
    586
    awesome! ill check it out thanks
     
  5. GameDevionist

    GameDevionist

    Joined:
    Aug 7, 2012
    Posts:
    3
    Mathf... There we meet again... :p

    Thanks for the code Eric.
     
  6. coingod

    coingod

    Joined:
    Aug 6, 2013
    Posts:
    16
    Note to self: Don't over complicate simple things.

    Thanks Eric.
     
  7. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,384
    Man.. Why is everything Eric posts so simple and profound?
     
  8. PhysicalBeef

    PhysicalBeef

    Joined:
    Jun 13, 2013
    Posts:
    150
    how can you make it snap to a bigger, wider grid?
     
  9. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    Try this (I haven't tested but it seemed logical to me).

    Code (csharp):
    1.  
    2.     var currentPos = transform.position;
    3.     transform.position = Vector3(Mathf.Round(currentPos.x * 10),
    4.                                  Mathf.Round(currentPos.y * 10),
    5.                                  Mathf.Round(currentPos.z * 10));
    6.  
    Or try multiply by 100 or 1000, whatever :)
     
  10. Bivrost

    Bivrost

    Joined:
    Mar 26, 2014
    Posts:
    80

    Sorry, but that's incorrect. It's simply the other way around.

    To get an object's position on a grid, you have to divide its position by the grid size.
    So in case of a three dimensional grid, you'd calculate the position as follows:

    Code (csharp):
    1.  
    2. Vector3 currentPos = transform.position;
    3. transform.position = Vector3( Mathf.Round( currentPos.x / gridSize.x ),
    4.                               Mathf.Round( currentPos.y / gridSize.y ),
    5.                               Mathf.Round( currentPos.z / gridSize.z ) );
    6.  
     
    pachermann likes this.
  11. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    I guess that's how we learn thanks.
     
    bbstilson likes this.
  12. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Another option: try

    Mathf.Round(currentPos.x) * grid_scaling_size;

    // multiplying AFTER rounding, which will "spread out" the otherwise unit-based grid if multiplying by values greater than 1, and will "squeeze" it if multiplying by values between 0 and 1.
    // grid_scaling_size could also be a random value for craziness…
     
  13. Bivrost

    Bivrost

    Joined:
    Mar 26, 2014
    Posts:
    80
    Of course, that's the great thing about coding. And I'm sorry, willemsenzo, I didn't want to sound too harsh, arrogant or even disrespectful.
     
    Last edited: Apr 15, 2014
  14. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    If you want objects to keep as close to their original position as possible, but with a larger grid, you could use:

    Code (csharp):
    1. var currentPos = transform.position;
    2. transform.position = Vector3(Mathf.Round(currentPos.x / grid_scale) * grid_scale,
    3.                              Mathf.Round(currentPos.y / grid_scale) * grid_scale,
    4.                              Mathf.Round(currentPos.z / grid_scale) * grid_scale);
     
    Last edited: Apr 15, 2014
  15. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    Don't worry I don't feel offended in any way :)
     
    StrangeWays777 and The-Sam like this.
  16. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Great thread, I plan to use some of the ideas on here. Could be very useful. Thanks everyone!
     
  17. youngapprentice

    youngapprentice

    Joined:
    Apr 10, 2010
    Posts:
    260
    Just throwing in my two cents. I wrote a simple function that runs through an array of Vector2s (Or Vector3s) and returns the index of the position that is currently closest to yours.

    Code (CSharp):
    1.     int CompareSet( Vector2[] myArray, Vector2 pos ){
    2.         int closestIndex = 0;
    3.         float smallestDistance = 0.0f;
    4.         for( int u = 0; u < myArray.Length; u++ ){
    5.  
    6.             if( u != 0 ){
    7.  
    8.                 float thisDistance = (pos - myArray[u]).sqrMagnitude;
    9.  
    10.                 closestIndex =  ( thisDistance < smallestDistance ) ? u : closestIndex;
    11.                 smallestDistance = ( thisDistance < smallestDistance ) ? thisDistance : smallestDistance;
    12.  
    13.             }
    14.  
    15.             else smallestDistance = (pos - myArray[u]).sqrMagnitude;
    16.  
    17.         }
    18.  
    19.         return closestIndex;
    20.  
    21.     }
     
    NeatWolf and NordicIsle like this.
  18. astralislux

    astralislux

    Joined:
    Aug 8, 2014
    Posts:
    10
    Still learning this. Could someone apply this in an example?

    Code (CSharp):
    1. Vector3 currentPos = transform.position;
    2. transform.position = Vector3( Mathf.Round( currentPos.x / gridSize.x ),
    3.                               Mathf.Round( currentPos.y / gridSize.y ),
    4.                               Mathf.Round( currentPos.z / gridSize.z ) );
     
    Last edited: Aug 28, 2014
  19. devstudent14

    devstudent14

    Joined:
    Feb 18, 2014
    Posts:
    133
    Yes I'd like to second that. I've tried to apply this to moving a cube around the terrain according to a grid but ended up with all kinds of errors.
     
  20. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,848
    Well, so far all we've talked about here is how to round numbers (note: only Errorsatz's post above does this correctly for a grid size other than one).

    To actually apply this, we'd need to know more about what you're trying to accomplish... I mean, sure, you can snap an object to a grid, but how does it move? Does it move at all? Do you want it to slide smoothly from one grid position to another, and then snap? Or can it just jump from one grid position to the next? Are objects falling in from outer space, and you want them to only land on even grid positions? What?

    Cheers,
    - Joe
     
  21. devstudent14

    devstudent14

    Joined:
    Feb 18, 2014
    Posts:
    133
    Hello JoeStrout. Thanks for the offer of help. Originally I wanted to move a building around the map according to a grid so it would be easier to place the buildings in perfectly straight lines. Since writing that comment I've found out that I do not need a grid to do this as I can just round to the nearest coordinate in unity. I will need to go back to grids soon though as I'm developing a turn-based combat system with tile-based movement (similar to fallout 1,2, wasteland 2 etc.).

    So far I think I will need to instantiate a grid when combat begins and then limit movement to the tiles of that grid and to the number of points the player has to move (1 point = 1 grid square). I want the grid to be square and I want to allow diagonal movement and attack so it would have eight directions. The movement between grids should be smooth. I would also need to find a way to tie Aron Granberg's pathfinding into the grid so the units find the shortest route to the destination and avoid obstacles when they move.

    I definitely don't expect anyone to have any ready made solutions to this. However any pointers in the right direction in regards any of the points raised would be appreciated.
     
    Deathstarengineer likes this.
  22. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,848
    You might look through the Asset Store... something like this or this might help.

    Good luck,
    - Joe
     
    devstudent14 likes this.
  23. devstudent14

    devstudent14

    Joined:
    Feb 18, 2014
    Posts:
    133
    Thank you. If purchased assets allow you to look at the original code then this would be a great way to learn how to do some of these things.
     
  24. bradywestveer

    bradywestveer

    Joined:
    Mar 18, 2015
    Posts:
    6
    Make sure you use a new Vector3 in C#
    Code (CSharp):
    1. Vector3 currentPos = transform.position;
    2.         gameObject.transform.position = new Vector3(Mathf.Round(currentPos.x), Mathf.Round(currentPos.y), Mathf.Round(currentPos.z));
     
    hassancortex likes this.
  25. JGriffith

    JGriffith

    Joined:
    Sep 3, 2012
    Posts:
    22

    Old thread I know but I read it after searching as to why my function wasn't working and have some code that gives you an example.(FYI, MY problem was actually that I'm tired and used getkeydown instead of getkey and didn't notice, lol)

    Code (CSharp):
    1.             Vector3 MouseWorld = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -GetComponent<Camera>().transform.position.z - 5.0f));
    2.  
    3.             if (Input.GetKey(KeyCode.LeftControl))
    4.             {
    5.                 EditorPrefab.transform.position = new Vector3(((int)(MouseWorld.x / GridSize.x)) * GridSize.x, ((int)(MouseWorld.y / GridSize.y)) * GridSize.y, -5.0f);
    6.             }
    7.             else
    8.             {
    9.                 EditorPrefab.transform.position = MouseWorld;
    10.             }
     
    Last edited: Jan 12, 2016
  26. TimBibbee

    TimBibbee

    Joined:
    Feb 11, 2017
    Posts:
    1
    I made a forum account just to say that you are brilliant.
     
    JoeStrout likes this.
  27. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Well, thank you. Welcome to the forums!

    --Eric
     
  28. Gryffind96

    Gryffind96

    Joined:
    Mar 21, 2015
    Posts:
    3
    If I want to have differents prefab with diferen grid size of ocuppation for example house 4*4 bank 2*2 how can attack this problem with this piece of script:
    1. Vector3 currentPos = transform.position;
    2. transform.position = Vector3( Mathf.Round( currentPos.x / gridSize.x ),
    3. Mathf.Round( currentPos.y / gridSize.y ),
    4. Mathf.Round( currentPos.z / gridSize.z ) );
     
  29. Arno1975

    Arno1975

    Joined:
    Aug 14, 2013
    Posts:
    43
    I followed this amazing tutorial :


    how do i get that grid in there..can't figure it out...it uses a transform to instantiate a gameobject..but how do i link this to the grid can't get it done..

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class StructurePlacement : MonoBehaviour {
    6.  
    7.  
    8.     private Transform currentStructure;
    9.     private PlaceableStructure placeableStructure;
    10.     private Camera cam;
    11.     private bool hasPlaced;
    12.    
    13.  
    14.     public LayerMask structureMask;
    15.  
    16.     // Use this for initialization
    17.     void Start() {
    18.         cam = Camera.main;
    19.     }
    20.  
    21.     // Update is called once per frame
    22.     void Update()
    23.     {
    24.         Vector3 m = Input.mousePosition;
    25.         m = new Vector3(m.x, m.y, transform.position.y);
    26.         Vector3 p = cam.ScreenToWorldPoint(m);
    27.  
    28.         if (currentStructure != null && !hasPlaced)
    29.         {
    30.  
    31.             currentStructure.position = new Vector3(p.x, 0, p.z);
    32.  
    33.             if (Input.GetMouseButtonDown(0))
    34.             {
    35.                 if (IsLegalPosition())
    36.                 {
    37.                     hasPlaced = true;
    38.                 }
    39.             }
    40.         }
    41.         else
    42.         {
    43.             if (Input.GetMouseButtonDown(0))
    44.             {
    45.                 RaycastHit hit = new RaycastHit();
    46.                 Ray ray = new Ray(new Vector3(p.x, 8, p.z), Vector3.down);
    47.                 if (Physics.Raycast(ray, out hit, Mathf.Infinity, structureMask))
    48.                 {
    49.                     Debug.Log(hit.collider.name);
    50.                     //destroy the object that is clicked
    51.                     Destroy(hit.collider.gameObject);
    52.                 }
    53.             }
    54.         }
    55.     }
    56.  
    57.  
    58.     bool IsLegalPosition()
    59.     {
    60.         if(placeableStructure.colliders.Count>0)
    61.         {
    62.             return false;
    63.         }
    64.         return true;
    65.     }
    66.  
    67.     public void SetItem(GameObject b)
    68.     {
    69.         hasPlaced = false;
    70.         currentStructure = ((GameObject)Instantiate(b)).transform;
    71.         placeableStructure = currentStructure.GetComponent<PlaceableStructure>();
    72.     }
    73. }
     
  30. noahamyot

    noahamyot

    Joined:
    Nov 29, 2019
    Posts:
    1
    Okay say that you wanted your object to snap to a 0.5 grid, you can't use a math.Round on that because to it will just move it by moving it to an int, how do you get around this?
     
  31. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,848
    You divide by 0.5, round, and then multiply by 0.5.
     
    Nexer8 and toomasio like this.
  32. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    Which is more performant:

    Code (CSharp):
    1. var p = new Vector3(Mathf.Round(r.x/g.x) * g.x, Mathf.Round(r.y/g.y) * g.y, Mathf.Round(r.z/g.z) * g.z);
    or

    Code (CSharp):
    1. vvar p = new Vector3((int)(r.x / g.x) * g.x, (int)(r.y / g.y) * g.y, (int)(r.z / g.z) * g.z);
    I suspect the latter as Math.Round has more processing

    *I know one is to the nearest, the other is to the lower..
     
    Last edited: Dec 9, 2020
  33. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,780
    Spock, there is only ever one answer to this:

    On the specific hardware you care about (NOT in the editor!), attach the Profiler (Window -> Profiler) and see.

    Any other answer is simply not logical.

    Kirk, er Kurt
     
  34. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    I don't have test case to profile. That's why I'm asking.