`
wgcode
  • 浏览: 578262 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

45度深度排序

阅读更多
一 、 像素排序图层处理法(碰撞检测)
var house:House = new House();
var fish:Fish = new Fish();

var bs:BitmapData = new BitmapData(house.width, house.height, true, 0x00000000);
bs.draw(house);

var bg:BitmapData = new BitmapData(fish.width, fish.height, true, 0x00000000);
bg.draw(fish);


var rect:Rectangle = new Rectangle(0, 0, bg.width, bg.height);
var pt:Point = new Point(0, 0);

var filter:BitmapData = new BitmapData(bg.width, bg.height);

var bsm:Bitmap = new Bitmap(bs);
addChild(bsm);

var bgm:Bitmap = new Bitmap(bg.clone());
addChild(bgm);


stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoving);
function onMouseMoving(event:MouseEvent):void {
	// move bmp2 to the mouse position (centered).
	bgm.x = mouseX - 20;
	bgm.y = mouseY - 50;
		
	//设置阈值(临界值)范围
	var rect2:Rectangle = new Rectangle(bgm.x, bgm.y, bg.width, bg.height);
	//填充一个矩形像素区域(复制)
	filter.fillRect(rect,  0xff0000ff);
	//处理阈值(临界值)像素生成新图像
	filter.threshold(bs, rect2, pt, ">", 0x00000000, 0x80000000);//所有不透明的点变为透明

	//bgm.bitmapData = filter;
	//填充新图像到旧图像中显示
	bgm.bitmapData.copyPixels(bg, rect, pt, filter, pt, false);
}

 

二、当前的对象进行Y方面的深度排序

     按照Y方向先排一下序,然后在用setChildIndex就可以了

 

public function sortY(container:Sprite, ar:Array):void
  {
           ar.sortOn("y", Array.DESCENDING | Array.NUMERIC);
           for (var i:int = 0; i < ar.length; i ++)
           {
                  var tempisplayObject = ar[i];
                  container.setChildIndex(temp, i);
           }
  }

 

三、中心点排序

这个算法好复杂啊
我看过一个实现倒是蛮简单的
在45°的最终视图上
直接做物体中心点的的屏幕坐标比较
优先y轴就可以了

 

var pos1 : Point;
var pos2 : Point;
// 此处的坐标为建筑物的中心点屏幕x & y 坐标
pos1 = renderer1.position;
pos2 = renderer2.position;        
if (pos2.y < pos1.y) {
    return 1;
}
if (pos2.y > pos1.y) {
    return -1;
}
if (pos2.x < pos1.x) {
    return 1;
}
if (pos2.x > pos1.x) {
    return -1;
}
// 结果用于排序的
 四、任意矩形的排序

 

由于做项目做到需要45°排序,搜索到的方法不尽如人意。
http://bbs.9ria.com/viewthread.p ... ertype=1&page=1这篇的算法还算不错,作者也说明已经在实际项目中应用,我觉得对其中3区域和5区域并不能这么简单的归于dephtMin或者dephtMax。实际上,3或者5区域与target的关系是无法确定。


如上图,如果没有C或者D,是根本无法判断A和B的先后位置关系的。(这个图是45°坐标系下的,真实坐标请顺时针旋转45°或者脑袋往左偏45°)
而这个图中的物品丢给上述排序算法,好像也会有问题的,也不知道是否是我不够深入理解上面作者的算法。

我讲一下我的思路。
首先把要插入的物件target的周围分分区域(同样请顺时针旋转45°或者脑袋往左偏45°)



 只要item有点在A区域,那item一定在target后面,我这么判断

 

(item.bottom.x < target.top.x && item.top.y < target.bottom.y) || (item.bottom.y < target._top.y && item.top.x < target.bottom.x)
 

 

前一半是在左上,后一半是右上。
同样只要在B区域,那就说明item一定在target前面,

(item.top.x > target_bottom.x && item.bottom.y > target.top.y)
                        ||(item.top.y > target.bottom.y && item.bottom.x > target._top.x)
 
判断的标准是,只要有点落入A区域或者B区域就行了。C区域的标准是必须所有点都在C区域。当然,以上剩下的全归C了。

然后是C区域,怎么办呢?无法判断前后关系,那就直接无视了。。。下面会讲可以无视的道理。


关于单排或者全排,不管全排有多快,肯定没单排快,而且我觉得完全没必要全排,因为一般来讲,每次插入数组的肯定只有一个物体,就算你插2个也得一个一个来,所以只要分清楚数组内的物品跟插入的数组之间的关系就可以了。
函数:

 

function insertItem($targetisplayObject, $arr:Array):Array

 
$target当然是需要插入的物体,
$arr原先的数组,不包括$target,
返回Array插入之后的新数组

 

 

var tmpArr:Array = [];
tmpArr.push($target);
var index:int = 0;//记录target在数组中的位置
for (var i:int = 0; i < $arr.length; i++ ) {
//循环
var item:DisplayObject = $arr[i];//
if(//A区域){
tmpArr.splice(index, 0, item);//插到targetq前面
index++;
}
else if(//B区域){
tmpArr.push(item);//插到target后面
}
else{//C区域
//这里的话,我觉得无论你用A区域内的加入,或者用B区域的加入,都行。
}
return tmpArr;
}
 

 

 

数组越前面就说明物品层越低,这个好理解,addChild的时候只要按照数组顺序加入就可以了。

这就算结束了。
稍微作以下解释,这里A区域使用splice,B区域使用push的原因,是为了保证原先确定的排序不会被打乱。
当然会有一些比如,数组的第3个在target后面,4跑到target前面,5又跑后面去了,那3,4,5次序不是被打乱了?对,排的就是你,这些3,4,5就是在以前的排序中,互相处于C区域而被无视的那些。这就是为什么处于C区域可以无视,因为处于C区域的时候,其实对本次的顺序其实是没影响的,而一旦出现第一个图中的情况,有物体的插入影响到2者的顺序的时候,自然就能被排出顺序了。

关于优化,算法的话其实还算简单的。当给场景中的物品交换层的时候,可能并不是每个都需要动顺序的,我觉得只要跟target有直接关系的(就是AB区域的)重新设一下顺序就OK了。

五、wxsr45度地图深度消隐算法(深度排序法) 
开篇引章,在这我要先说说我的这个消隐算法的完成前的一个设想:
说这个设想前我们要说说这个设想要成立的一个条件:
Function : getOnlyDepthFunc(targetisplayObject,source:Array):Object
 

target --物品列表中的某一物品。
source --物品列表(包含target)

这个条件方法的最终结果是要返回当前某一物品在一个物品列表中的 唯一确定深度 【itemDepth】以及除去了 target 的剩余物品列表【residualSource】。(可以不需考虑其他物品的深度变化,因为这里只关心target的深度,而事实上因为每次确定一个物品的深度时都有可能导致剩余物品的深度变化所以也是不需要考虑其他物品深度变化的)

好,先不要问这个方法怎么实现,具体实现下边会提到。下边说说我的这个算法的设想


假如现在有一个长度为n的物品列表 【sourceN:Array】,因为假设的已知条件方法【getOnlyDepthFunc】可以返回某一物品在物品列表中的确定深度,我们是否可以
通过逸代这个【getOnlyDepthFunc】方法 并且 参数target 以每次执行完后得到的剩余物品列表【residualSource】的某一个物品,source 则以每次执行完后得到的剩余物品列表【residualSource】去赋值,并且把每次得到的在该片段物品列表中target的唯一确定深度 【itemDepth】储存并整理还原为原物品列表 【sourceN:Array】所对应的物品深度,那么我们就应该可以得到最总我们想要的深度已经排好序的物品新数组了。

上边就是我的设想,这里为了方便大家理解,这里再点一下要注意的一些地方。方法【getOnlyDepthFunc】返回的深度只是参数source列表里的确定深度,但由于每次逸代的
剩余物品列表【residualSource】是总物品列表【sourceN】的剩余片段列表,所以他们存在一个耦合性。

处理上我是这么做的,在排序我前先声明一个跟【sourceN】一样长度的空数组【rebackSource】;然后从第一次开始,以第一次得到的深度为索引 ,将索引对应的物品赋值给【rebackSource】数组对应的位上。然后逸代下一次。因为第2次开始已经是剩余物品列表。所以得出的深度【itemDepth】只是相对于每次返回的剩余物品列表
【residualSource】的对应唯一深度。但正因为是剩余物品列表,所以我们可以通过从开始项到得到的深度索引【itemDepth】项,不为undefiend的项数,来得到在总列表中的位置。也就是【residualSource】列表的具体项。然后把这次的target赋值给该位置。逸代一共执行品列表 【sourceN:Array】长度次。不用考虑效率,因为每次都是剩余列表的长度都在减少,而且不用排序,是一个高效的嵌套循环。

流程大致可以这样表示:

假设第一次的结果为3总物品数为6

【residualSource】=[undefined,undefined,undefined,【第一次的结果】,undefined,undefined,undefined]
.
.
第2次假设得到的结果也是3,这里因为这次的参数列表是剩余列表,也就只要在剩下的6个undefiend中找到第4个undefiend的位置就可以了(因为数组是从0开始的所以3其实相对于第4位)

【residualSource】=[undefined,undefined,undefined,【第一次的结果】,【第二次结果】,undefined,undefined]
.
.

第3次假设得到的结果是0
【residualSource】=[【第三次结果】,undefined,undefined,【第一次的结果】,【第二次结果】,undefined,undefined]
.
.
.
.
第7次结束

就这样一直逸代下去直到循环结束



下边说说关键条件方法实现的原理

要实现这个方法有一个前提条件就是我们必须知道每个物品4个在45度视角下的边界方格位置(原因可看下边)。具体实现我就不说了,因为这样说也没完了,这里只是说原理。而且查找4边界方格位置也是做45度地图的基本工。


下边继续

怎么查找一个物品的唯一深度呢,实现也不难,就是确定一个是深度比自己小的 所有物品的数组dephtMin,或者深度比自己大的多有物品的数组depthMax数组
这样就可以知道该物品的深度了。该物品的深度就是 dephtMin元素个数加1,或者depthMax元素个数减一
方法可以用9宫格法


怎么实现9宫格法,途径很多种,我用的是通过不断推敲得到的算法,下边是参考片段
简要说明下  


                          {[L]}{x,y}{[T]}
                     {x,y}{x,y}{x,y}
                {[B]}{x,y}{[R]}

[L],[T],[R],[B]对应一个物品的4个45度下的边界坐标点也就是我之前说的【getOnlyDepthFunc】方法必要的条件


item是【getOnlyDepthFunc】循环 列表的非target的对象,

target为【getOnlyDepthFunc】的target参数

公式:

item.sideR=(target.[B].y-item.[L].y)
item.sideL=(item.[B].y-target.[L].y)
item.sideB=(target.[T].x-item.minZ.[L].x)
item.sideT=(item.[T].x-target.[L].x)

当item.sideR<0时,item于target的右边;
当item.sideL<0时,item于target的左边;
当item.sideT<0时,item于target的上边;
当item.sideB<0时,item于target的下边;
当item.sideL<0且item.sideT<0时,item于target的左上边;
当item.sideL<0且item.sideB<0时,item于target的左下边;
当item.sideR<0且item.sideT<0时,item于target的右上边;
当item.sideR<0且item.sideB<0时,item于target的右下边;
当上边4值任意为-1时,target于item的对应边界



通过这个算法,我们就可以简易的确定出以target为中心的相对于target与物品列表其他物品位置关系的一个9宫格分布了。也就是下边的图示

得到了这个9宫格然后怎么办了,这里再罗嗦下 45度下的深度排布,也就是画家算法的基本原理;

               {5}{2}{0}
             {7}{4}{1}
            {8}{6}{3}

45度下的物品深度由低到高应该是这样的。越越视角深度越低,越高视角深度则越高

             
像上边的图示,target应该的位置就是{4} 而之前我们提到的两个数组dephtMin 跟dephtMax
就应该等于 dephtMin =【{0},{1},{2},{3}】
dephtMax=【{5},{6},{7},{8}】
当然这两个数组的个数根据我上边给出的公式得到的具体数目决定,

好了教程到此结束,不明白的地方可以回复或者,mes 我,

欢迎大家谈论,还有上边的设想我是已经实现的了碍与项目保密性就不发例子了,但可以说效果很好,所以特发此教程跟大家一起分享下 要转载的请表明下谢谢


 



 

 

 

 

 

  • 大小: 44.1 KB
  • 大小: 18.9 KB
  • 大小: 9.3 KB
  • 大小: 137.2 KB
  • 大小: 48.7 KB
  • 大小: 28.8 KB
  • 大小: 14 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics