JavaScriptでの壮大な破壊アニメーション(ピクセルダスト)

HTML5 ゲームの開発プロセスでは、各要素に破壊効果を描画するか、JavaScript(キャンバス)でプログラムでこれを実行しようとするというジレンマに直面しました。 最初の方法ですべてが明確である場合(確実に機能しますが、アーティストにとっては多くの作業が必要です)、2番目の方法では、レンダリング速度が60FPS x 64 x 4バイト〜1 MB / sであるため、疑問がありました。 1つの要素で、1つの画面に40個ある場合







したがって、タスクは次のとおりです。HTML5(キャンバス)に基づいてゲームの効果を作成するには、効果はサイズが32x32〜64x64ピクセルの画像を取得し、60FPSの周波数で再生するフレームのシーケンスを生成する必要があります。 プロセッサーを過負荷にしないようにキャッシュできるように思えますが、60FPS x 64幅x 64高さxピクセルあたり4バイトは既にほぼメガバイトであり、これは入力イメージごとに1秒です。 数百の画像にエフェクトを適用する必要があり、1秒より長く続くことを想像してください-十分なメモリが得られません。 リアルタイムの計算が残っており、ここでそれについて説明します。



入力ラスターをサイズが2x2または4x4ピクセルの小さな断片に分割し、各図面で新しい位置を計算して、結果のラスタ​​ーに配置するという考え方です。 色成分とアルファチャネルも、二次の法則に従って時間に依存する必要があります。 私の場合、「ヒープ」の色は0x323232、アルファ値は1.0、ピクセル均等化の方向(左/右)から透明度(アルファ0)になります。



波の効果には2種類の粒子が必要です:いくつかは横に飛び、他は落ち着いて束を形成します。 さらに、各パーティクルには、何らかのランダムな出発速度が必要です。 すべてを完全にランダムに見えるようにするために、両方のランダム変数をパーリンのノイズから取得できます。



判明したように、V8は、フル60FPSでの平均サイズが48x48の画像に対して、これらのエフェクトのうち40個を同時にサポートできるほど高速です。 (それを見て







詳細なコメント付きのエフェクトコード
//       var test = [], test2 = [] for (var i = 0; i < 256; i++) { test.push(0); test2.push(0); } //  - Effect = function () { this.buffer = document.createElement('canvas'); }; // ****       -,    //       (new Effect()) Effect.prototype.ready = function () { return this.progress >= 0.99; } //    // w, h -       // part -     // dir -   , -1 , 0  , 1  //               , //     this.w2 //        Effect.prototype.init0 = function (w, h, part, dir) { this.buffer.width = dir == 0 ? w : 2 * w; this.buffer.height = h; this.dir = 0; this.sx = 0; this.w = w; this.w2 = w; this.h = h; this.dir = dir; if (dir == -1) { this.sx = w; this.w *= 2; } if (dir == 1) { this.w *= 2; } this.wp = w / part; this.hp = h / part; this.part = part; return this.buffer; } //      ,      (x, y) Effect.prototype.init1 = function (x, y) { var context = this.buffer.getContext("2d"); //    var data = context.createImageData(this.w, this.h); //   var orig = context.getImageData(0, 0, this.w2, this.h); //  : 0 -  , 1 -  , 2 -   , 3 -    var parts = []; //     ,    1 var px = [], py = []; //  ,      var vx = [], speed = []; //           var noise = GenerateRandom(this.wp, this.hp); var k = 0; var part = this.part; for (var j = this.hp - 1; j >= 0; j--) { for (var i = 0; i < this.wp; i++) { var x0 = i * part; var y0 = j * part; var c = 0; for (var dx = 0; dx < part; dx++) for (var dy = 0; dy < part; dy++) { var t = (x0 + dx) + (y0 + dy) * this.w2; if (orig.data[t * 4 + 3] != 0) { c++; } } var r = noise[k++] px.push(x0 + this.sx); py.push(y0); //      if (c * 2 >= part * part) { speed.push(1.2 * r + 0.75); if (r > 0.5) { parts.push(3); } else { parts.push(2); } } else { speed.push(0); parts.push(0); } } } //     this.level = []; for (var i = 0; i < this.w; i++) this.level.push(this.h); this.parts = parts; this.vx = vx; this.speed = speed; this.px = px; this.py = py; this.context = context; this.data = data; this.orig = orig; this.progress = 0.0; this.x = x; this.y = y; return this; } //     img,    Effect.prototype.init01 = function (x, y, w, h, part, dir, img, imgX, imgY, imgW, imgH) { this.init0(w, h, part, dir); var context = this.buffer.getContext("2d"); context.drawImage(img, imgX, imgY, imgW, imgH, 0, 0, w, h); this.init1(x, y); return this; } //               Effect.prototype.draw = function (context, x, y, w, h) { if (w === undefined) { w = this.w2; h = this.h; } if (this.dir == -1) { x -= w; w *= 2; } if (this.dir == 1) { w *= 2; } context.drawImage(this.buffer, x, y, w, h); } //    , progress -       , this.progress  0.0  1.0 Effect.prototype.update = function (progress) { this.progress += progress; var c = 100; var data = this.data.data; var orig = this.orig.data; var wp = this.wp; var hp = this.hp; var part = this.part; var h = this.h; var w = this.w; var k = 0; var w2 = this.w2; // test -   , test2 -    var p = this.progress; var p2 = Math.min(p * p, 1.0); for (var i = 0; i < 256; i++) { var j = i + (50 - i) * p2 | 0; if (j > 255) j = 255; if (j < 0) j = 0; test[i] = j; j = i + (255 - i) * p2 | 0; if (p2 > 0.7) j = 255 * (1.0 - p2) / 0.3 | 0 test2[i] = j; } //    for (var i = 3; i < w * h * 4; i += 4) data[i] = 0; for (var j = hp - 1; j >= 0; j--) for (var i = 0; i < wp; i++, k++) if (this.parts[k] != 0) { //   //   ,        var p = this.progress * this.speed[k]; //      var x0 = i * part; var y0 = j * part; var x = this.px[k], y = this.py[k]; var a = 1.0; //   0.2      if (p > 0.2) { p = (p - 0.2) / 0.8; //   x,          0.1, //          var px = p * this.dir + this.progress * (this.speed[k] * 10 % 0.1); if (this.parts[k] == 2) { //     x = x0 + this.sx + px * w / 2 | 0; y = y0 + p * p * this.h | 0; } else if (this.parts[k] == 3) { //   -,         x = x0 + this.sx + px * w | 0; y = y0 + p * w / 4 | 0; if (this.dir == -1) { a = Math.min(1.0, x / w2); } else if (this.dir == 0) { a = Math.min(1.0, 1.0 - y / h); y = y + p * w / 2 | 0; } else if (this.dir == 1) { a = Math.min(1.0, 2.0 - x / w2); } //   -  if (y + part > h) this.parts[k] = 0; } //    -  if (x < 0 || x + part > w) this.parts[k] = 0; } if (this.parts[k] == 0) continue; var min = 0; //    ,      if (this.parts[k] == 2) { var max = this.level[x] var num = x; //       for (var x1 = x + 1; x1 < x + part; x1++) if (this.level[x1] > max) { num = x1; max = this.level[x1]; } //    if (y + part > max) { y = max - part; x = num; this.level[num]--; this.parts[k] = 1; } } this.px[k] = x; this.py[k] = y; //         ,            if (this.parts[k] == 3 && p > 0.2) { for (var dy = 0; dy < part; dy++) for (var dx = 0; dx < part; dx++) { var s = (x + dx) + (y + dy) * w; var t = (x0 + dx) + (y0 + dy) * w2; s *= 4; t *= 4; data[s] = test[orig[t]]; data[s + 1] = test[orig[t + 1]]; data[s + 2] = test[orig[t + 2]]; data[s + 3] = a * orig[t + 3] | 0; } } else { //      for (var dy = 0; dy < part; dy++) for (var dx = 0; dx < part; dx++) { var s = (x + dx) + (y + dy) * w; var t = (x0 + dx) + (y0 + dy) * w2; s *= 4; t *= 4; data[s] = test[orig[t]]; data[s + 1] = test[orig[t + 1]]; data[s + 2] = test[orig[t + 2]]; data[s + 3] = test2[orig[t + 3]]; } } } //       this.context.putImageData(this.data, 0, 0); }
      
      







コメント付きのソースはここからダウンロードできます



All Articles