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

游戏效率优化之 如何降低容器子集好庞大时鼠标的滑动消耗

阅读更多

如果你有一定的as游戏开发经验,那相信你也应该知道但场景里放入好多的子可视对象时,鼠标的滑动会导致cpu的狂飙;

原因主要在于fp内部在不停的遍历可视对象.你可能会用过或者知道可视对象都有这个方法getObjectsUnderPoint ()

它能够返回鼠标点下的可视对象列表 .这也是鼠标滑过时消耗高的原因所在.当然它更大的用途是用于辅助重绘的实现以及其他.

有什么方法可以降低这块的消耗呢?答案是有的;

每个可视对象都有两个属性

 mouseChildren 跟mouseEnabled

mouseChildren的作用是确定对象的子项是否支持鼠标 而

mouseEnabled 的作用就在于  指定此对象是否接收鼠标消息。 
恩很显然 mouseEnabled跟 mouseChildren就是决定对象是否可以侦听鼠标事件的关键所在;
事实也证明只要设置了这两个属性鼠标滑过的高消耗就减少了,那是因为但这两个属性都设置为false后 就不在归到遍历树的对象中去了,

当然你也发现折辱这两个属性的功能呢个一样虽然我们可以把这两个属性都设置为false,但这不就意味着我们要放弃鼠标侦听?要知道游戏里对鼠标点击,鼠标松开,鼠标滑等鼠标事件都是十分依赖的.

恩,这是事实,但我们却可以用别的方法来取代他们;取代现有提供的鼠标事件方法;
而我这里说的方法就是动态4叉树.相信了解的人都知道4叉树主要用于搜索,跟剔除.而且效率相当高
当然一个4叉树还不够,我们还需要一个碰撞检测的方法来辅助下,下边会说说原理. 
(没有了解的可以去看看我这帖子http://wxsr.blogbus.com/logs/60788934.html) 

我之所以采用动态4叉树除了它效率高之外还在于它可以忽略遮挡物,对,fp的鼠标事件必须要点击到可视对象中去,而且如果某可视对象注册了鼠标事件但如果他上边有另外一个可视对象遮挡住的话,那么它依然无法触发到事件,但动态4叉树却可以给我们解决掉这个游戏里紧要需求的问题.

 动态4叉树的工作原理我就不多说了,大家可以查找资料或者看看我之前发的帖子.
下边说说这么用动态4叉树来取代鼠标事件;
这里要声明下,我这里说的取代鼠标事件并非完全不用鼠标,至少我这里还是需要两个鼠标事件一个是mouseDown跟mouseUp没办法要捕获鼠标动态只能通过InteractiveObject的这两个事件来实现,但这个注册的容器却是不需要固定的,它可以是任意的一个,只要你觉得方便即可,而关键的一点在于,,他解决掉了一大部分鼠标滑过的cpu消耗;

好下边继续, 动态4叉树主要的左右就是搜索出鼠标点下一个范围内的以注册可视对象;他的最终目的是高效的返回某个点下的以注册的可视对象列表.
然后我们需要做的就是对着先对象进行排序,这里要说明一点虽然这里我排序了,但不影响消耗,为什么呢?主要是因为我们可以通过限制我们的搜索范围来达到 缩小排序对象的数目,一般情况下,搜索出来的对象几8个以内具体似乎你的重叠数目了,这部分的排序的目的就是为了将他们按深度高到低来排序,然后一个循环,从最高为开始.检测该对象是否于鼠标点碰撞.也就是说鼠标点是否在他的对象范围矩形内.由高往低排序也是为了符合深度最上的对象优先的原则;
只要俺这个顺序某个碰撞了,那么我们就可以确定到我们鼠标点下的可视对象是什么了然后跳出该循环即可,
整个取代鼠标事件的主要实现过程也就是这些了;

当然还有一些优化的方法,对于游戏来说很多时候我们游戏的物品不一定就在同一夫级下的,那种情况我们有怎么界定他们的深度关系呢?

这个问题其实还是比较好解决的,比方说A跟B 两个容器下,他们都有n个子集对象,我们只要先知道A跟B的深度关系来确定一个夫级系数然后让他们的子对象乘以该系数就好了,比方说A跟B位于最外图层,那么我们可以分派给最外层的系数为10000,A跟B的子集深度系数就是10000乘以A跟B各自深度+1(深度是从0开始的)然后各自的子集对象只要拿他们的深度加上这个夫级系数即可相似的看作是一个有序的深度大小关系了,

比方说AB位于场景下,A的深度是0,它有两个子对象a,b他们的深度分别为a-0,b-1 . B的深度是1它也有两个子对象c,d 他们的深度为别为c-0,d-1
假设我们给A,B定的系数是100
那么abcd 的深度大小关系就是
a-1001   
b-1002  
c-2001  
d-2002
 这样我们就可以确定出每层的不同父级的对象的深度关系了.


同样的但我们面对的对象是一张png位图 时除了确定深度关系我们还要排序非同透明区域,,也就是精准像素碰撞的方法,这个实现在这里就相当简单了,只要我们每检测一个对象时以该对象下的鼠标点为值画一个像素的bitmapdata然后提取一下它的alpha通道值是否为0即可了.
好了就说到这了,下边是例子:
http://filer.blogbus.com/1587898/resource_158789812690578840.rar
 
 <?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx" 
creationComplete="init()" 
backgroundColor="0xcacaca"
minWidth="955" minHeight="600">
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.quadTrees.Hash;
import com.quadTrees.INoder;
import com.quadTrees.Noder;
import com.quadTrees.QuadTrees;

import flash.filters.GlowFilter;
import flash.utils.getTimer;

import mx.core.UIComponent;
private var qtree:QuadTrees=new QuadTrees
private var keys:Vector.<String>=new Vector.<String>
private var array:Vector.<INoder>=new Vector.<INoder>
private var s:Sprite=new Sprite
private var arr:Vector.<INoder>=new Vector.<INoder>
private var searhSize:int=200;
private var ui:UIComponent=new UIComponent
private var definition:int=10
private var _idIndex:int=0
private var item:Noder
private var selete:INoder
private var mouseDown:Boolean
private var clickItem:Noder
private function init():void
{

this.addElement(ui)
this.addElement(txt)
this.addElement(box)
this.addElement(this.add)
this.addElement(this.remove)
this.addElement(this.numStepper)
this.addElement(this.numStepper0)
this.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownFunc);

this.addEventListener(MouseEvent.MOUSE_UP,mouseUpFunc)
for(var i:int=0;i<300;i++){
var s:Noder=new Noder(this.qtree)
s.graphics.lineStyle(1)
s.graphics.beginFill(0xffff00)
s.graphics.drawCircle(0,0,40)
s.x=Math.random()*900>>0
s.y=Math.random()*450>>0
s.vo.id=idIndex.toString()
s.mouseChildren=false
s.mouseEnabled=false
s.cacheAsBitmap=true
ui.addChild(s)
array.push(s)
keys.push(s.vo.id)
if(i==0)item=s;

}


var rect:Rectangle=new Rectangle(0,0,1000,1000)
qtree.setUP(1000/2,1000/2,rect,array,keys);
qtree.graphics=ui.graphics
this.qtree.minSize=10
var b:Timer=new Timer(80)
b.addEventListener(TimerEvent.TIMER,moveFunc);
var hash:Hash=this.qtree.nodes

b.start()
}

private function mouseUpFunc(event:MouseEvent):void
{
mouseDown=false
if(clickItem)clickItem.filters=[]
clickItem=null
}
private function mouseDownFunc(event:MouseEvent):void
{
mouseDown=true
var array:Vector.<INoder>=this.getMouseUnderPoint()

var item:INoder=this.getHitTestPoint(array)

if(item)
{
Noder(item).filters=[new GlowFilter(0x0000ff,1,20,20)]
clickItem=item as Noder
}
}
private function comparFunc(a:INoder,b:INoder):Number
{
var index1:int=DisplayObject(a).parent.getChildIndex(DisplayObject(a))
var index2:int=DisplayObject(b).parent.getChildIndex(DisplayObject(b))
return index2-index1
}
private function get idIndex():int
{
this._idIndex++
return this._idIndex
}
protected function add_clickHandler(event:MouseEvent):void
{
for(var i:int=0;i<10;i++){
var s:Noder=new Noder(this.qtree)
s.graphics.lineStyle(2)
s.graphics.beginFill(0)
s.graphics.drawCircle(0,0,(Math.random()*3>>0)+20)
s.x=Math.random()*900>>0
s.y=Math.random()*450>>0
s.vo.id=idIndex.toString()
s.mouseEnabled=false;
s.mouseChildren=false
s.cacheAsBitmap=true
ui.addChild(s)
array.push(s)
}
}

public function getHitTestPoint(array:Vector.<INoder>):INoder
{
if(array.length<1)return null;
array=array.sort(comparFunc);
for(var i:int=0;i<array.length;i++)
{
var item:INoder=array[i]
if(DisplayObject(item).hitTestPoint(this.mouseX,this.mouseY)){
return item
break
}
}
return null
}
protected function remove_clickHandler(event:MouseEvent):void
{
try{
for(var i:int=0;i<10;i++)
{
var item:Noder=array.shift() as Noder
item.unload()
item.parent.removeChild(item)

}
}catch(e:Error)
{

}
}
private function moveFunc(event:TimerEvent):void
{

if(!this.mouseDown){
for(var i:int=0;i<this.array.length;i++){
var item:Noder=array[i] as Noder
item.x+=item.vx*item.a
if(item.x>900||item.x<0)
{
item.a=-item.a;
}
item.y+=item.vy*item.b
if(item.y>500||item.y<0)
{
item.b=-item.b;
}
}

if(selete)
{
Noder(selete).filters=[]
}

var t:Number=getTimer();
//	 arr=getMouseUnderPoint()
//	 selete=getHitTestPoint(arr)
//	 this.txt.text='区域内共有:'+arr.length+'个对象 搜索时间:'+String(getTimer()-t)+' 毫秒'
//	 this.box.text='对象数:'+array.length.toString()
if(selete){
Noder(selete).filters=[new GlowFilter];
}
}

}

private function getMouseUnderPoint():Vector.<INoder>
{
var vx:Number=this.mouseX-searhSize/2;
var vy:Number=this.mouseY-searhSize/2;

this.ui.graphics.clear();
this.ui.graphics.drawRect(vx,vy,searhSize,searhSize)
var rect2:Rectangle=new Rectangle(vx,vy,searhSize,searhSize)
return qtree.find(this.qtree.node,rect2,definition)

}
private function sizeChangeFunc():void
{
this.searhSize=this.numStepper.value
}
private function sizeChangeFunc2():void
{
this.definition=this.numStepper0.value

}



]]>
</fx:Script>
<s:NumericStepper visible="false" id="numStepper" width="55" 
change="sizeChangeFunc()" snapInterval="2" x="313" y="39" minimum="10" maximum="500" value="100" stepSize="10"/>
<s:NumericStepper visible="false" id="numStepper0" width="55" 
change="sizeChangeFunc2()" snapInterval="5" x="423" y="39" minimum="10" maximum="200" value="10" stepSize="5"/>
<s:TextInput id="txt" x="10" y="10" width="468"/>
<s:TextInput id="box" x="10" y="36"/>
<s:Button click="add_clickHandler(event)" id="add" x="210" y="40" label="+" width="31"/>
<s:Button click="remove_clickHandler(event)" id="remove" x="249" y="40" label="-" width="26"/>
<s:Label x="146" y="49" text="添加屏遮物"/>
</s:Application>
 

分享到:
评论

相关推荐

    5-1+_子集和问题_

    子集和问题的一个实例为?St?〈St〉。其中,S={x1,x2,…,xn}S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在 S 的一个子集 S1,使得 ∑x∈S1x=c ∑x∈S1x=c。试设计一个解子集和...

    子集和问题子集和问题的一个实例为〈S,t〉。其中,S={x1,x2,...,xn}是一个正整数的集合,c

    子集和问题 Description 子集和问题的一个实例为〈S,t〉。其中,S={x1,x2,...,xn}是一个正整数的集合,c 是一个正整数。子集和问题判定是否存在S的一个子集S1,使得x∈S1,∑x=c. 试设计一个解子集和问题的回溯法...

    求集合的所有子集问题

    试写一个递归算法实现求一个集合的所有子集。 算法设计: 给定一个非空的集合,用递归算法输出它的所有子集。 数据输入: 由文件input.txt 提供输入数据。文件第1行是集合中的元素个数,第2行是集合的元素序列(元素...

    子集和问题

    问题描述: 子集和问题的一个实例为〈S,t〉。其中,S={ 1 x , 2 x ,…, n x }是一个正整数的集合,c是一... 程序运行结束时,输出子集和问题的解输。当问题无解时,输出“No Solution!”(solution开头是大写)。

    截取字体子集FontShrinker

    截取字体文件的一个子集,使用于ttf格式

    算法设计实现题子集和问题c实现

    子集和问题判定是否存在S 的一个子集S1,使得子集里的元素之和为c 试设计一个解子集和问题的回溯法。 算法设计:对于给定的正整数的集合S={x1,x2,...,xn}和正整数c,计算S的一个子集S1,使得子集里的元素之和为c。 ...

    C语言子集 解释器

    C语言子集的解释器,可自举。把C源码编译成机器码执行。VS2010 C工程。

    多目标优化在特征选择子集评价中的应用

    为综合考虑特征选择中多种子集评价方式间的折中,优化子集性能,提出一种基于子集评价多目标优化的特征选择框架,并重点对多目标粒子群优化(MOPSO)在特征子集评价中的应用进行了研究。该框架分别根据子集的稀疏度...

    算法设计与分析-子集和问题

    子集和问题的一个实例为〈S,c〉。其中,S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得 ∑x=c, (其中x∈S1)。试设计一个解子集和问题的方法。你可以假设处理范围...

    C/C++语言编程安全子集

    C/C++语言编程安全子集

    C语言子集词法分析

    C语言子集词法分析上交报告

    ImageNet是个非常庞大的数据集,该资源为ImageNet的子集,包含2200多张大象的自然图像

    ImageNet是个非常庞大的数据集,该资源为ImageNet的子集,包含2200多张大象的自然图像

    回溯法求解子集和问题

    用回溯法实现子集和问题的完整代码

    论文研究-基于IGA的支持向量机特征子集选择和参数优化.pdf

    特征子集选择和训练参数的优化一直是SVM研究中的两个重要方面,选择合适的特征和合理的训练参数可以提高SVM分类器的性能,以往的研究是将两个问题分别进行解决。随着遗传优化等自然计算技术在人工智能领域的应用,...

    子集打印问题~新奇算法

    很多人在算法分析中说打印子集很难 我当初用c编写的一个程序,是利用文件的打开,复制存取中间子集来实现了打印所有的子集

    c++子集和程序

    完整的VC++子集和程序,用回溯法实现的,可以运行。在算法分析与设计上的一个实验。

    SQL用于查询子集集合

    得知根节点的ID查询出此节点下所有的子集,并可以转成json格式

    C语言子集编译器前端(C++)

    实现了一个C语言简单子集的编译器点段部分 可以将文法定义的合法的源代码转化为四元式 实现了词法分析、语法分析、语义分析部分 进行文件的输入输出,从文件读取文法、源代码、将四元式输出到文件

Global site tag (gtag.js) - Google Analytics