更好的缓存以消除帧率下降。

3
我正在制作一款小游戏,仅用于练习目的,这是我第一次做。正如您在我的fiddle中所看到的,当屏幕上有很多子弹和/或敌人时,它开始出现帧率下降。有没有办法通过某种方式进行缓存来减少这种情况?
我已经阅读了一些关于预渲染的内容。但由于我使用的是Kinetic库,我不认为这是我能做的事情。有没有一些技巧可以减少帧率下降?或者使用KineticJS进行预渲染的方法?
这是我的fiddle链接:http://jsfiddle.net/3nEUv/3/ 我认为子弹的绘制是一个真正的瓶颈:(在fiddle的713行)
function Enemybullet(destinationX, destinationY, enemySprite) {
    this.id = 'enemyBullet';
    this.x = enemySprite.getX()+(enemySprite.getWidth()/2);
    this.y = enemySprite.getY()+(enemySprite.getHeight()/2);

    this.damage = enemy.damage;

    //The targetX and Y are compensated by the player width and height. Subtract or add the halve of the player accordingly
    if (this.x > player.sprite.x) {
        var targetX = (destinationX - this.x)-(player.sprite.getWidth()/2);
        targetY = (destinationY - this.y)-(player.sprite.getHeight()/2);
    } else {
        var targetX = (destinationX - this.x)+(player.sprite.getWidth()/2);
        targetY = (destinationY - this.y)+(player.sprite.getHeight()/2);
    }


    var distance = Math.sqrt(targetX * targetX + targetY * targetY);

    this.velX = (targetX / distance) * enemyAttackSpeed;
    this.velY = (targetY / distance) * enemyAttackSpeed;

    this.finished = false;

    this.sprite = new Kinetic.Circle({
        x: this.x,
        y: this.y, 
        radius: 2,
        fill: 'black',
        name: 'enemyProjectile'
    });

    this.draw = function(indexEnemy, indexBullet) {

        var mayDelete = false;

        this.x += this.velX;
        this.y += this.velY;

        this.sprite.setAbsolutePosition(this.x, this.y);
        //console.log(this.sprite.getX());


        if(collisionDetection(this, player) == true) {
            player.collide(this);
            mayDelete = true;
        }

        if (bulletLeftField(this.sprite) == true) {
            mayDelete = true;
        }

        if (mayDelete == true) {
            delete this;
            this.sprite.remove();
            //console.log(enemies[indexEnemy].bullets);
            if (enemies[indexEnemy]) {
                enemies[indexEnemy].bullets.splice(indexBullet, 1);
            }
        }

        ammoLayer.draw();
    }

}

提前感谢!


好的,你可以创建一个小图像,并将其复制重用作为你的“预渲染”对象。 - SoluableNonagon
另外,我认为减速是由于碰撞检测和每个物品层的不断重绘造成的。 - SoluableNonagon
2个回答

1
一些不太能成为答案的想法

我注意到你会一次发射5颗子弹。这个连发速度非常快,以至于5颗子弹会朝着目标直线飞行。我的建议是只检测前面的子弹是否碰撞。如果第一颗子弹击中了,那么后面的子弹最终也会击中你的静态目标。

KineticJS形状非常智能,因此非常消耗处理器。所以你可以使用缓存子弹图像,而不是创建智能子弹。KineticJS的创始人Eric Drowell表示,“愚蠢”的图像比“聪明”的形状性能提高了4倍。您可以缓存5种子弹图像模式(1颗子弹、2颗子弹、3颗子弹、4颗子弹、5颗子弹)。在发射时,您可以遍历1-5颗子弹图像,直到到达5颗子弹。然后,您只需沿着发射线移动5颗子弹图像。

最后,从离屏缓冲画布中复制绘图(blitting)将非常有用,但不可能实现,因为KineticJS拒绝放弃对其画布的可写引用。Eric Drowlell,如果您在听,请注意一下……喜欢您的作品,但能否给我们一个缓冲画布呢!


谢谢回答!就是“哑”对象!还有Jarrod的答案!:D - CaptainCarl

1
我能想到几件事情会有所不同。

1/ 对象池

这是一种回收对象的技术。创建新对象(并通过垃圾回收机制删除旧对象)是浪费的。

这可以通过将不再需要的对象,例如子弹,移动到临时数组中来实现。当它飞出屏幕或击中敌人时,就像将其还原为新的子弹对象。

请查看此链接(搜索标题“回收鱼”)


2/ 四叉树碰撞检测

这是一种很好的碰撞优化技术。不必在每个tick中检查你的子弹是否与每个敌人碰撞,而是只检查那些与你的子弹在同一个“quad”中的敌人。

这里有一个很好的tutorial


3/ 缓冲处理

使用离屏画布。我会为背景、UI、玩家/敌人/子弹等各自创建一个离屏图层。有一些不同的变化,但从我的经验来看,最有效的方法是将所有元素绘制到离屏图层上; 然后每个时刻只重新绘制(到离屏图层)如果该图层已更改的图像。完成之后,您可以将每个离屏图层编译到一个可见图层中。我已经在我的移动游戏中成功使用了这种技术,在iPhone4s上以60fps运行时,屏幕上同时显示超过90个物体。


编辑:刚刚看到了这个有趣的演示,展示了包括Kinetic在内的3种不同框架的性能。对我来说,Kinetic在我的台式机和移动设备上都表现最差。

交互演示在这里


感谢您提供的精彩答案。不过,creativeJS链接已经失效了。无论如何,我会继续查看其余内容! - CaptainCarl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接