preface

If you’ve ever played a battle flag game like Sanguchi or a business simulation game like City Sim, Clash of Clans or Boom Beach, you’re familiar with grid maps. In these games, all the objects in the map scene are based on neat grids to record information such as location. The diagram below:

If you still can’t sense what a grid map is. You will not be unfamiliar with Tetris or snake, the existence of objects is based on a regular grid map.

As always, this is a zero-based article, so if you are a beginner and interested in grid maps, you can learn this article and try your hand at creating your own game!

The final display effect of this article is:

1. Create the basic units that form the grid

We know that a grid is made up of cells, so the first step is to create a basic template:

Create A script named Grid and define some properties that we need to modify. For this example I want to create A map with obstacles to use as A* pathfinding map. So the following information is needed:

  • Width of the template
  • The template height
  • The template color
  • Whether the template is an obstacle (indicated by color)
  • Template click Event (Template color conversion)

To write a template script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Grid : MonoBehaviour
{

    public float gridWidght;
    public float girdHeight;
    public bool isHinder;
    public Color color;
    public Action OnClick;    
    // When the grid map is large, updating the template color per frame is more performance consuming, which can be modified to trigger by event
    void Update()
    {
        gameObject.GetComponent<MeshRenderer>().material.color=color;
    }
    // Delegate the binding template click event
    private void OnMouseDown()
    {
        OnClick?.Invoke();
    }

}
Copy the code

After writing the script and creating the template preform, this example uses a simple square as a demonstration case. To ensure that each square is distinguishable, the size is scaled to 0.9, so that there is space between the two squares to split the different grid blocks.

After the Grid is created, hang the Grid script on the object and set the relevant initial parameters, as shown in the following figure:

2, edit the grid creation script

Create a script named GridMeshCreate and then write the script. In order to create the grid map function, we need to get some basic information:

  • Create the width of the grid:xshaftGridThe number of preforms
  • Create the height of the grid:yshaftGridThe number of preforms
  • Creating a gridGridPosition of: through an initial point, and then throughGridThe length and width of

With the above information defined, we can write the script to implement the Grid creation function, but before we do that we need to think about whether each Grid we create will look exactly the same. The answer is definitely no. For example, in some business simulation games, an object may have some influence on the surrounding environment. In order to mark its influence, it needs to be represented by a grid of different colors, as shown in the figure:

As can be seen in the above picture, we need to display different information for different blocks of the grid, which requires us to pass in the corresponding processing logic when the grid is created. The specific code structure is:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;


public class GridMeshCreate : MonoBehaviour{[Serializable]
    public class MeshRange
    {
        public int widght;
        public int height;
    }
    // The width and height range of the grid
    public MeshRange meshRange;
    // Generate the grid starting point
    public Vector3 startPos;
    // The parent object generated by the mesh
    public Transform parentTran;
    // Template prefab
    public GameObject gridPre;
    
    private Grid[,] m_grids;
    public Grid[,] MeshGridData
    {
        get
        {
            returnm_grids; }}// Register the template event
    public Action<Grid> gridEvent;

    /// <summary>
    ///Create a grid based on the initial data of the mounted component
    /// </summary>
    public void CreateMesh()
    {
        if (meshRange.widght == 0 || meshRange.height == 0)
        {
            return;
        }
        ClearMesh();
        m_grids = new Grid[meshRange.widght, meshRange.height];
        for (int i = 0; i < meshRange.widght; i++)
        {
            for (int j = 0; j < meshRange.height; j++) { CreateGrid(i, j); }}}/// <summary>
    ///Overload to create a grid based on the incoming width and height data
    /// </summary>
    /// <param name="height"></param>
    /// <param name="widght"></param>
    public void CreateMesh(int height,int widght)
    {
        if (widght == 0 || height == 0)
        {
            return;
        }
        ClearMesh();
        m_grids = new Grid[widght, height];
        for (int i = 0; i < widght; i++)
        {
            for (int j = 0; j < height; j++) { CreateGrid(i, j); }}}/// <summary>
    ///Create a basic Grid object based on the location
    /// </summary>
    /// <param name="row">The x coordinate</param>
    /// <param name="column">Y coordinates</param>
    public void CreateGrid(int row,int column)
    {
        GameObject go = GameObject.Instantiate(gridPre, parentTran);
        Grid grid = go.GetComponent<Grid>();

        float posX = startPos.x + grid.gridWidght * row;
        float posZ = startPos.z + grid.girdHeight * column;
        go.transform.position = newVector3(posX, startPos.y, posZ); m_grids[row, column] = grid; gridEvent? .Invoke(grid); }/// <summary>
    ///Delete the grid map and clear the cached data
    /// </summary>
    public void ClearMesh()
    {
        if (m_grids == null || m_grids.Length == 0)
        {
            return;
        }
        foreach (Grid grid in m_grids)
        {
            if(grid.gameObject ! =null)
            {
                Destroy(grid.gameObject);
            }
        }
        Array.Clear(m_grids, 0, m_grids.Length); }}Copy the code

There are two key points about the above script:

  • Create a grid
  • External exposure treatmentGridLogical method

Public void CreateMesh(int height,int widght); public void CreateMesh(int height,int widght); The width and height of the grid (note that the width and height refers to the number of x and y grids) can be flexibly changed through the script later.

The implementation of the Grid logic is exposed by adding a delegate event to the prefab when it is created. This allows us to write logical methods while our other scripts are being created, without any modifications to the encapsulated grid map creation class. For more information on delegating, see my previous post:

Articles on entrustment:

  • C# delegate basics and introduction

3. Map generation case

After we wrap up the grid creation script, we can use the script to make a simple grid map to demonstrate its use

Create a script named MainRun and edit it:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MainRun : MonoBehaviour
{
    // Get the grid creation script
    public GridMeshCreate gridMeshCreate;
    // Control the probability that the grid element is an obstacle
    [Range (0, 1)]
    public float probability;

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space)) { Run(); }}private void Run()
    {
        
        gridMeshCreate.gridEvent = GridEvent;
        gridMeshCreate.CreateMesh();
    }

    /// <summary>
    ///Method that is executed when the Grid is created and passed in by delegate
    /// </summary>
    /// <param name="grid"></param>
    private void GridEvent(Grid grid)
    {
        // The probability randomly determines whether the element is an obstacle
        float f = Random.Range(0.1.0 f);
        Debug.Log(f.ToString());
        grid.color = f <= probability ? Color.red : Color.white;
        grid.isHinder = f <= probability;
        // The template element clicks the event
        grid.OnClick = () => {
            if (!grid.isHinder)
                grid.color = Color.blue;
        };

    }
}
Copy the code

As you can see, in the Run method is a call to our Grid creation framework, while in GridEvent(Grid Grid) we can write our logic and modify the code in the Grid script to help achieve the desired effect, such as writing a click event to the Grid in this case. You can define the event through a delegate at creation time.

Note:

  • It’s used in the scriptThe Random Range (0, 1.0 f)To generate a probability, be careful not to writeRandom.Range(0, 1), because the output result can only be an integer, that is, only output zero

After writing the script, you canGridMeshCreateScripts are mounted to objects in the scene and are assigned based on comments. As shown in figure:

After the script is mounted, click run. After entering the game, click the space bar and a map will be created. There will be random obstacles in the map.

conclusion

This is just a simple example, if you find it useful, try creating your own grid map generation method based on the GridMeshCreate script to get the results you want!