【Unity3D】利用TextAsset读入文件并生成地图

来源:互联网 发布:视频cms 编辑:程序博客网 时间:2024/05/16 10:49

Unity3D可以利用C#的文件流读入文件,但不建议这样做,因为自身就提供了一个TextAsset用于读入数据,尤其是可以将一个关键的csv和txt文件放到Resource文件中,让发布的时候能让其自动打包,不会让用户轻易修改看上去没这么业余。同时比起《【C#】txt的读写》(点击打开链接)的读入方法,利用TextAsset读入数据,比文件流更加简单。下面举一个例子来说明这个问题。

有一个这样的map.csv地图文件:

1,1,1,1,1,0,11,0,0,0,1,0,11,0,2,0,2,0,11,0,1,0,1,0,11,0,1,0,0,0,11,0,2,0,2,0,11,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/这个原始尺寸,就是我们要这个物体缩放的比例。

最后,至于这些二维表文件配合容器处理的思想,可以参考《【C#】读取txt、csv等二维表》(点击打开链接)和《【Java】一行代码读完记事本中的二维表》(点击打开链接)我已经一些再写了,不赘述了。


0 0
原创粉丝点击