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

Can't snap to isometric grid properly (with screenshot)

Discussion in '2D' started by laveurdegoudron, Jan 20, 2021.

  1. laveurdegoudron

    laveurdegoudron

    Joined:
    Oct 10, 2017
    Posts:
    14
    Hello all !
    I'm working on a 2D isometric city building game. I made a script that rounds the position of the spawned building to make it snap to my isometric grid. It works fine but I would like to avoid "half values" : at the moment the player can spawn a building between two cells as shown on the image.


    The following is the code I use (BuildingData is a ScriptableObject). The magic mostly happens between line 60 and 70 :

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. public class BuildItems : MonoBehaviour
    8. {
    9.     [HideInInspector] public float buildingCount;
    10.  
    11.     [Header("UI Elements")]
    12.     public Text natureDisplay;
    13.     public Text foodDisplay;
    14.  
    15.     [Header("Forge")]
    16.     public BuildingData forgeData;
    17.     [SerializeField] private GameObject forgePrefab;
    18.  
    19.     private float naturePoints, foodPoints;
    20.     private Vector3 mousePosition, worldPosition;
    21.     private bool isPlacing, isOverlapping;
    22.     private GameObject lastBuilt;
    23.     private GameObject canva;
    24.     //This code is responsible for triggering the building of an item when a button is pressed in the UI.
    25.  
    26.     private void Start()
    27.     {
    28.         naturePoints = GameObject.Find("ResourceController").GetComponent<NatureController>().naturePoints;
    29.         foodPoints = GameObject.Find("ResourceController").GetComponent<FoodController>().foodPoints;
    30.         natureDisplay = GameObject.Find("NaturePointsDisplay").GetComponent<Text>();
    31.         foodDisplay = GameObject.Find("FoodPointsDisplay").GetComponent<Text>();
    32.         canva = GameObject.Find("Canvas");
    33.         natureDisplay.text = naturePoints.ToString();
    34.  
    35.         buildingCount = 0;
    36.     }
    37.  
    38.     private void Update()
    39.     {
    40.         //We store the world location of the mouse at each frame.
    41.         CheckMouseInput();
    42.  
    43.         //Opens Build Menu if player presses tab.
    44.         if (Input.GetKeyDown(KeyCode.Tab))
    45.         {
    46.             canva.SetActive(true);
    47.         }
    48.  
    49.         //If the player pressed a build button and had enought Points, he is placing the future building in the world.
    50.         if (isPlacing == true)
    51.         {
    52.             //We assign the building blueprint's position to the mouse position.
    53.             lastBuilt.transform.position = worldPosition;
    54.  
    55.             //We assign the collision checking method to the instantiated gameobject.
    56.             isOverlapping = lastBuilt.GetComponent<ItemManager>().isOverlapping;
    57.  
    58.             //If the player presses his mouse button, we check for collision. If any, the player can't build. Otherwise, the building is placed.
    59.             if (Input.GetMouseButtonDown(0))
    60.             {
    61.                 if (isOverlapping == false)
    62.                 {
    63.                     isPlacing = false;
    64.                     Debug.Log("You built an item.");
    65.  
    66.                     //We assign the object's position to mouse position rounded to isometric proportions.
    67.                     lastBuilt.transform.position = new Vector3(Mathf.Round(worldPosition.x * 2) / 2, Mathf.Round(worldPosition.y * 4) / 4, worldPosition.z);
    68.  
    69.                     //Nature cost is paid and nature points are displayed.
    70.                     naturePoints = naturePoints - lastBuilt.GetComponent<ItemManager>().natureCost;
    71.                     natureDisplay.text = naturePoints.ToString();
    72.  
    73.                     lastBuilt.GetComponent<ItemManager>().StartBuilding();
    74.                 }
    75.                 else
    76.                 {
    77.                     Debug.Log("You can't build here.");
    78.                 }
    79.             }
    80.         }
    81.     }
    82.  
    83.     public void BuildForge()
    84.     {
    85.         if (naturePoints >= forgeData.natureCost)
    86.         {
    87.             canva.SetActive(false);
    88.             //If the player has enough Nature Points, the item is created as "forge
    89.             lastBuilt = Instantiate(forgePrefab);
    90.             lastBuilt.name = forgeData.buildingName + buildingCount++;
    91.             isPlacing = true;
    92.         }
    93.     }
    94.  
    95.     private void CheckMouseInput()
    96.     {
    97.         mousePosition = Input.mousePosition;
    98.         mousePosition.z = Camera.main.nearClipPlane;
    99.         worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
    100.     }
    101. }
    102.  
    How could I avoid that ?
    Thank you for reading me.
    Best regards;
     
  2. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    Probably should just be using the worldtocell/celltoworld function from the grid for this sort of thing instead of manually computing it.
     
  3. laveurdegoudron

    laveurdegoudron

    Joined:
    Oct 10, 2017
    Posts:
    14
    Thank you for your answer.
    I am a bit confused, as the Unity Scripting API describes worldtocell as to be used with a GridLayout and not a Grid. Isn't a Grid Layout an UI component ?
    Thank you
     
  4. laveurdegoudron

    laveurdegoudron

    Joined:
    Oct 10, 2017
    Posts:
    14
    Figured it out, thank you so much ! I'm pasting the code in here. I have taken off many things to leave the minimum, so some things might not fit with the //description.
    Void BuildForge is triggered by a button.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEngine.Tilemaps;
    7.  
    8. public class BuildItems : MonoBehaviour
    9. {
    10.     [Header("Forge")]
    11.     [SerializeField] private GameObject forgePrefab;
    12.  
    13.     private Vector3 mousePosition, worldPosition;
    14.     private Vector3Int cellPosition;
    15.     private GameObject lastBuilt;
    16.     private Tilemap tilemap;
    17.     //This code is responsible for triggering the building of an item when a button is pressed in the UI.
    18.  
    19.     private void Start()
    20.     {
    21.         tilemap = GameObject.Find("Tilemap").GetComponent<Tilemap>();
    22.     }
    23.  
    24.     private void Update()
    25.     {
    26.         //We store the world location of the mouse at each frame.
    27.         CheckMouseInput();
    28.  
    29.         //If the player pressed a build button and had enought Points, he is placing the future building in the world.
    30.         if (isPlacing == true)
    31.         {
    32.             //We assign the building blueprint's position to the mouse position.
    33.             lastBuilt.transform.position = worldPosition;
    34.  
    35.             //If the player presses his mouse button, we check for collision. If any, the player can't build. Otherwise, the building is placed.
    36.             if (Input.GetMouseButtonDown(0))
    37.             {
    38.                 if (isOverlapping == false)
    39.                 {
    40.                     isPlacing = false;
    41.                     Debug.Log("You built an item.");
    42.  
    43.                     //We assign the object's position to mouse position rounded to isometric proportions.
    44.                     lastBuilt.transform.position = new Vector3 (tilemap.GetCellCenterLocal(cellPosition).x, tilemap.GetCellCenterLocal(cellPosition).y, -1);
    45.  
    46.                     lastBuilt.GetComponent<ItemManager>().StartBuilding();
    47.                 }
    48.                 else
    49.                 {
    50.                     Debug.Log("You can't build here.");
    51.                 }
    52.             }
    53.         }
    54.     }
    55.  
    56.     public void BuildForge()
    57.     {
    58.         if (naturePoints >= forgeData.natureCost)
    59.         {
    60.             canva.SetActive(false);
    61.             //If the player has enough Nature Points, the item is created as "forge
    62.             lastBuilt = Instantiate(forgePrefab);
    63.             lastBuilt.name = forgeData.buildingName + buildingCount++;
    64.             isPlacing = true;
    65.         }
    66.     }
    67.  
    68.     private void CheckMouseInput()
    69.     {
    70.         mousePosition = Input.mousePosition;
    71.         mousePosition.z = Camera.main.nearClipPlane;
    72.         worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
    73.         cellPosition = tilemap.WorldToCell(worldPosition);
    74.     }
    75. }