二. 使用Gizoms绘制网格及矩阵转换使用
1. 创建Leve类,作为场景控制类:
1 using UnityEngine; 2 //使用namespace方便脚本管理 3 namespace RunAndJump { 4 //使用部分类partial将类依据不同的功能分布到各个文件中,便于功能区分个管理 5 public partial class Level : MonoBehaviour { 6 [SerializeField] 7 public int _totalTime = 60; 8 [SerializeField] 9 private float _gravity = -30; 10 [SerializeField] 11 private AudioClip _bgm; 12 [SerializeField] 13 private Sprite _background; 14 15 [SerializeField] 16 private int _totalColumns = 25; 17 18 [SerializeField] 19 private int _totalRows = 10; 20 21 public const float GridSize = 1.28f; 22 23 private readonly Color _normalColor = Color.grey; 24 private readonly Color _selectedColor = Color.yellow; 25 public int TotalTime { 26 get { return _totalTime; } 27 set { _totalTime = value; } 28 } 29 30 public float Gravity { 31 get { return _gravity; } 32 set { _gravity = value; } 33 } 34 35 public AudioClip Bgm { 36 get { return _bgm;} 37 set { _bgm = value; } 38 } 39 40 public Sprite Background { 41 get { return _background; } 42 set { _background = value; } 43 } 44 45 public int TotalColumns 46 { 47 get 48 { 49 return _totalColumns; 50 } 51 52 set 53 { 54 _totalColumns = value; 55 } 56 } 57 58 public int TotalRows 59 { 60 get 61 { 62 return _totalRows; 63 } 64 65 set 66 { 67 _totalRows = value; 68 } 69 } 70 71 //绘制边界 72 private void GridFrameGizmo(int cols, int rows) 73 { 74 Gizmos.DrawLine(new Vector3(0,0,0),new Vector3(0,rows*GridSize,0) ); 75 Gizmos.DrawLine(new Vector3(0, 0, 0), new Vector3(cols*GridSize,0, 0)); 76 Gizmos.DrawLine(new Vector3(cols*GridSize, 0, 0), new Vector3(cols*GridSize, rows * GridSize, 0)); 77 Gizmos.DrawLine(new Vector3(0, rows*GridSize, 0), new Vector3(cols*GridSize, rows * GridSize, 0)); 78 } 79 80 //绘制内部线条 81 private void GridGizmos(int cols, int rows) 82 { 83 for (int i = 0; i < cols; i++) 84 { 85 Gizmos.DrawLine(new Vector3(i*GridSize,0,0),new Vector3(i*GridSize,rows*GridSize,0) ); 86 } 87 88 for (int j = 0; j < rows; j++) 89 { 90 Gizmos.DrawLine(new Vector3(0,j * GridSize, 0), new Vector3(cols * GridSize, j * GridSize, 0)); 91 } 92 } 93 94 //D使用unity默认的OnDrawGizmos方法来绘制Gzimos 95 private void OnDrawGizmos() 96 { 97 Color oldColor = Gizmos.color;//修改的这些属性都是静态属性,所以要在修改前保存其值,修改后再复原,防止后续使用该静态属性是修改后的 98 Matrix4x4 oldMatrix = Gizmos.matrix;//修改的这些属性都是静态属性,所以要在修改前保存其值,修改后再复原,防止后续使用该静态属性是修改后的 99 Gizmos.matrix = transform.localToWorldMatrix;//该语句可以为gizmos提供该transform位移,旋转,缩放等特性 100 101 Gizmos.color = _normalColor; 102 GridGizmos(_totalColumns,_totalRows); 103 GridFrameGizmo(_totalColumns,_totalRows); 104 105 Gizmos.color = oldColor;//恢复修改后的静态属性 106 Gizmos.matrix = oldMatrix;//恢复修改后的静态属性 107 } 108 109 private void OnDrawGizmosSelected() 110 { 111 Color oldColor = Gizmos.color; 112 Matrix4x4 oldMatrix = Gizmos.matrix; 113 Gizmos.matrix = transform.localToWorldMatrix; 114 115 116 Gizmos.color = _selectedColor; 117 GridFrameGizmo(_totalColumns, _totalRows); 118 119 Gizmos.color = oldColor; 120 Gizmos.matrix = oldMatrix; 121 122 } 123 124 /// <summary> 125 /// 将世界坐标转换为grid网格中的点坐标 126 /// </summary> 127 /// <param name="point">世界坐标</param> 128 /// <returns></returns> 129 public Vector3 WordToGridCoordinates(Vector3 point) 130 { 131 Vector3 gridPoint=new Vector3((int)((point.x-transform.position.x)/GridSize),(int)((point.y-transform.position.y)/GridSize),0.0f); 132 return gridPoint; 133 } 134 135 /// <summary> 136 /// Grid网格中的位置转换为世界坐标坐标 137 /// </summary> 138 /// <param name="col">行值</param> 139 /// <param name="row">列值</param> 140 /// <returns></returns> 141 public Vector3 GridToWordCoordinates(int col,int row) 142 { 143 Vector3 wordPoint=new Vector3(transform.position.x+(col*GridSize/2.0f),transform.position.y+(row*GridSize/2.0f),0.0f); 144 return wordPoint; 145 } 146 /// <summary> 147 /// 坐标位置是否在网格边界内 148 /// </summary> 149 /// <param name="point"></param> 150 /// <returns></returns> 151 public bool IsInsideGridBounds(Vector3 point) 152 { 153 float minX = transform.position.x; 154 float maxX = minX + _totalColumns*GridSize; 155 float minY = transform.position.y; 156 float maxY = minY + _totalRows*GridSize; 157 return (point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY); 158 } 159 160 /// <summary> 161 /// 坐标位置是否在网格边界内 162 /// </summary> 163 /// <param name="point"></param> 164 /// <returns></returns> 165 166 public bool IsInsideGridBounds(int col,int row) 167 { 168 return (col>=0&&col<_totalColumns&&row>=0&&row<=_totalRows); 169 } 170 } 171 }
2. 创建EditorUtil类,作为辅助工具类:
1 using UnityEngine; 2 using System.Collections; 3 using UnityEditor; 4 using UnityEditor.SceneManagement; 5 6 namespace RunAndJump.LevelCreator //为防止类名冲突,使用namespace时一个好的解决方案 7 { 8 public class EditorUtil 9 { 10 11 //创建新场景 12 public static void NewScene() 13 { 14 //该方法后续过时,被下面方法替代:EditorApplication.SaveCurrentSceneIfUserWantsTo(); 15 EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();//当前场景有未保存的东西是,弹出对话框提醒是否保存当前场景 16 //该方法后续过时,被下面方法替代:EditorApplication.NewScene(); 17 EditorSceneManager.NewScene(NewSceneSetup.EmptyScene); 18 } 19 20 21 //清空场景 22 public static void CleanScene() 23 { 24 GameObject[] allObjects = Object.FindObjectsOfType<GameObject>(); 25 26 foreach (GameObject go in allObjects) 27 { 28 GameObject.DestroyImmediate(go); 29 } 30 } 31 32 //创建新关卡 33 public static void NewLevel() 34 { 35 NewScene(); 36 CleanScene(); 37 38 //可以在创建新关卡时添加上必要的游戏对象 39 //add something... 40 41 GameObject levelGo = new GameObject("Level"); 42 levelGo.transform.position=Vector3.zero; 43 levelGo.AddComponent<Level>(); 44 45 } 46 } 47 }
3. 创建MenuItems类,作为编辑器菜单工具类:
1 using UnityEngine; 2 using System.Collections; 3 using UnityEditor; 4 5 namespace RunAndJump.LevelCreator 6 { 7 8 //菜单项管理类,用来控制扩展方法在菜单项中显示 9 public class MenuItems 10 { 11 [MenuItem("Tools/LevelCreator/NewLevelScene %q") ] 12 private static void NewLevel() 13 { 14 EditorUtil.NewLevel(); 15 } 16 } 17 }
4. 创建SnapToGridTest类,用来测试Leve类中方法:
1 using UnityEngine; 2 using System.Collections; 3 using RunAndJump; 4 5 [ExecuteInEditMode]//在editor场景模式下不用运行就调用 6 public class SnapToGridTest : MonoBehaviour { 7 8 // Update is called once per frame 9 void Update () 10 { 11 print(name+" in level"); 12 Vector3 gridCoord = Level.Instance.WordToGridCoordinates(transform.position); 13 transform.position = Level.Instance.GridToWordCoordinates((int) gridCoord.x, (int) gridCoord.y); 14 } 15 16 private void OnDrawGizmos() 17 { 18 print("gizoms"); 19 Color oldColor = Gizmos.color; 20 Gizmos.color = (Level.Instance.IsInsideGridBounds(transform.position)) ? Color.green : Color.red; 21 Gizmos.DrawCube(transform.position,Vector3.one*Level.GridSize); 22 Gizmos.color = oldColor; 23 } 24 }
效果:
我们通过MenuItems创建的菜单调用EditorUtil中创建场景的方法,场景中在OnDrawGizoms方法中绘制出自己的网格。现在创建一个空物体为其绑上SnapToGridTest脚本用来验证level中用来对齐坐标到网格和验证是否出界的方法。