3D可以利用C#的文件流读入文件,但不建议这样做,因为自身就提供了一个TextAsset用于读入数据,尤其是可以将一个关键的csv和txt文件放到Resource文件中,让发布的时候能让其自动打包,不会让用户轻易修改看上去没这么业余。同时比起《【C#】txt的读写》(点击打开链接)的读入方法,利用TextAsset读入数据,比文件流更加简单。下面举一个例子来说明这个问题。
有一个这样的map.csv地图文件:
1,1,1,1,1,0,1
1,0,0,0,1,0,1
1,0,2,0,2,0,1
1,0,1,0,1,0,1
1,0,1,0,0,0,1
1,0,2,0,2,0,1
1,0,1,1,1,1,1
转成UTF-8编码的,避免乱码,天地可鉴。
、
要按照上面的地图配置csv(可以用Excel编辑;保存成txt都没问题),生成如下的7x7地图,其中1代表墙高1个单位,2代表墙高2个单位,0代表没有墙。用逗号分割出一个个单位。
地图换一个视觉则如下所示:
当然地图简陋无比,这灯光和摄像机整成的渣画面,绝对无法上架,但原理就是这个原理,你让你的策划MM(哪有这么多MM?有也是有另一半的-_-!)布置一张1个亿x1个亿的地图也是这样生成的。制作过程如下:
我们根本就不需要在场景布置任何东西,你只要将摄像机和灯光放到合适位置就行,设置你可以脚本生成灯光和控制摄像机。我这里是用了一个Point light在这迷宫上方,有更好的灯光布置方式真的请多加指教!你只要在Asset新建一个Rescource文件夹,将上述的Map.csv如同《【Unity3D】BGM》(点击打开链接)中的BGM或者《【Unity3D】对话》(点击打开链接)中的对白导入到这个Rescoure文件夹则行。
整一个空物体布置如下的Map.cs就行。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;//这里用到了C#容器
public class Map : MonoBehaviour
{
void Start()
{
TextAsset textAsset = (TextAsset)Resources.Load("Map");//载入Map.csv,注意不要有其它格式叫Map的,或许有未知错误
string[] map_row_string = textAsset.text.Trim().Split('\n');//清除这个Map.csv前前后后的换行,空格之类的,并按换行符分割每一行
int map_row_max_cells = 0;//计算这个二维表中,最大列数,也就是在一行中最多有个单元格
List<List<string>> map_Collections = new List<List<string>>();//设置一个C#容器map_Collections
for (int i = 0; i < map_row_string.Length; i++)//读取每一行的数据
{
List<string> map_row = new List<string>(map_row_string[i].Split(','));//按逗号分割每个一个单元格
if (map_row_max_cells < map_row.Count)
{//求一行中最多有个单元格,未来要据此生成一个Plane来放Cube的
map_row_max_cells = map_row.Count;
}
map_Collections.Add(map_row);//整理好,放到容器map_Collections中
}
/*生成一个刚好放好Cube的Plane*/
GameObject map_plane = GameObject.CreatePrimitive(PrimitiveType.Plane);//生成一个Plane
map_plane.transform.position = new Vector3(0, 0, 0);//放到(0,0,0)这个位置
//求其原始大小
float map_plane_original_x_size = map_plane.GetComponent<MeshFilter>().mesh.bounds.size.x;
float map_plane_original_z_size = map_plane.GetComponent<MeshFilter>().mesh.bounds.size.z;
//缩放这个Map到所需大小,刚好和二维表匹配
float map_plane_x = map_row_max_cells / map_plane_original_x_size;
float map_plane_z = map_Collections.Count / map_plane_original_z_size;
map_plane.transform.localScale = new Vector3(map_plane_x, 1, map_plane_z);
/*在Plane上放Cube*/
for (int i = 0; i < map_Collections.Count; i++)//Z方向是长度就是容器的大小,也就是map.csv有多少有效的行
{
for (int j = 0; j < map_Collections[i].Count; j++)
{//X方向的宽度就是容器一行中的最大的长度,也就是map.csv中每行最大长度
int cube_num = int.Parse(map_Collections[i][j]);//将每个单元格的数字转换成整形
for (int k = 0; k < cube_num; k++)
{//根据数字,在一个单元格内生成cube
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(-(map_row_max_cells / 2) + i, (float)0.5 + k, -(map_Collections.Count / 2) + j);
/*
cube所处的坐标就是(-(map_row_max_cells / 2) + i, (float)0.5 + k, -(map_Collections.Count / 2) + j)
*/
}
}
}
}
}
整个算法的思想如下图所示:
首先要注意的是,笛卡尔三维坐标系Y是垂直的轴。
然后算法内,在Unity3D你要缩放一个物体,只能用到~.transform.localScale去单位缩放,也就是说只能设置缩放多少倍,但我们就是要将原本默认的10x10的Plane缩放的7x7该怎么做呢?就是要利用~.GetComponent<MeshFilter>().mesh.bounds.size.X/Y/Z;求出该物体在X/Y/Z轴的原始尺寸,然后再用7/这个原始尺寸,就是我们要这个物体缩放的比例。