首先,我们先来看一下现成的地图拼接算法。下面是一张《魔兽争霸3》的地表素材。
看到了比较清楚的图片边界是吗?我们把这张图按照64X64进行一下切分
其实把图摆成这样是有原因的,现在,我们来看4张图:1号,2号,4号以及8号。可以发现,他们刚好是四个角落的素材。如果我们把一张64X64的图,再进行4等分,默认以0来标识,如下:
0 | 0
----------------
0 | 0
再把刚才所提到的4张图,根据编号和位置,填到上面的结构里,如:
1号图(右上角):
0 | 1
----------------
0 | 0
2号图(左上角):
2 | 0
----------------
0 | 0
4号图(右下角):
0 | 0
----------------
0 | 4
8号图(左下角):
0 | 0
----------------
8 | 0
或许你会很奇怪,我们为什么要定义这4个数字,下面,来做一些有趣的事情吧。
我们把4号结构和8号结构按照对应的位置相加,得到了什么?
0 | 0
----------------
8 | 4
此时,4个角落的数字相加,为0+0+4+8 = 12
12,这个数字貌似我们在前面的图中看到过,找找编号看。你会发现,刚好12就是下面连成一气的草地素材。
再做个其他试验?例如把8号和1号结构相加:
0 | 1
----------------
8 | 0
此时,4个角落的数字相加,为0+1+8+0=9
当然,9也刚好就是我们的素材里,右下和左上连成一气的草地素材。
数学原理:以1,2,4,8分别代表一个区块的4个角落的素材编号。当发生叠加时候,将角落里的值进行累加,最后,4个角的合即为地图区块所对应的编号。
// 用一个数组来标记图形中各个位置的编号
var config:Array = [
[0,4,8,12],
[1,5,9,13],
[2,6,10,14],
[3,7,11,15],
];
// 用来存放图片素材的数组
var lib:Array = new Array();
var bitmap:BitmapData;
// 源素材,就是我们上面的那张PNG
var bd:BitmapData = new BMD();
var py:uint;
var px:uint;
// 进行切割
for(py = 0;py
var arr:Array = new Array();
// 生成10X10的地图
for(py=0;py<10;py++)
{
var data:Array = new Array();
for(px=0;px<10;px++)
{
// 每个地图区块包含4个顶点数据,默认为0
data.push([0,0,0,0]);
}
arr.push(data);
}
当我们点下鼠标时候,如图所示,我们会把鼠标指针所在的位置的顶点数值设置为4,而临近的顶点数值分别设置为8,1,2,刚好拼凑成上面这样的图形。
当然,同样用这样的方法在临近的位置点击,我们就会得到这样的效果:
如图,我们点击的鼠标位置,和上次点击一样,我们把点击的位置顶点值设置为4,临近顶点为8,1,2。而此时,因为这个顶点和上次的8号顶点其实在同一个Tile里,导致这个Tile内的顶点总和变成了12,所以更换了素材。于是我们得到了一个非常平滑的过度。
当然,再继续点下去,也是同样的算法,这里就不再赘述了。
来看一下后面的代码,点击的时候,当然是计算点击位置对应的区块,然后把改区块的右下角顶点值设置为4,这里要注意,如果这个顶点已经是4了,那就没必要再设置了。如果再设置,这个顶点变成了8,很显然就不对了。
stage.addEventListener(MouseEvent.CLICK,onClick);
function onClick(e:MouseEvent):void
{
// 计算区块
var _mx:uint = int(e.stageX/64);
var _my:uint = int(e.stageY/64);
// 区块顶点设置,3右下 2右上 1左下 0左上
if(arr[_my][_mx][3]!=4) arr[_my][_mx][3]+=4; // 当前区块的右下
if(arr[_my][_mx+1][1]!=8) arr[_my][_mx+1][1]+=8; // 右边区块的左下
if(arr[_my+1][_mx][2]!=1)arr[_my+1][_mx][2]+=1; // 下面区块的右上
if(arr[_my+1][_mx+1][0]!=2)arr[_my+1][_mx+1][0]+=2; // 下面右边区块的左上
reDraw();
}
var resBD:BitmapData = new BitmapData(640,640,true,0xff000000);
addChild(new Bitmap(resBD));
function reDraw():void
{
resBD.fillRect(resBD.rect,0);
for(py=0;py<10;py++)
{
for(px=0;px<10;px++)
{
var b:uint=arr[py][px][0]+arr[py][px][1]+arr[py][px][2]+arr[py][px][3];// 计算顶点合
if(b==0) continue;
if(b>15) b=15; // 超出15的顶点合是没有意义的。在魔兽争霸里,超出15会随机一个填充满的样式以丰富地表
resBD.copyPixels(lib[b],lib[b].rect,new Point(px*64,py*64),null,null,true);
}
}
}
文章来源:http://bbs.9ria.com/forum.php?mod=viewthread&tid=157487