用3D技术实现2D场景

一、超大场景平滑切换的实现方法(3D/2D场景都适用)
二、非多重混合纹理实现地表(既用图素方法够成)
三、碰撞检测
四、室内外场景结合


整 个场景由64*64=4096个区域构成,每个区域管理4*4=16个屏幕大小场景,合计65535个屏幕场景。理论上可以更加大,目前的这样的场景数据 约占用300M的磁盘空间(Zlib标准压缩后约12M空间)。不用多线程场景切换约为<1秒。多线程时候,采用中等优先级别的线程就可以做到平滑 切换了。

Class QuadTree{
    //用以剪裁判断,哪些区域的块需要渲染
};

Class 区域的块 :public QuadTree{
    *m_p区域;//隶属于哪个区域
    int32 *m_pDoodadsIndex;//哪些场景物件在这个区域的块中(索引)
};

Class 区域{
    int m_nX, m_nY;//该区域的x,y
    uint8* m_pPath;//路径障碍关系
    uint8* m_pGroundFlag;//贴图图素位置信息
    场景物件* m_pDoodads;
    区域块[4][4];
    QuadTree m_QuadTree;
    LoadData(){
       --[[
           根据m_nX, m_nY ,从磁盘装载该区域的数据
        ]]
    };
    SetUpQuadTree(){
      //将装载好的数据分成区域块,放到QuadTree的中,每个区域块都是QuadTree的一个叶子
    };
};

Class世界{
    int m_nX,m_nY;//管理区域的中心,即屏幕中心的块的x,y
    区域装载的缓冲[16];
    区域指针[3][3];
    Enter(x,y);//进入某个区域
};

上面的结构应该不是很难理解, QuadTree部分只是剪裁渲染部分使用的,完全可以跳过。
以下旨在介绍 区域装载缓冲 的运用

*--*--*--*
|    |    |    |
*--*--*--*
|    |@|    | 
*--*--*--*
|    |    |    | 
*--*--*--*

@是现在Enter(x,y)进入的区域,我们需要将其周围的那些块都装载到内存来,并进行设备初始化包括网格贴图模型。(注意装载不是说一定要对其进行渲染。是否渲染是由QuadTree或者其他剪裁方法来完成的)
Enter(x,y)
{
  m_nX = x; m_nY = y;
  For(int i=0;i<3;i++)
  {
      For(int j=0;j<3;j++)
      {
        区域指针[i][j] = _Load(x-1+i,y-1+j);
      }
  }
}

Load(x, y)
{
  //首先判断x,y是否合法(x,y<0,x,y>=64),如果不合法,return NULL.
  Int nNULL = 16;//需要找一块没有使用或者不需要使用的缓冲区来装载该区域
  for(int i=0; i<16;i++)
  {
    if(区域缓冲[i] != NULL)
    {
      if(区域缓冲[i].m_x == x && 区域缓冲[i].m_y == y)
      {
        //原来已经装载过这个区域了,返回就好
        //return 区域缓冲[i];
      }
    }
    else
    {
      if(i< nNULL) nNULL=i;
    }
  }
  if(nNULL == 16)
  {//所有的缓冲都被使用了
   //用离本区域最远的一块缓冲将其来装载
   //最远意味着该区域短时间内用不上
    int m, n = 0, k = 0;
    for (int i=0; i<16; i++)
    {
        m = abs(区域缓冲[i].m_nX-m_nX) + abs(区域缓冲[i].m_nY-m_nY);
        if (m>n){n = m;k=i;}
    }
    //找到了,将这个最远的区域删除掉
    delete[] 区域缓冲[k]; 区域缓冲[k]=NULL;
    nNULL = k;
  }
  //好了。现在有空位缓冲装载这个区域了
  区域缓冲[nNULL] = new 区域(x, y);
  {//用多线程装载
    LoadThreadManang(区域缓冲[nNULL]);
  }
  {//不用多线程
    区域缓冲[nNULL].Load();//装载该区域的数据
    区域缓冲[nNULL].InitDeviceObject();
  }
}


=================================================================

http://war.5u56.com/mebin.tar.gz
可以下载演示程序。不过这个只能运行在X-Window环境下,需要GTK2.0支持以及安装了FMOD4.12的动态库。
后面的贴有windows下运行的程序。
注意:因为windows环境下没有对应linux字体的缘故
打开exe目录下的config.lua,并修改

原来的
--[[ windows
SYSTEM_FONT_FACENAME = "新宋体";
DEFALUT_FONT_FILENAME = "fzbwks_j.ttf";
DEFALUT_FONT_FACENAME = "方正北魏楷书简体";
]]
SYSTEM_FONT_FACENAME = "AR PL SungtiL GB";
DEFALUT_FONT_FACENAME = "ZYSong18030";

修改为这样
SYSTEM_FONT_FACENAME = "新宋体";
DEFALUT_FONT_FILENAME = "fzbwks_j.ttf";
DEFALUT_FONT_FACENAME = "方正北魏楷书简体";
--SYSTEM_FONT_FACENAME = "AR PL SungtiL GB";
--DEFALUT_FONT_FACENAME = "ZYSong18030";

应该就可以了。

另外,windows下面字体显示部分会是乱码。搜索应用程序目录下的所有*.lua文件。
用记事本打开,重新保存为ANSI码模式,就可以了。源模式是UTF-8的。

二、非多重混合纹理实现地表 
常见采用多重纹理混合来实现色彩丰富的地表,大概方法如下
#N贴图+Alpha通道
#3贴图+Alpha通道
#2贴图+Alpha通道
#1贴图+Alpha通道
#0最底层地表贴图
操作方法和PhotoShop的图层概念一样,选中某一层,刷通道就可以了。
这样的方法,制作简单,地表丰富多彩,贴图占用适中,渲染时候效率也高,没有缺点。
以下主要介绍用图素拼接来表现地表。此方法贴图占用最小,渲染效率中等。优点是适合做一些特殊地形地表的表现。例如《模拟人生2》地面地砖变化。
制作图素地表方法和在家里铺地砖的方法,简单的做法是拿一块砖铺一块砖。想快点铺的话,那么按鼠标键不访,在需要铺的地方,刷就好了。
这里说的砖就是图片图素,可以通过通道,对其进行变化。好比一块砖是32*32大小的图片,如果该图片的左半边是透明通道,那么就是半块砖了。砖的表现形状取决于通道的变化。
渲染的时候相对比较复杂,效率没有多重混合纹理地表高。渲染之前需要做一次规划(不是每次渲染之前,这个工作一共只需要一次就可以了)
一、首先获取用到了多少种地砖,按照该使用数量将其分为对应层。
二、计算每种地砖使用了多少次,根据其位置,算出网格。每一块砖就是一个网格。这样做的目是为了批量渲染网格,一个个渲染就太慢了。
之后,在渲染的时候,可以这样做
for(int i=0;i<多少种砖;i++)
{
 render(这样砖使用的网格信息);
}
欢迎提出疑问,更欢迎相互讨论学习。

三、碰撞检测以及室内外场景结合
之所以说是2D场景3D效果演示,因为这里的高度数据除了渲染时候用到外,没有任何用途。3D场 景中的碰撞检测一般多用包围盒或者其他方式的模型碰撞检测。而这里适用的是100%的2D场景中最常见的PATH数组来实现的。这样做最大的好处就是碰撞 检测的速度快,如果需要的话,服务器也可以保留这样障碍数据,便于检查判断在移动时候的合法性。同时可以使用常用的2D路径搜索方案。例如A*。
例如
0x01不能走
0x02不能飞
0x04不能放置物件
0x08,0x10,0x20....
每个物件或者建筑物可以有对应一个障碍关系的图片。如附件中的图片。
蓝色表示:不能放置建筑物 0x04
洋红色表示:不能放置建筑物,也不能行走 0x04|0x01
等等

正是应为这样的采用PATH数组来保存障碍,所以室内外场景的组合,制作起来就非常容易了。
一栋房屋建筑占地面积可能很大,甚至超过一屏或者更多屏。(注意以下介绍的方法不合适多层建筑。)
A、模型制作。需要美术制作人员制作出房屋外观模型和室内模型。家具物件等是在地图编辑其中摆放的,无需在制作室内模型摆放。
B、处理方法。当角色在室外时候,只外场景的地表以及该室外模型的外观,室内模型以及该房间内的所以其他家具等模型全部不渲染。当角色进入市内时候,只渲染室内模型以及已经放在quadtree中的那些需要渲染的家具物件。
C、如何判断何时进出室内外。可以通过查询PATH得知进还是出,如果是进入,继续查询进入的房间编号。

欢迎提出疑问,更欢迎相互讨论学习。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值