序文
Three Kingdomsタイプの戦闘旗ゲーム、またはSim City、Clash of Clans、Boom Beachなどのシミュレーション管理ゲームをプレイしたことがある場合は、グリッドマップに精通している必要があります。これらのゲームでは、マップシーン内のすべてのオブジェクトは、位置などの情報を記録するためのきちんとしたグリッドに基づいています。以下に示すように:
それでもグリッドマップが何であるかを認識できない場合。テトリスやスネークに不慣れであってはなりません。オブジェクトの存在は、通常のグリッドマップに依存します。
いつものように、この記事には基本的な内容はありません。Xiaomengを初めて使用し、グリッドマップに興味がある場合は、この記事を調べて、独自のゲームを作成してみてください。
この記事の最終的な表示効果は次のとおりです。
1.グリッドを構成する基本ユニットを作成します
グリッドはグリッドで構成されていることがわかっているため、最初のステップは基本的なテンプレートを作成することです。
名前の付いたスクリプトを作成し、Grid
変更する必要のあるいくつかのプロパティを定義します。この場合、A*パスファインディングのマップとして使用する障害物のあるマップを作成します。したがって、次の情報が必要です。
- テンプレートの幅
- テンプレートの高さ
- テンプレートの色
- テンプレートが障害物であるかどうか(色で識別)
- テンプレートクリックイベント(テンプレート色変換)
テンプレートスクリプトを作成します。
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;
//当网格地图比较大时,每帧更新模板颜色比较消耗性能,可以修改为通过事件触发
void Update()
{
gameObject.GetComponent<MeshRenderer>().material.color=color;
}
//委托绑定模板点击事件
private void OnMouseDown()
{
OnClick?.Invoke();
}
}
スクリプトを作成したら、テンプレートプレハブを作成します。この場合、デモンストレーションの例として単純な正方形を使用します。各正方形を確実に区別できるように0.9
、2つの間にギャップができるようにサイズを調整します。異なる正方形を分離するための正方形。グリッドブロック。
グリッドを作成したら、Grid
次の図に示すように、スクリプトをオブジェクトに掛けて、関連する初期パラメーターを設定します。
2.グリッド作成スクリプトを編集します
次に、グリッド作成スクリプトをカプセル化し、という名前のスクリプトを作成してから、スクリプトを作成する必要がありGridMeshCreate
ます。グリッドマップを作成する機能を実現するには、いくつかの基本情報を取得する必要があります。
- 作成されたグリッドの幅:
x
軸Grid
プレハブの数 - グリッドの高さの作成:
y
軸Grid
プレハブの数 - グリッドに位置を作成します
Grid
。最初のポイントを渡し、次にGrid
長さと幅の計算を渡します
上記の情報の定義が完了したら、グリッド作成の機能を実装するスクリプトを作成できますが、その前に質問について考える必要があります。それぞれの作成Grid
はまったく同じになりますか。答えは間違いなくありません。たとえば、一部のビジネスシミュレーションゲームでは、オブジェクトが周囲の環境に何らかの影響を与える場合があります。その影響範囲を特定するには、次の図に示すように、オブジェクトをさまざまな色のグリッドで表す必要があります。
上の図に示されているように、さまざまなブロックのグリッドについてさまざまな情報を表示する必要があります。これには、グリッドの作成時に対応する処理ロジックを渡す必要があります。具体的なコード構造は次のとおりです。
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;
}
//网格的宽高范围
public MeshRange meshRange;
//生成网格起始点
public Vector3 startPos;
//网格生成的父物体
public Transform parentTran;
//模板预制体
public GameObject gridPre;
private Grid[,] m_grids;
public Grid[,] MeshGridData
{
get
{
return m_grids;
}
}
//注册模板事件
public Action<Grid> gridEvent;
/// <summary>
/// 基于挂载组件的初始数据创建网格
/// </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>
/// 重载,基于传入宽高数据来创建网格
/// </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>
/// 根据位置创建一个基本的Grid物体
/// </summary>
/// <param name="row">x轴坐标</param>
/// <param name="column">y轴坐标</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 = new Vector3(posX, startPos.y, posZ);
m_grids[row, column] = grid;
gridEvent?.Invoke(grid);
}
/// <summary>
/// 删除网格地图,并清除缓存数据
/// </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);
}
}
上記のスクリプトには2つの重要なポイントがあります。
- グリッドを作成する
Grid
処理ロジックを外部に公開する方法
グリッドの作成に関して、スクリプトでは、public void CreateMesh(int height,int widght)
後でスクリプトを介してグリッドの幅と高さを柔軟に変更できるように、グリッドの幅と高さを渡すオーバーロードメソッドを記述しました(幅と高さに注意してください)。ここでは、x
軸とy
軸グリッドの数を示します)
ロジックエクスポージャーの実装ではGrid
、作成時にプレハブにデリゲートイベントを追加するために使用されます。このようにして、このカプセル化されたグリッドマップ作成クラスを変更することなく、他のスクリプトを作成するときにロジックメソッドを記述できます。委任に関する知識については、以前の記事を確認してください。
委任に関する記事:
3.マップ生成の場合
グリッド作成用のスクリプトをカプセル化した後、スクリプトを使用して簡単なグリッドマップを作成し、その使用法を示すことができます。
次の名前のスクリプトを作成してMainRun
編集します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainRun : MonoBehaviour
{
//获取网格创建脚本
public GridMeshCreate gridMeshCreate;
//控制网格元素grid是障碍的概率
[Range(0,1)]
public float probability;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Run();
}
}
private void Run()
{
gridMeshCreate.gridEvent = GridEvent;
gridMeshCreate.CreateMesh();
}
/// <summary>
/// 创建grid时执行的方法,通过委托传入
/// </summary>
/// <param name="grid"></param>
private void GridEvent(Grid grid)
{
//概率随机决定该元素是否为障碍
float f = Random.Range(0, 1.0f);
Debug.Log(f.ToString());
grid.color = f <= probability ? Color.red : Color.white;
grid.isHinder = f <= probability;
//模板元素点击事件
grid.OnClick = () => {
if (!grid.isHinder)
grid.color = Color.blue;
};
}
}
このRun
メソッドにはグリッド作成フレームワークの呼び出しがあり、その中GridEvent(Grid grid)
でロジックをGrid
記述し、スクリプト内のコードを変更して、必要な効果を完了するのに役立てることができます。たとえば、この場合はGrid
Write a [イベント]をクリックすると、作成時にデリゲートを介してイベントを定義できます。
知らせ:
Random.Range(0, 1.0f)
これは、確率を生成するためにスクリプトで使用されますRandom.Range(0, 1)
。出力結果は整数のみ、つまりゼロのみを出力できるため、記述しないように注意してください。
スクリプトを記述した後GridMeshCreate
、シーン内のオブジェクトにスクリプトをマウントし、コメントに従って関連する割り当てを実行できます。図に示すように:
スクリプトをマウントしたら、クリックして実行します。ゲームに入ったら、スペースバーをクリックしてマップを作成します。マップにはランダムな障害物があります。障害物は赤でマークされており、クリックできません。白の色はクリックすると面積が変化します。青色で、具体的な効果は図のようになります。
補充する
グリッドマップで作成されたコードを使用する場合、不便を感じるかもしれません。つまり、その中の変数タイプの1つがクラス名Grid
であるため、制限があります。私のプレハブスクリプトはマウントすることしかできずGrid
、明らかに不便です。そのため、後でいくつかの変更を加え、変更されたスクリプトGrid
に置き換えました。GameObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class GridMeshCreate : MonoBehaviour
{
[Serializable]
public class MeshRange
{
public int horizontal;
public int vertical;
}
[Header("网格地图范围")]
public MeshRange meshRange;
[Header("网格地图起始点")]
private Vector3 startPos;
[Header("创建地图网格父节点")]
public Transform parentTran;
[Header("网格地图模板预制体")]
public GameObject gridPre;
[Header("网格地图模板大小")]
public Vector2 scale;
private GameObject[,] m_grids;
public GameObject[,] grids
{
get
{
return m_grids;
}
}
//注册模板事件
public Action<GameObject, int, int> gridEvent;
/// <summary>
/// 基于挂载组件的初始数据创建网格
/// </summary>
public void CreateMesh()
{
if (meshRange.horizontal == 0 || meshRange.vertical == 0)
{
return;
}
ClearMesh();
m_grids = new GameObject[meshRange.horizontal, meshRange.vertical];
for (int i = 0; i < meshRange.horizontal; i++)
{
for (int j = 0; j < meshRange.vertical; j++)
{
CreateGrid(i, j);
}
}
}
/// <summary>
/// 重载,基于传入宽高数据来创建网格
/// </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 GameObject[widght, height];
for (int i = 0; i < widght; i++)
{
for (int j = 0; j < height; j++)
{
CreateGrid(i, j);
}
}
}
/// <summary>
/// 根据位置创建一个基本的Grid物体
/// </summary>
/// <param name="row">x轴坐标</param>
/// <param name="column">y轴坐标</param>
public void CreateGrid(int row, int column)
{
GameObject go = GameObject.Instantiate(gridPre, parentTran);
//T grid = go.GetComponent<T>();
float posX = startPos.x + scale.x * row;
float posZ = startPos.z + scale.y * column;
go.transform.position = new Vector3(posX, startPos.y, posZ);
m_grids[row, column] = go;
gridEvent?.Invoke(go, row, column);
}
/// <summary>
/// 删除网格地图,并清除缓存数据
/// </summary>
public void ClearMesh()
{
if (m_grids == null || m_grids.Length == 0)
{
return;
}
foreach (GameObject go in m_grids)
{
if (go != null)
{
Destroy(go);
}
}
Array.Clear(m_grids, 0, m_grids.Length);
}
}
要約する
これは単純なケースです。便利な場合は、GridMeshCreate
スクリプトに基づいて独自のグリッドマップ生成メソッドを作成して、必要な効果を作成してみてください。