页面

2010年4月20日星期二

2.5D基础--菱形Tile

@    当然菱形格子有好几种,我接触到的,也是平时用最多的,就算是这一种了吧,还有个名字的不过给忘了,鉴于平时做东西总是用完忘完,所以乘着还在做这个东西,把一些东西给记录下来,下次用的时候也方便点,这个帖子估计得分好几次来写完吧!
    现在进入正题,下图是自己在windows自带的画图工具里草草画的,说明意思就可以了


如上图,地图里用tile,可以是一个地图用一片tile,也可以按功能区分为几片tile,这样可以省略点没有功能的地图也消耗一些资源吧!功能区用Field来管理,也就是说一个地图可以这么来分层(容器就叫World吧):
一、GBPanel,背景层,里面加载一张地表的位图;
二、TilePanel,格子层,里面管理所有的格子,当然这些格子又是按照区来组织起来的
      TileList:在TilePanel里保存一个的数组来存储几个区Field; 
        Field:在这里面才是真正管理Tile的地方,每一个Field就如上图所画的东西样,管理着其下的一片Tile,完成诸如建筑占地啦,拖动建筑时的映像啦,人物寻路啦等功能;
          Tile:这个就是单个的菱形格子了,要完成按照不能的信息绘出不同的形状啦,保存一些信息啦。
三、BuildingPanel,建筑层,也包括人物,主要地图之上要表现和交互的元素基本都在这一层了,要管理元素的排序啦等;
四、EffectPanel,这一层主要放些不需要交互的效果,如放些飞鸟啦,云啦什么的。

    哇!好像扯了很远啊!赶紧返回到主题来,话说这个格子层是分有逻辑坐标和物理坐标的,这两个应该很好理解,那这个Field的物理(0,0)坐标就在它的中间最上面的那一个Tile的上顶点位置了,而以该顶点沿X轴正方向向下延伸的即为逻辑横坐标,而沿X轴负方向向下延伸的为逻辑纵坐标,看看上图格子里标的逻辑坐标就比较清楚了
    接下就应该了解下两种坐标体系的转化公式了,在说这个之前先分析个问题:初始化Field时肯定是要生成每个Tile(row,col),然后把这个addChild(Tile)的,那在addChild时怎么确定这个Tile的物理坐标呢?
     ====================================================
    不要混乱,我们分开来看,不要把思路给搞乱,计算其X坐标值吧!我们不要直接去找跟(0,0)点有什么关系,我们首先看某个Tile的逻辑横坐标row相对于Tile(row,0)偏移了多少,这个很好计算出来offsetX_1=-col*WIDTH/2,而Tile(row,0)相对于Tile(0,0)的偏移量是offsetX_2=row*WIDTH/2,所以我们就把这个Tile的物理横坐标给求出来了
@#    pX=row*WIDTH/2-col*WIDTH/2;
接下来再来搞它的纵坐标,其实还是用上面的方法
@#    pY=row*HEIGHT/2+col*HEIGHT/2;
这样我们就顺利的生成出了一片的Tile了,但是这还不够的,我们平时操作的时候更多的用到的是从物理坐标取到相应的逻辑格子出来,那这个反方向的计算好不好弄呢?这是个很容易的解二元一次方程啊!1式两边同乘HEIGHT,2式两边同乘WIDTH,然后两式相加得row,相减得col
#    row=pY/HEIGHT+pX/WIDTH;
#    col=pY/HEIGHT-pX/WIDTH;
这就好了吗?不对的,因为取坐标可不会刚好某个Tile的(0,0)坐标的,所有得先把那个物理坐标调整下才能用,那怎么调整呢?从Tile(0,0)就能看出来横坐标大于0但小于WIDTH/2的都得算0,纵坐标大于0小于HEIGHT/2的都得算0,所以调整后的式子就是这样的
#    row=int(pY/HEIGHT/2)*HEIGHT/2  /HEIGHT+ int(pX/WIDTH/2)*WIDTH/2  /WIDTH;
#    col=int(pY/HEIGHT/2)*HEIGHT/2  /HEIGHT- int(pX/WIDTH/2)*WIDTH/2  /WIDTH;
最后结果就是这样了:
@#    row=0.5*(int(pY/HEIGHT/2)+int(pX/WIDTH/2));
@#    col=0.5*(int(pY/HEIGHT/2)-int(pX/WIDTH/2));
好,坐标转换到此结束!
    ====================================================
    坐标转换只是个基础而已,是个不涉及业务的基础,即使不了解这个转换机制一样能写出个好的例程来,只需要查到工式直接套用就可以了,所以以上内容了解下就可以了,重点精力还是要放到具体怎么来使用这些格子的知识来转换为我们的业务功能。
    首先,这个TilePanel或者说是Field吧,跟BuildingPanel是处于同一层的,同被World管理,那么就明白BuildingPanel其实只是管理显示,而逻辑是放在TilePanel(也可以是Field,看是什么粒度了)中的,下面就展开来说明我所遇到的这些功能:
    一、根据Field来决定初始时哪些地方可用,哪些地方不可用。虽然在一张大地图上已经为功能区和非功能区划分出了几个实际的Field,那没有Field肯定是没有功能的了,但不是每个Field包含的所有Tile都是有功能的,功能区不可能总是规则的那么一块大菱形吧!所以就要根据数据来决定一个Field中的哪些地方是可用的,哪些地方是不可用的。而TilePanel中的每个Field都应该包括以下属性:x,y,rowCount,colCount,type,data,其中前四项好理解,分别为在地图中的坐标及总格子数,而type算是个标记吧,总得分开每个Field,最后一个data属性这个是关键的,这个值应该是个数组,一个包含Field中每个Tile属性的数据,如0代表可用,1代表不可用等,而这个值应该是用地图编辑器来生成的。
    二、动态刷新逻辑数据。这个是用来处理比如建造个建筑,移除个建筑,焦点某块区域等,需要注意一点:Field来管理区域,而Tile处理单个格子。
比如:
1)要在一个Field当中的某个坐标上建筑一个3*3格子大小的建筑,那就要由Field来找出坐标对应的这个3*3区域内的(0,0)格子,再把接下来的8个格子全部做一个处理,如:通知这九个格子已经被占、这九个格子绘成红色等
2)拖着一个建筑时要显示该建筑映像的格子,那就要在拖动的过程当中一直去寻找当前建筑对应的(0,0)格子,再根据建筑占地大小把那一块区域的格子置为焦点状态,这里有个技巧:不要一次去处理找(0,0)格子和绘焦点状态,而应该找到(0,0)格子,然后抛一个TILE_CHANGE事件到World里再去处理Field.focusArea(),因为可能随着焦点格子的变化需要处理多方面的数据如BuildingPanel里要处理,Field里要处理,还有其它层里也要处理等
    
    最后想说一下Tile的处理,Tile虽说是只处理个根据自己状态绘不同表现的功能,但也有技巧的,它的状态可以用二进制来记录,然后根据传进来的值, 或者 异或 其state,这样就可以保存多个值并都可以单独处理,如block的状态时也可以focus状态,focus状态消失后不影响其block状态,因为它们在不同的位上记录着!

这个后期最好把代码给加上


没有评论:

发表评论