我想使用KineticJS將許多對象動畫到畫布上。我在每一幀都使用內置的移動方法。衆所周知,重繪圖層是一項昂貴的操作,可能會導致性能問題,所以我只在每個移動操作已經執行之後才調用layer.draw()。儘管如此,我生成的對象越多,表現越差,最終的結果就是動畫遲緩。KineticJS能夠使用移動方法執行許多對象的平滑動畫嗎?
爲了比較KineticJS性能與本地畫布,我準備了兩個相同的演示 - 在500x500的畫布中彈跳球。第一個是使用本地畫布。它只是清除每個框架上的畫布並畫出球。第二個使用KineticJS,創建圖像對象後,它使用移動方法移動它們。
很明顯,雖然本機演示與10,100和1000個球執行相同,但KineticJS演示的性能受球的數量影響很大。 1000,它只是無法使用。對這兩個示例都有很多優化,包括對動畫循環使用requestAnimationFrame或對KineticJS使用內置的Animation對象,但這些不會改變演示的性能。
所以這裏是兩個演示。首先,原生一個 - http://jsfiddle.net/uxsLN/1/
(function() {
window.addEventListener('load', loaded, false);
function loaded() {
img = new Image();
img.onload = canvasApp;
img.src = 'ball.png';
}
function canvasApp() {
var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");
function drawScreen() {
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = '#000000';
context.strokeRect(1, 1, theCanvas.width - 2, theCanvas.height - 2);
context.fillStyle = "#000000";
var ball;
for (var i = 0; i < balls.length; i++) {
ball = balls[i];
ball.x += ball.xunits;
ball.y += ball.yunits;
context.drawImage(img, ball.x, ball.y);
if (ball.x + ball.radius * 2 > theCanvas.width || ball.x < 0) {
ball.angle = 180 - ball.angle;
updateBall(ball);
} else if (ball.y + ball.radius * 2 > theCanvas.height || ball.y < 0) {
ball.angle = 360 - ball.angle;
updateBall(ball);
}
}
}
function updateBall(ball) {
ball.radians = ball.angle * Math.PI/180;
ball.xunits = Math.cos(ball.radians) * ball.speed;
ball.yunits = Math.sin(ball.radians) * ball.speed;
}
var numBalls = 1000;
var maxSize = 8;
var minSize = 5;
var maxSpeed = maxSize + 5;
var balls = [];
var radius = 24;
for (var i = 0; i < numBalls; i++) {
var speed = maxSpeed - radius;
var angle = Math.floor(Math.random() * 360);
var radians = angle * Math.PI/180;
var ball = {
x : (theCanvas.width - radius)/2,
y : (theCanvas.height - radius)/2,
radius : radius,
speed : speed,
angle : angle,
xunits : Math.cos(radians) * speed,
yunits : Math.sin(radians) * speed
}
balls.push(ball);
}
function gameLoop() {
window.setTimeout(gameLoop, 20);
drawScreen()
}
gameLoop();
}
})();
接下來,KineticJS - http://jsfiddle.net/MNpUX/
(function() {
window.addEventListener('load', loaded, false);
function loaded() {
img = new Image();
img.onload = canvasApp;
img.src = 'ball.png';
}
function canvasApp() {
var stage = new Kinetic.Stage({
container : 'container',
width : 500,
height : 500
});
var layer = new Kinetic.Layer();
stage.add(layer);
rect = new Kinetic.Rect({
x : 0,
y : 0,
width : stage.getWidth(),
height : stage.getHeight(),
fill : '#EEEEEE',
stroke : 'black'
});
layer.add(rect);
function drawScreen() {
var ball;
for (var i = 0; i < balls.length; i++) {
ball = balls[i];
ball.obj.move(ball.xunits, ball.yunits);
if (ball.obj.getX() + ball.radius * 2 > stage.getWidth() || ball.obj.getX() < 0) {
ball.angle = 180 - ball.angle;
updateBall(ball);
} else if (ball.obj.getY() + ball.radius * 2 > stage.getHeight() || ball.obj.getY() < 0) {
ball.angle = 360 - ball.angle;
updateBall(ball);
}
}
layer.draw();
}
function updateBall(ball) {
ball.radians = ball.angle * Math.PI/180;
ball.xunits = Math.cos(ball.radians) * ball.speed;
ball.yunits = Math.sin(ball.radians) * ball.speed;
}
var numBalls = 1000;
var maxSize = 8;
var minSize = 5;
var maxSpeed = maxSize + 5;
var balls = [];
var radius = 24;
for (var i = 0; i < numBalls; i++) {
var speed = maxSpeed - radius;
var angle = Math.floor(Math.random() * 360);
var radians = angle * Math.PI/180;
var obj = new Kinetic.Image({
image : img,
x : (stage.getWidth() - radius)/2,
y : (stage.getHeight() - radius)/2
});
layer.add(obj);
var ball = {
radius : radius,
speed : speed,
angle : angle,
xunits : Math.cos(radians) * speed,
yunits : Math.sin(radians) * speed,
obj : obj
};
balls.push(ball);
}
function gameLoop() {
window.setTimeout(gameLoop, 20);
drawScreen()
}
gameLoop();
}
})();
所以,問題是 - 我懷念一些事情KineticJS或者它只是沒有內置這樣的目的是什麼?
所以你建議,以避免移動方法,並使用天然情況下這樣的目的呢?這可以真正解決性能問題,但同時你會失去大部分的KineticJS功能和抽象。考慮到彈跳球的例子,你不再能夠與每個球互動,就好像它們是「真實」的對象一樣。 –
您的設計要求決定了您應用的解決方案。請記住,由於每個球是一個獨立的對象,您仍然可以與它們交互(命中測試,調整屬性等)。最後,您需要權衡一下:本地畫布速度與Kinetic輕鬆對象管理。祝你的項目好運! – markE
+1。我還想指出,KineticJS將支持一種新的高性能模式,不包括節點嵌套,轉換,事件處理,事件觸發等。對於使用簡單用戶的人來說,這將是理想的,並且將會完成接近原生渲染速度。這將作爲v5.1.0發佈 –