PIXI.ParticleContainer로 많은 양의 스프라이트를 고성능으로 처리해보자
PIXI.ParticleContainer에 담으면 많은 수의 스프라이트를 좀더 가볍게 처리할 수 있다
단점은 제한된 기능만 사용할 수 있다
그렇다해도 화면표현에 대해서는 꽤 많은것을 할 수 있으니 큰 제약이 되지 않는다
bGV0IGdldF9hbmdsZV9pbl9yYWRpYW5fYmV0d2Vlbl90d29fcG9pbnRzID0gZnVuY3Rpb24gKHBvaW50MSwgcG9pbnQyKSB7CiAgIHJldHVybiBNYXRoLmF0YW4yKHBvaW50Mi55IC0gcG9pbnQxLnksIHBvaW50Mi54IC0gcG9pbnQxLngpOwp9OwpsZXQgZ2V0X2Rpc3RhbmNlX2JldHdlZW5fdHdvX3BvaW50ID0gZnVuY3Rpb24gKHBvaW50MSwgcG9pbnQyKSB7CiAgIHZhciBhID0gcG9pbnQxLnggLSBwb2ludDIueDsKICAgdmFyIGIgPSBwb2ludDEueSAtIHBvaW50Mi55OwogICByZXR1cm4gTWF0aC5zcXJ0KGEgKiBhICsgYiAqIGIpOwp9CmZ1bmN0aW9uIGdldF9wb2ludF9ieV9yYWRpYW4oeCwgeSwgbGVuZ3RoLCBhbmdsZSkgewogICByZXR1cm4gWwogICAgICB4ICsgTWF0aC5jb3MoYW5nbGUpICogbGVuZ3RoLAogICAgICB5ICsgTWF0aC5zaW4oYW5nbGUpICogbGVuZ3RoCiAgIF07Cn0KCndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24gKCkgewogICAoZnVuY3Rpb24gKCkgeyB2YXIgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7IHNjcmlwdC5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7IHZhciBzdGF0cyA9IG5ldyBTdGF0cygpOyBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHN0YXRzLmRvbSk7IHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbiBsb29wKCkgeyBzdGF0cy51cGRhdGUoKTsgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGxvb3ApIH0pOyB9OyBzY3JpcHQuc3JjID0gJy8vbXJkb29iLmdpdGh1Yi5pby9zdGF0cy5qcy9idWlsZC9zdGF0cy5taW4uanMnOyBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7IH0pKCk7CgoKICAgZnVuY3Rpb24gbWFrZVBpeGkobW9kZSkgewogICAgICBsZXQgcGFyZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2NvbnRhaW5lcl93aW50ZXInKTsKICAgICAgLy8gcGFyZW50LmlubmVySFRNTCA9ICcnOwogICAgICBsZXQgcGFyZW50U2l6ZSA9IHBhcmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgICAgbGV0IHdpZHRoID0gcGFyZW50U2l6ZS53aWR0aCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvOwogICAgICBsZXQgaGVpZ2h0ID0gcGFyZW50U2l6ZS53aWR0aCAvIHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvOwogICAgICBsZXQgYXBwID0gbmV3IFBJWEkuQXBwbGljYXRpb24oewogICAgICAgICB3aWR0aCwKICAgICAgICAgaGVpZ2h0LAogICAgICAgICBhbnRpYWxpYXM6IHRydWUsCiAgICAgICAgIHRyYW5zcGFyZW50OiB0cnVlLAogICAgICAgICByZXNvbHV0aW9uOiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbywKICAgICAgfSk7CgogICAgICBhcHAudmlldy5zZXRBdHRyaWJ1dGUoJ2lkJywgJ3NjcmVlbicpOwogICAgICBwYXJlbnQuYXBwZW5kQ2hpbGQoYXBwLnZpZXcpOwoKICAgICAgY29uc3Qgc2VnID0gMTAwMDA7CiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IG5ldyBQSVhJLlBhcnRpY2xlQ29udGFpbmVyKHNlZywgeyBhbHBoYTogdHJ1ZSwgcm90YXRpb246IHRydWUgfSk7CiAgICAgIGFwcC5zdGFnZS5hZGRDaGlsZChjb250YWluZXIpOwoKICAgICAgY2xhc3MgUmVjdGFuZ2xlIGV4dGVuZHMgUElYSS5TcHJpdGUgewogICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgICAgLy9QSVhJLlRleHR1cmUuV0hJVEUKICAgICAgICAgICAgY29uc3QgdGV4dHVyZSA9IFBJWEkuVGV4dHVyZS5mcm9tKCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUFFQUFBQUJDQVFBQUFDMUhBd0NBQUFBQzBsRVFWUjQybVA4L3g4QUF3TUNBTytpcDFzQUFBQUFTVVZPUks1Q1lJST0nKTsKICAgICAgICAgICAgc3VwZXIodGV4dHVyZSk7CiAgICAgICAgIH0KICAgICAgfQogICAgICBjbGFzcyBMaW5lIGV4dGVuZHMgUmVjdGFuZ2xlIHsKICAgICAgICAgc3BlYyA9IHt9CiAgICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgICBzdXBlcigpOwogICAgICAgICAgICB0aGlzLmFuY2hvci55ID0gMC41OwogICAgICAgICAgICB0aGlzLmF4aXMgPSAwLjU7CiAgICAgICAgICAgIHRoaXMudGhpY2tuZXNzID0gMTsKICAgICAgICAgfQogICAgICAgICBzZXQgdGhpY2tuZXNzKHYpIHsgdGhpcy5oZWlnaHQgPSB2OyB9CiAgICAgICAgIGdldCB0aGlja25lc3MoKSB7IHJldHVybiB0aGlzLmhlaWdodDsgfQogICAgICAgICBzZXQgYXhpcyh2KSB7IHRoaXMuYW5jaG9yLnggPSB2OyB9CiAgICAgICAgIGdldCBheGlzKCkgeyByZXR1cm4gdGhpcy5hbmNob3IueDsgfQogICAgICAgICBzZXQgYXgodikgeyB0aGlzLnNwZWMuYXggPSB2OyB0aGlzLmNhbGNwb3MoKTsgfQogICAgICAgICBnZXQgYXgoKSB7IHJldHVybiB0aGlzLnNwZWMuYXggPz8gMDsgfQogICAgICAgICBzZXQgYXkodikgeyB0aGlzLnNwZWMuYXkgPSB2OyB0aGlzLmNhbGNwb3MoKTsgfQogICAgICAgICBnZXQgYXkoKSB7IHJldHVybiB0aGlzLnNwZWMuYXkgPz8gMDsgfQogICAgICAgICBzZXQgYngodikgeyB0aGlzLnNwZWMuYnggPSB2OyB0aGlzLmNhbGNwb3MoKTsgfQogICAgICAgICBnZXQgYngoKSB7IHJldHVybiB0aGlzLnNwZWMuYnggPz8gMDsgfQogICAgICAgICBzZXQgYnkodikgeyB0aGlzLnNwZWMuYnkgPSB2OyB0aGlzLmNhbGNwb3MoKTsgfQogICAgICAgICBnZXQgYnkoKSB7IHJldHVybiB0aGlzLnNwZWMuYnkgPz8gMDsgfQogICAgICAgICBnZXQgbGVuZ3RoKCkgewogICAgICAgICAgICBsZXQgYSA9IHRoaXMuYXggLSB0aGlzLmJ4OwogICAgICAgICAgICBsZXQgYiA9IHRoaXMuYXkgLSB0aGlzLmJ5OwogICAgICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KGEgKiBhICsgYiAqIGIpOwogICAgICAgICB9CiAgICAgICAgIGNhbGNwb3MoKSB7CiAgICAgICAgICAgIHRoaXMud2lkdGggPSB0aGlzLmxlbmd0aDsKICAgICAgICAgICAgdGhpcy54ID0gdGhpcy5ieCAtICgodGhpcy5ieCAtIHRoaXMuYXgpICogKDEgLSB0aGlzLmFuY2hvci54KSk7CiAgICAgICAgICAgIHRoaXMueSA9IHRoaXMuYnkgLSAoKHRoaXMuYnkgLSB0aGlzLmF5KSAqICgxIC0gdGhpcy5hbmNob3IueCkpOwogICAgICAgICAgICB0aGlzLnJvdGF0aW9uID0gTWF0aC5hdGFuMih0aGlzLmJ5IC0gdGhpcy5heSwgdGhpcy5ieCAtIHRoaXMuYXgpOwogICAgICAgICB9CiAgICAgIH0KICAgICAgY29uc3QgbGlzdCA9IFtdOwogICAgICBjb25zdCBsZW4gPSB3aWR0aCAqIDAuNTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWc7IGkrKykgewogICAgICAgICBsZXQgbG4gPSBuZXcgTGluZSgpOwogICAgICAgICBsbi50aW50ID0gMHgwMDAwMDA7CiAgICAgICAgIGxuLnRoaWNrbmVzcyA9IDAuMDM7CiAgICAgICAgIGxuLmF4ID0gMC41ICogd2lkdGg7CiAgICAgICAgIGxuLmF5ID0gMC41ICogd2lkdGg7CiAgICAgICAgIGxldCBicmFkaWFuID0gKE1hdGguUEkgKiAyIC8gc2VnKSAqIGk7CiAgICAgICAgIGxldCByb3RjbnQgPSAwOwogICAgICAgICBsbi5icG9pbnQgPSAoKSA9PiB7CiAgICAgICAgICAgIGxldCBbeCwgeV0gPSBnZXRfcG9pbnRfYnlfcmFkaWFuKGxuLmF4LCBsbi5heSwgbGVuLCBicmFkaWFuICsgcm90Y250KTsKICAgICAgICAgICAgbG4uYnggPSB4OwogICAgICAgICAgICBsbi5ieSA9IHk7CiAgICAgICAgIH0KICAgICAgICAgbG4uYW5pID0gKCkgPT4gewogICAgICAgICAgICByb3RjbnQgKz0gMC4wMDAwNTsKICAgICAgICAgICAgbG4uYnBvaW50KCk7CiAgICAgICAgIH0KICAgICAgICAgbG4uYnBvaW50KCk7CiAgICAgICAgIGxpc3QucHVzaChsbik7CiAgICAgICAgIChtb2RlID8gY29udGFpbmVyIDogYXBwLnN0YWdlKS5hZGRDaGlsZChsbik7CiAgICAgIH0KICAgICAgbGV0IHVwZGF0ZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgLy8gaWYgKCFhcHAudmlldy5wYXJlbnROb2RlKSByZXR1cm4gZmFsc2U7CiAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykgewogICAgICAgICAgICBsZXQgbG4gPSBsaXN0W2ldOwogICAgICAgICAgICBsbi5hbmkoKTsKICAgICAgICAgfQogICAgICB9OwogICAgICBQSVhJLlRpY2tlci5zaGFyZWQuYWRkKHVwZGF0ZSk7CgogICAgICByZXR1cm4gewogICAgICAgICBkcm9wKCkgewogICAgICAgICAgICBQSVhJLlRpY2tlci5zaGFyZWQucmVtb3ZlKHVwZGF0ZSk7CiAgICAgICAgICAgIC8vIGFwcC5zdGFnZS5kZXN0cm95KHRydWUpOwogICAgICAgICAgICBjb250YWluZXIuY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiAoYykgeyBjb250YWluZXIucmVtb3ZlQ2hpbGQoYykgfSkKICAgICAgICAgICAgYXBwLnN0YWdlLmNoaWxkcmVuLmZvckVhY2goZnVuY3Rpb24gKGMpIHsgYXBwLnN0YWdlLnJlbW92ZUNoaWxkKGMpIH0pCgogICAgICAgICAgICBhcHAuZGVzdHJveSh0cnVlKTsKICAgICAgICAgICAgLy8gYXBwLnN0YWdlID0gbnVsbDsKCiAgICAgICAgICAgIGFwcCA9IG51bGw7CiAgICAgICAgICAgIHdoaWxlIChsaXN0Lmxlbmd0aCkgbGlzdC5zcGxpY2UoMCwgbGlzdC5sZW5ndGgpOwogICAgICAgICB9CiAgICAgIH0KICAgfQogICBsZXQgcGl4aTsKICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2J0bmZhc3QnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGUgPT4gewogICAgICBwaXhpICYmIHBpeGkuZHJvcCgpOwogICAgICBwaXhpID0gbWFrZVBpeGkoIWZhbHNlKTsKICAgfSkKICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2J0bnNsb3cnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGUgPT4gewogICAgICBwaXhpICYmIHBpeGkuZHJvcCgpOwogICAgICBwaXhpID0gbWFrZVBpeGkoIXRydWUpOwogICB9KQogICBidG5mYXN0LmNsaWNrKCk7Cgp9KQ==
let get_angle_in_radian_between_two_points = function (point1, point2) {
return Math.atan2(point2.y - point1.y, point2.x - point1.x);
};
let get_distance_between_two_point = function (point1, point2) {
var a = point1.x - point2.x;
var b = point1.y - point2.y;
return Math.sqrt(a * a + b * b);
}
function get_point_by_radian(x, y, length, angle) {
return [
x + Math.cos(angle) * length,
y + Math.sin(angle) * length
];
}
window.addEventListener('load', function () {
(function () { var script = document.createElement('script'); script.onload = function () { var stats = new Stats(); document.body.appendChild(stats.dom); requestAnimationFrame(function loop() { stats.update(); requestAnimationFrame(loop) }); }; script.src = '//mrdoob.github.io/stats.js/build/stats.min.js'; document.head.appendChild(script); })();
function makePixi(mode) {
let parent = document.querySelector('#container_winter');
// parent.innerHTML = '';
let parentSize = parent.getBoundingClientRect();
let width = parentSize.width / window.devicePixelRatio;
let height = parentSize.width / window.devicePixelRatio;
let app = new PIXI.Application({
width,
height,
antialias: true,
transparent: true,
resolution: window.devicePixelRatio,
});
app.view.setAttribute('id', 'screen');
parent.appendChild(app.view);
const seg = 10000;
const container = new PIXI.ParticleContainer(seg, { alpha: true, rotation: true });
app.stage.addChild(container);
class Rectangle extends PIXI.Sprite {
constructor() {
//PIXI.Texture.WHITE
const texture = PIXI.Texture.from('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=');
super(texture);
}
}
class Line extends Rectangle {
spec = {}
constructor() {
super();
this.anchor.y = 0.5;
this.axis = 0.5;
this.thickness = 1;
}
set thickness(v) { this.height = v; }
get thickness() { return this.height; }
set axis(v) { this.anchor.x = v; }
get axis() { return this.anchor.x; }
set ax(v) { this.spec.ax = v; this.calcpos(); }
get ax() { return this.spec.ax ?? 0; }
set ay(v) { this.spec.ay = v; this.calcpos(); }
get ay() { return this.spec.ay ?? 0; }
set bx(v) { this.spec.bx = v; this.calcpos(); }
get bx() { return this.spec.bx ?? 0; }
set by(v) { this.spec.by = v; this.calcpos(); }
get by() { return this.spec.by ?? 0; }
get length() {
let a = this.ax - this.bx;
let b = this.ay - this.by;
return Math.sqrt(a * a + b * b);
}
calcpos() {
this.width = this.length;
this.x = this.bx - ((this.bx - this.ax) * (1 - this.anchor.x));
this.y = this.by - ((this.by - this.ay) * (1 - this.anchor.x));
this.rotation = Math.atan2(this.by - this.ay, this.bx - this.ax);
}
}
const list = [];
const len = width * 0.5;
for (let i = 0; i < seg; i++) {
let ln = new Line();
ln.tint = 0x000000;
ln.thickness = 0.03;
ln.ax = 0.5 * width;
ln.ay = 0.5 * width;
let bradian = (Math.PI * 2 / seg) * i;
let rotcnt = 0;
ln.bpoint = () => {
let [x, y] = get_point_by_radian(ln.ax, ln.ay, len, bradian + rotcnt);
ln.bx = x;
ln.by = y;
}
ln.ani = () => {
rotcnt += 0.00005;
ln.bpoint();
}
ln.bpoint();
list.push(ln);
(mode ? container : app.stage).addChild(ln);
}
let update = function () {
// if (!app.view.parentNode) return false;
for (let i = 0; i < list.length; i++) {
let ln = list[i];
ln.ani();
}
};
PIXI.Ticker.shared.add(update);
return {
drop() {
PIXI.Ticker.shared.remove(update);
// app.stage.destroy(true);
container.children.forEach(function (c) { container.removeChild(c) })
app.stage.children.forEach(function (c) { app.stage.removeChild(c) })
app.destroy(true);
// app.stage = null;
app = null;
while (list.length) list.splice(0, list.length);
}
}
}
let pixi;
document.querySelector('#btnfast').addEventListener('click', e => {
pixi && pixi.drop();
pixi = makePixi(!false);
})
document.querySelector('#btnslow').addEventListener('click', e => {
pixi && pixi.drop();
pixi = makePixi(!true);
})
btnfast.click();
})