2016-10-01 123 views
0

所以我用canvas和javascript(一些jQuery)製作了一個簡單的粒子系統,但我似乎無法讓它在我的舊電腦上運行速度超過8fps,這是代碼:如何使用粒子對象優化畫布粒子系統

var starList = []; 

function Star(){ 
    this.x = getRandomInt(0, canvas.width); 
    this.y = getRandomInt(0, canvas.height); 
    this.vx = getRandomInt(2,5); 
    this.size = this.vx/5; 
    this.opacity = getRandomInt(0, 5000)/10000; 
    this.color = getRandomFromArray(["239, 207, 174", "162, 184, 229", "255, 255, 255"]); 
    this.draw = function(){ 
     ctx.fillStyle = "rgba("+this.color+","+this.opacity+")"; 
     ctx.beginPath(); 
     ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, true); 
     ctx.closePath(); 
     ctx.fill(); 
    }, 
    this.move = function(){ 
     this.x = this.x - this.vx; 

     if(this.x < 0) { 
      this.x = canvas.width; 
      this.opacity = getRandomInt(0, 5000)/10000; 
      this.color = getRandomFromArray(["239, 207, 174", "162, 184, 229", "255, 255, 255"]); 
      this.y = getRandomInt(0, canvas.height); 
      this.size = this.vx/5; 
      this.vx = getRandomInt(2,5); 
     } 
    } 
} 

var canvas, ctx; 

function setCanvas(){ 
    canvas = $('canvas')[0]; 
    ctx = canvas.getContext("2d"); 

    canvas.width = $(window).width()/5; 
    canvas.height = $(window).height()/5; 
} 

setCanvas(); 

function generateStars(){ 
    for(var i = 0; i < 5000; i++){ 
     var star = new Star(); 
     starList.push(star); 
    } 

    for(var i = 0; i < starList.length; i++) { 
     star = starList[i]; 
     star.draw(); 
    } 
} 

generateStars(); 

function loop() { 
    window.requestAnimationFrame(loop); 

    //clear canvas 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 

    //draw and move stars 
    for(var i = 0; i < starList.length; i++) { 
     star = starList[i]; 
     star.draw(); 
     star.move(); 
    } 
} 

我假定使用對象的粒子(星)和通過物的5000索引陣列循環,並執行這兩個函數是硬的處理器/ GPU但如何可以優化此代碼?

我見過其他人避免在構造函數上使用函數,並在它們遍歷數組時循環移動和繪製粒子。這會使它更快嗎?

編輯:忽略getRandomInt和類似的功能,他們是我用來生成隨機東西的簡單功能。

+1

除了它是一個不完整的列表和想法不能被測試,只是轉發給你 - 看起來顯而易見的一點似乎是繪製函數。 5000弧似乎需要一段時間才能畫出。我會嘗試繪製5000個矩形。如果速度快得多,可能仍然值得使用合成材料繪製圓形透明png來爲其着色。計算弧的輪廓將會很慢,我想可能不是硬件加速。另一方面,圖像混合/縮放/着色可以。以下是時間安排:https://developer.mozilla.org/en-US/docs/Web/API/Performance/now – enhzflep

回答

2

你的代碼的最慢的部分是路徑繪製命令:

ctx.fillStyle = "rgba("+this.color+","+this.opacity+")"; 
ctx.beginPath(); 
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, true); 
ctx.closePath(); 
ctx.fill(); 

帆布很快吸引,但5000張圖紙需要一定的時間。

,而不是...

創建包含要顯示的全明星變化的spritesheet。

複製像素從spritesheet到顯示畫布比執行繪圖命令更快。繪製圓弧的地方尤其如此,因爲在圓周上必須計算許多點。

重要!

限制星形變化 - 觀衆不會注意到你的星星不是無限隨機的。

然後使用drawimage剪輯版本迅速從spritesheet繪製每個所需明星精靈:

// set the global alpha 
ctx.globalAlpha = getRandomInt(0, 5000)/10000; 

// cut the desired star-sprite from the spritesheet 
// and draw it on the visible canvas 
ctx.drawImage(spritesheet,        // take from the spritesheet 
    this.sheetX, this.sheetY, this.width, this.height, // at this sprite's x,y 
    this.x, this.y, this.width, this.height)   // and draw sprite to canvas 

的spritesheet

您可以使用第二個內存帆布作爲你的spritesheet並在您的應用首次啓動時在客戶端創建您的明星精靈。 drawImage命令將接受您的第二個內存畫布作爲圖像源(!)。

var spritesheet=document.createElement('canvas'); 
var spriteContext=spriteSheet.getContext('2d'); 
... 
// draw every variation of your stars on the spritesheet canvas 
...