06-用对象池管理对象实例
9.1.4 用对象池管理对象实例
读者已经学习了与声音相关的对象池,但是未曾将这个概念应用到游戏对象。由于对象池这种技术的设计初衷是为了节省处理时间,因此它非常适合于街机游戏,例如本章正在创建的游戏。有时,创建对象实例是一项比较耗费处理器的任务,使用对象池管理对象实例,可以避免在游戏运行期间执行类似的任务。特别是创建爆炸碎片时,会在1帧中创建多个对象。在一个处理能力比较弱的平台上(例如手持设备),对象池技术可以提高帧率。
1.在Geo Blaster扩展版中使用对象池
在本章的游戏中,将把对象池的概念应用到爆炸碎片上。当然,也可以把这个概念应用到陨石、导弹、飞碟以及其他需要多次创建的对象上。但本例仅关注爆炸碎片。读者将会看到,在JavaScript中添加对象池是一个相对简单但却非常强大的技术。
2.在游戏中添加对象池变量
为了创建爆炸碎片的对象池,需要在有的应用程序作用域范围内添加以下4个变量。
var particlePool = [];
var maxParticles = 200;
var newParticle;
var tempParticle;
particlePool数组用于保存碎片对象实例的列表,在后面将用到这些对象。当createExplode()函数需要使用碎片时,程序将首先检查数组中是否有可用对象。如果有可用对象,函数将从particlePool栈中的顶端“弹出”该对象,并将它赋值给应用程序作用域的变量newParticle。该变量将引用一个池中的对象。createExplode()函数会设置newParticle对象的属性,然后将其放入已经存在的particles数组的底部。
一旦碎片的生命耗尽,updateParticles()函数会将该碎片从particles数组中剥离,然后放入particlePool数组的底部。创建一个名为tempParticle的变量,在updateParticles()函数中将使用该变量在每一帧中引用新创建的对象实例。
在一个名为createObjectPools()的新函数中使用maxParticles变量的值。在创建声音和图片表的加载事件之前,应先在gameStateInit()函数中调用此函数。
下面所示为createObjectPools()函数。
function createObjectPools(){
for (var ctr=0;ctr<maxParticles;ctr++){
var newParticle = {};
particlePool.push(newParticle)
}
console.log("particlePool=" + particlePool.length)
}
该函数从0循环到maxParticles的值减1,然后在对象中每个元素中放置一个通用对象。当需要一个碎片时,createExplode()函数将检查particlePool.length是否大于0。如果找到一个可用碎片,就会在设置碎片属性后将该碎片添加到particles数组中。如果没有可用碎片,则不会使用任何对象。
提示
用户可以对这个功能进行扩展。例如,当没有可用对象时,为其添加一个碎片。虽然本例没有添加该功能,但这却是一个常见的对象池算法。
以下是修改之后的createExplode()函数的全部代码。
function createExplode(x,y,num,type){
playSound(SOUND_EXPLODE,.5);
for (var partCtr=0;partCtr<num;partCtr++){
if (particlePool.length > 0){
newParticle = particlePool.pop();
newParticle.dx = Math.random()*3;
if (Math.random()<.5){
newParticle.dx* = -1;
}
newParticle.dy = Math.random()*3;
if (Math.random()<.5){
newParticle.dy* = -1;
}
newParticle.life = Math.floor(Math.random()*30+30);
newParticle.lifeCtr = 0;
newParticle.x = x;
newParticle.width = 2;
newParticle.height = 2;
newParticle.y = y;
newParticle.type = type;
//ConsoleLog.log("newParticle.life=" + newParticle.life);
particles.push(newParticle);
}
}
}
updateParticles()函数将遍历particles数组中的实例,更新每个实例的属性,然后检查每个碎片的生命是否已经耗尽。如果是,函数将把该碎片放回到对象池中。为了将碎片重新放入池中,将以下代码添加到updateParticles()函数中。
if (remove){
particlePool.push(tempParticle)
particles.splice(particleCtr,1)
}