Reputation: 3489
I'm working on a small game, just for practicing purposes, for the first time. And as you can see in my fiddle that it starts to framedrop after a while when a lot of bullets and/or enemies are on the screen. Is there a way to reduce this by caching it somehow?
I've read something about pre-rendering. But since i'm using the Kinetic library i don't think this is something i can do. Are there some tips&tricks to reduce it's framedrop? Or a way to pre-render using KineticJS?
Here's my fiddle: http://jsfiddle.net/3nEUv/3/
I think the drawing of the bullets is a real dealbreaker: (line 713 in fiddle)
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();
}
}
Thanks in advance!
Upvotes: 3
Views: 211
Reputation: 9465
A couple of things I can think of that would make a difference.
1/ Object pooling
This is the technique of recycling your objects. Creating new ones (and removing old ones through garbage collection) is wasteful.
This is done by moving, say, your bullet to a temporary array when you no longer need it. Like when it's gone off the screen or hit an enemy. Then, when you need a new bullet, you take the object from your temporary array and re-initialise the bullet.
Check out this link (search for the heading "Recycling the fish")
2/ Quad-tree collision detection
This is a good collision optimisation technique. Instead of checking if your bullet has collided with every enemy on every tick, you only check those enemies that are in the same "quad" as your bullet.
Here is a good tutorial.
3/ Buffering
Use offscreen canvases. I'd have one for the background, UI, player/enemy/bullets. There are a few variations on this but from my experience, the most efficient is drawing all the elements to offscreen layers; then with each tick, you only redraw (to the offscreen layer) the image if that layer has changed. Once you've done that you compile each of the offscreen layers to one visible layer. I've successfully used this technique in my mobile game which has over 90 objects on the screen at one time, running at 60fps on an iPhone4s.
EDIT: just saw this interesting demo showing the performance of 3 different frameworks, including Kinetic. Kinetic sucked the most for me on both my desktop and mobile.
Upvotes: 1
Reputation: 105035
A few thoughts that don’t really rise to the level of an answer
I noticed you fire bullets in a burst of 5. The burst is so rapid that all 5 bullets travel in more/less a straight line toward their target. My suggestion is to collision-test only the leading bullet. If the leading bullet hits, the trailing bullets will eventually hit your stationary target.
KineticJS shapes are very smart, and therefore very processor intensive. So instead of creating smart bullets, you could use cached bullet images. Eric Drowell (KineticJS creator) says there’s a 4x performance boost to using “dumb” images over “smart” shapes. You could cache 5 bullet image patterns (1-bullet,2-bullets,3-bullets,4-bullets,5-bullets). On firing, you iterate through the 1-5 bullet images until you get to 5-bullets. Then you just move the 5-bullet image along the slope of the firing line.
And finally, blitting from an off-screen buffer canvas would really be helpful, but not possible because KineticJS refuses to give up writable references to it’s canvases. Eric Drowlell, if you’re listening…love your work, but how about giving us a buffer canvas!
Upvotes: 1