本篇文章是从新浪搬过来的。http://blog.sina.com.cn/s/articlelist_5880195292_0_1.html点击打开链接
新浪每次该文章。尖括号都会莫名其妙消失掉,而且也用了转义符号。所以以后博客都在这里发布。
这是当前地形编辑的效果
附上源码 原理讲解在下一篇http://blog.csdn.net/zhong1213/article/details/76906336
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
using
UnityEngine; using System.Collections; using System.Collections.Generic; public class TerrainManager : MonoBehaviour { Mesh mesh; //材质 public Material diffuseMap; //顶点、uv、索引信息 private Vector3[] vertives; private Vector2[] uvs; private int [] triangles; private ushort [] blockData; //生成信息 private Vector3 chunkSize; //长宽高 private int groundHeight; //地面高度 //区块主体 private GameObject terrain; void Start() { SetTerrain( 10 , 10 , 10 , 5 ); } // 通过参数生成地形 public void SetTerrain( float width, float height, float length, int groundH) { Init(width, height, length, groundH); //初始化数据 GetVertives(); DrawMesh(); terrain.AddComponent } private void Init( float width, float height, float length, int groundH) { chunkSize = new Vector3(width, height, length); //初始化区块尺寸并赋值 groundHeight = groundH; //给地面高度赋值 if (terrain != null ) { Destroy(terrain); } terrain = new GameObject(); //初始化区间 terrain.name = "plane" ; //设置chunk名字 terrain.layer = 8 ; //设置区间所在层数。只有这一层内的碰撞体才会被射线检测到 blockData = new ushort [( int )(chunkSize.x * chunkSize.y * chunkSize.z)]; //初始化方块数据,方括号内是该区间内所容纳方块数,该数组的容量 //该循环遍历0,0,0 到 (chunksize-1,chunksize-1,chunksize-1)的方块位置。并根据地面高度。分配方块对应的数字。0是空,1是有方块 for ( int x = 0 ; x < chunkSize.x; x++) { for ( int y = 0 ; y < chunkSize.y; y++) { for ( int z = 0 ; z < chunkSize.z; z++) { if (y <= groundH) { blockData[getBlockIndex(x, y, z)] = 1 ; } else { blockData[getBlockIndex(x, y, z)] = 0 ; } } } } //用于测试 blockData[getBlockIndex( 5 , 1 , 5 )] = 0 ; blockData[getBlockIndex( 5 , 2 , 5 )] = 0 ; blockData[getBlockIndex( 5 , 3 , 5 )] = 0 ; blockData[getBlockIndex( 5 , 4 , 5 )] = 0 ; blockData[getBlockIndex( 5 , 5 , 5 )] = 0 ; blockData[getBlockIndex( 5 , 5 , 6 )] = 0 ; blockData[getBlockIndex( 5 , 5 , 7 )] = 0 ; blockData[getBlockIndex( 6 , 5 , 5 )] = 0 ; blockData[getBlockIndex( 7 , 5 , 5 )] = 0 ; } public void BuildBlock( float px, float py, float pz, int blockID) { //获取对应的方块并且赋值blockID blockData[( int )((pz + py * (( int )chunkSize.z) + (px * ( int )(chunkSize.y) * ( int )(chunkSize.z))))] = ( ushort )blockID; //这里开始重绘网格 GetVertives(); //给mesh 赋值 mesh.Clear(); mesh.vertices = vertives; //,pos); mesh.uv = uvs; mesh.triangles = triangles; //重置法线 mesh.RecalculateNormals(); //重置范围 mesh.RecalculateBounds(); //更新网格碰撞体 terrain.GetComponent } /// private void DrawMesh() { mesh = terrain.AddComponent terrain.AddComponent if (diffuseMap == null ) { Debug.LogWarning( "No material,Create diffuse!!" ); diffuseMap = new Material(Shader.Find( "Diffuse" )); } terrain.GetComponent mesh.Clear(); mesh.vertices = vertives; //,pos); mesh.uv = uvs; mesh.triangles = triangles; //重置法线 mesh.RecalculateNormals(); //重置范围 mesh.RecalculateBounds(); } /// /// /// private Vector3[] GetVertives() { int index = 0 ; //顶点初始序号 //GetUV(); vertives = new Vector3[( int )((chunkSize.x + 1 ) * (chunkSize.y + 1 ) * (chunkSize.z + 1 ))]; //初始化顶点序号 for ( int x = 0 ; x < chunkSize.x + 1 ; x++) { for ( int y = 0 ; y < chunkSize.y + 1 ; y++) { for ( int z = 0 ; z < chunkSize.z + 1 ; z++) { if (y == 0 ) //底面一定绘制 { vertives[index] = new Vector3(x, y, z); } else { if (!ifIsSide(x, y, z, 0 )) { if (ifDifFromAround(x, y, z)) { vertives[index] = new Vector3(x, y, z); } } } index++; //即将进行下一个遍历,顶点序号加一,这样是为了每一个坐标都有唯一对应的顶点序号。便于后面绘制三角形通过坐标计算顶点序号 } } } GetTriangles(); //生成三角形信息 return vertives; } //这个包含方块序号和坐标的对应规则,可以直接通过方块坐标获得方块序号 private int getBlockIndex( int x, int y, int z) { return (z + y * (( int )chunkSize.z) + (x * ( int )(chunkSize.y) * ( int )(chunkSize.z))); } //这部分是为了接下来多区块准备的,就是避开绘制周围一圈方块,因为周围一圈方块的绘制需要根据相邻chunk里的方块来绘制 private bool ifIsSide( int x, int y, int z, int VorT) //v =0 t=1 { if (VorT == 0 ) //0是给顶点遍历用的 { if (x == 0 || y == 0 || z == 0 || x >= ( int )chunkSize.x || y >= ( int )chunkSize.y || z >= ( int )chunkSize.z) { return true ; } else { return false ; } } else //1是给三角形遍历用的 { if (x == 0 || y == 0 || z == 0 || x >= ( int )chunkSize.x - 1 || y >= ( int )chunkSize.y - 1 || z >= ( int )chunkSize.z - 1 ) { return true ; } else { return false ; } } } //这部分是顶点遍历的时候。判断顶点周围八个方块是不是一样。只有不一样的情况。这个顶点才会被加载 private bool ifDifFromAround( int x, int y, int z) { if (blockData[getBlockIndex(x, y, z)] == 0 ) { if (blockData[getBlockIndex(x - 1 , y, z)] > 0 || blockData[getBlockIndex(x, y - 1 , z)] > 0 || blockData[getBlockIndex(x, y, z - 1 )] > 0 || blockData[getBlockIndex(x - 1 , y - 1 , z)] > 0 || blockData[getBlockIndex(x, y - 1 , z - 1 )] > 0 || blockData[getBlockIndex(x - 1 , y, z - 1 )] > 0 || blockData[getBlockIndex(x - 1 , y - 1 , z - 1 )] > 0 ) { return true ; } else { return false ; } } else { if (blockData[getBlockIndex(x - 1 , y, z)] == 0 || blockData[getBlockIndex(x, y - 1 , z)] == 0 || blockData[getBlockIndex(x, y, z - 1 )] == 0 || blockData[getBlockIndex(x - 1 , y - 1 , z)] == 0 || blockData[getBlockIndex(x, y - 1 , z - 1 )] == 0 || blockData[getBlockIndex(x - 1 , y, z - 1 )] == 0 || blockData[getBlockIndex(x - 1 , y - 1 , z - 1 )] == 0 ) { return true ; } else { return false ; } } return false ; } /// /// /// /*private Vector2[] GetUV() { int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1)); uvs = new Vector2[sum]; float u = 1.0F / segment.x; float v = 1.0F / segment.y; uint index = 0; for (int i = 0; i < segment.y + 1; i++) { for (int j = 0; j < segment.x + 1; j++) { uvs[index] = new Vector2(j * u, i * v); index++; } } return uvs; }*/ /// /// /// private int [] GetTriangles() { int sum = Mathf.FloorToInt(chunkSize.x * chunkSize.y * chunkSize.z * 6 ); triangles = new int [sum]; //初始化三角形数组 uint index = 0 ; //初始三角形序号 for ( int x = 0 ; x < chunkSize.x; x++) { for ( int y = 0 ; y < chunkSize.y; y++) { for ( int z = 0 ; z < chunkSize.z; z++) { /*if (blockData[z + (y * (int)chunkSize.z) + (x * (int)chunkSize.y * (int)chunkSize.z)] != 0){ if (y == 0){ int self = z + y * ((int)chunkSize.z+1)+ (x * (int)(chunkSize.y+1) * (int)(chunkSize.z+1)); int next = z + (y * (int)(chunkSize.z + 1) + ((x+1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); triangles[index] = self; triangles[index + 1] = self + 1; triangles[index + 2] = next + 1; triangles[index + 3] = self; triangles[index + 4] = next + 1; triangles[index + 5] = next; index += 6; } }*/ if (y == 0 ) { int self = z + y * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + (y * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); triangles[index] = self; triangles[index + 1 ] = self + 1 ; triangles[index + 2 ] = next + 1 ; triangles[index + 3 ] = self; triangles[index + 4 ] = next + 1 ; triangles[index + 5 ] = next; index += 6 ; } else { if (!ifIsSide(x, y, z, 1 )) { if (blockData[getBlockIndex(x, y, z)] == 0 ) { //下面是判断当前坐标方块上下左右前后的方块是不是实心的 //如果是实心的就把面绘制出来。而且要注意三角形面的绘制是一侧的。取决于你取点的顺序。顺时针就是正面,逆时针就是反面 //check up and draw triangle if (blockData[getBlockIndex(x, y + 1 , z)] != 0 ) { int self = z + (y + 1 ) * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + ((y + 1 ) * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); triangles[index] = self; triangles[index + 1 ] = next + 1 ; triangles[index + 2 ] = self + 1 ; triangles[index + 3 ] = self; triangles[index + 4 ] = next; triangles[index + 5 ] = next + 1 ; index += 6 ; } //check doawn and draw triangle if (blockData[getBlockIndex(x, y - 1 , z)] != 0 ) { int self = z + (y) * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + ((y) * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); triangles[index] = self; triangles[index + 1 ] = self + 1 ; triangles[index + 2 ] = next + 1 ; triangles[index + 3 ] = self; triangles[index + 4 ] = next + 1 ; triangles[index + 5 ] = next; index += 6 ; } //side if (blockData[getBlockIndex(x, y, z - 1 )] != 0 ) { int self = z + (y) * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + ((y) * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); int sup = self + ( int )chunkSize.z + 1 ; int nup = next + ( int )chunkSize.z + 1 ; triangles[index] = self; triangles[index + 1 ] = nup; triangles[index + 2 ] = sup; triangles[index + 3 ] = self; triangles[index + 4 ] = next; triangles[index + 5 ] = nup; index += 6 ; } if (blockData[getBlockIndex(x, y, z + 1 )] != 0 ) { int self = z + 1 + (y) * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + 1 + ((y) * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); int sup = self + ( int )chunkSize.z + 1 ; int nup = next + ( int )chunkSize.z + 1 ; triangles[index] = self; triangles[index + 1 ] = sup; triangles[index + 2 ] = nup; triangles[index + 3 ] = self; triangles[index + 4 ] = nup; triangles[index + 5 ] = next; index += 6 ; } if (blockData[getBlockIndex(x - 1 , y, z)] != 0 ) { int self = z + (y) * (( int )chunkSize.z + 1 ) + (x * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + ((y) * ( int )(chunkSize.z + 1 ) + ((x + 1 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); int sup = self + ( int )chunkSize.z + 1 ; int nup = next + ( int )chunkSize.z + 1 ; triangles[index] = self; triangles[index + 1 ] = sup; triangles[index + 2 ] = sup + 1 ; triangles[index + 3 ] = self; triangles[index + 4 ] = sup + 1 ; triangles[index + 5 ] = self + 1 ; index += 6 ; } if (blockData[getBlockIndex(x + 1 , y, z)] != 0 ) { int self = z + (y) * (( int )chunkSize.z + 1 ) + ((x + 1 ) * ( int )(chunkSize.y + 1 ) * ( int )(chunkSize.z + 1 )); int next = z + ((y) * ( int )(chunkSize.z + 1 ) + ((x + 2 ) * ( int )((chunkSize.y + 1 ) * (chunkSize.z + 1 )))); int sup = self + ( int )chunkSize.z + 1 ; int nup = next + ( int )chunkSize.z + 1 ; triangles[index] = self; triangles[index + 1 ] = sup + 1 ; triangles[index + 2 ] = sup; triangles[index + 3 ] = self; triangles[index + 4 ] = self + 1 ; triangles[index + 5 ] = sup + 1 ; index += 6 ; } } } } } } } return triangles; } } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
using
System;
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ray : MonoBehaviour { private TerrainManager terraManager; void Start () { terraManager = GameObject.Find( "Map" ).GetComponent
} void Update() { RaycastHit hit; Vector3 fwd = transform.TransformDirection(Vector3.forward); //获取摄像头向前的方向 if (Physics.Raycast(transform.position, fwd, out hit, Mathf.Infinity, 1 << 8 )) { Debug.DrawLine(transform.position, hit.point, Color.red); //scene视图中绘制射线 float px = Mathf.Floor(hit.point.x); float py = Mathf.Floor(hit.point.y); float pz = Mathf.Floor(hit.point.z); GameObject.Find( "po2" ).transform.position = new Vector3(px + 0 .5F, py + 1 , pz + 0 .5f); if (Input.GetMouseButtonDown( 0 )) { terraManager.BuildBlock(px, py - 1 , pz, 0 ); } else if (Input.GetMouseButtonDown( 1 )) { terraManager.BuildBlock(px, py, pz, 1 ); } else if (Input.GetMouseButtonDown( 2 )) { terraManager.SetTerrain( 10 , 10 , 10 , 5 ); } else { //没有碰撞时 } } } } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
using
UnityEngine; using System.Collections; public class playerControl: MonoBehaviour { public float sensitivityY = 2 .0f; //上下最大视角(Y视角) public float minmumY = -60f; public float maxmunY = 60f; float rotationY = 0f; public const int HERO_UP = 0 ; public const int HERO_RIGHT = 1 ; public const int HERO_DOWN = 2 ; public const int HERO_LEFT = 3 ; public GameObject mc; //人物当前行走的方向状态 public int state = 0 ; //人物移动速度 public int moveSpeed = 2 ; //初始化人物位置 public void Awake() { state = HERO_UP; } // Use this for initialization void Start() { mc = GameObject.Find( "mc" ); } // Update is called once per frame void Update() { float x1 = 0 , x2 = 0 ; x2 = Input.mousePosition.x; if (x1 != x2) { this .gameObject.transform.Rotate( new Vector3( 0 , Input.GetAxis( "Mouse X" ) * Time.deltaTime * 100 , 0 )); } x1 = x2; //Debug.Log(mc.transform.localEulerAngles); //根据鼠标移动的快慢(增量),获取相机上下移动的角度(处理Y) rotationY += Input.GetAxis( "Mouse Y" ) * sensitivityY; //角度限制,rotationY小于min返回min 大于max 返回max 否则返回value rotationY = Clamp(rotationY, maxmunY, minmumY); //设置摄像机角度 mc.transform.localEulerAngles = new Vector3(-rotationY, 0 , 0 ); //获取控制的方向, 上下左右, float KeyVertical = Input.GetAxis( "Vertical" ); float KeyHorizontal = Input.GetAxis( "Horizontal" ); //Debug.Log("keyVertical" + KeyVertical); //Debug.Log("keyHorizontal" + KeyHorizontal); if (KeyVertical == - 1 ) { setHeroState(HERO_DOWN); } else if (KeyVertical == 1 ) { setHeroState(HERO_UP); } if (KeyHorizontal == 1 ) { setHeroState(HERO_RIGHT); } else if (KeyHorizontal == - 1 ) { setHeroState(HERO_LEFT); } if (KeyVertical == 0 && KeyHorizontal == 0 ) { } } public float Clamp( float value, float max, float min) { if (value < min) return min; if (value > max) return max; return value; } void setHeroState( int newState) { //根据当前人物方向与上一次备份的方向计算出模型旋转的角度 int rotateValue = (newState - state) * 90 ; Vector3 transformValue = new Vector3(); //播放行走动画 //模型移动的位置数值 switch (newState) { case HERO_UP: transformValue = (Vector3.forward) * Time.deltaTime; ; break ; case HERO_DOWN: transformValue = (-Vector3.forward) * Time.deltaTime; break ; case HERO_LEFT: transformValue = Vector3.left * Time.deltaTime; break ; case HERO_RIGHT: transformValue = (-Vector3.left) * Time.deltaTime; break ; } //移动人物 this .gameObject.transform.Translate(transformValue * moveSpeed); state = newState; } } |