更好的缓存以消除framedrop

时间:2013-03-25 14:39:34

标签: javascript html5 html5-canvas kineticjs

我正在开展一个小型游戏,仅用于练习目的,这是第一次。正如你可以在我的小提琴中看到的那样,当屏幕上出现很多子弹和/或敌人时,它开始陷入困境。有没有办法通过某种方式缓存它来减少这种情况?

我已经阅读了有关预渲染的内容。但由于我使用的是Kinetic库,我不认为这是我能做的。是否有一些提示和技巧可以减少它的框架?或者使用KineticJS进行预渲染的方法?

这是我的小提琴:http://jsfiddle.net/3nEUv/3/

我认为子弹的绘制是一个真正的破坏者:(小提琴中的第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();
    }

}

提前致谢!

2 个答案:

答案 0 :(得分:1)

一些没有真正达到答案水平的想法

我注意到你在一阵5发射子弹。爆发是如此之快,以至于所有5发子弹都以更多/更少的直线向目标前进。我的建议是只对主要子弹进行碰撞测试。如果领先的子弹击中,尾随的子弹最终将击中你的静止目标。

KineticJS形状非常智能,因此处理器非常密集。因此,您可以使用缓存的子弹图像,而不是创建智能项目符号。 Eric Drowell(KineticJS的创造者)表示,使用“哑”图像而不是“智能”形状的性能提升了4倍。您可以缓存5个子弹图像模式(1个子弹,2个子弹,3个子弹,4个子弹,5个子弹)。在射击时,你会遍历1-5子弹图像,直到你获得5发子弹。然后你只需沿着射击线的斜坡移动5-bullet图像。

最后,从屏幕外的缓冲画布上进行blitting会非常有用,但是不可能,因为KineticJS拒绝放弃对它的画布的可写引用。 Eric Drowlell,如果你正在倾听......喜欢你的工作,但如何给我们一个缓冲画布呢!

答案 1 :(得分:1)

我能想到的一些事情会产生影响。


1 / 对象合并

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

这可以通过将你的子弹移动到不再需要它的临时数组来完成。就像当它离开屏幕或击中敌人时。然后,当您需要新的子弹时,从临时阵列中取出该对象并重新初始化子弹。

查看 this link(搜索“回收鱼”标题)


2 / 四叉树碰撞检测

这是一种很好的碰撞优化技术。而不是检查你的子弹是否在每个蜱上与每个敌人相撞,你只检查那些与你的子弹相同的“四边形”的敌人。

这是一个很好的tutorial


3 / 缓冲

使用屏幕外画布。我有一个背景,UI,玩家/敌人/子弹。这有一些变化,但根据我的经验,最有效的是将所有元素绘制到屏幕外层;然后在每个刻度线上,只有当图层发生变化时,才会重新绘制(到屏幕外层)图像。完成后,将每个屏幕外层编译为一个可见层。我在我的手机游戏中成功使用了这项技术,一次在屏幕上有超过90个对象,在iPhone4s上以60fps运行。


编辑:刚刚看到这个有趣的演示,展示了3种不同框架的性能,包括Kinetic。在我的桌面和移动设备上,Kinetic对我的吸引力最大。

interactive demo here