Document
Y2xhc3MgS29rYWNQNUV4dCB7CiAgICN0YXNrcyA9IG5ldyBNYXAoKTsKICAgYWRkKHYpIHsKICAgICAgdGhpcy4jdGFza3Muc2V0KHYpOwogICB9CiAgIHJlbW92ZSh2KSB7CiAgICAgIHRoaXMuI3Rhc2tzLmRlbGV0ZSh2KTsKICAgfQogICBnZXQgaXRlcmF0b3IoKSB7CiAgICAgIHJldHVybiB0aGlzLiN0YXNrcy5rZXlzKCk7CiAgIH0KICAgZGVsYXkocykgewogICAgICBpZiAoIXMpIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlKSk7CiAgICAgIGxldCB3YWl0ZXIgPSB7fTsKICAgICAgdGhpcy5hZGQod2FpdGVyKTsKICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICAgICAgIHdhaXRlci51cGRhdGUgPSAoKSA9PiB7CiAgICAgICAgICAgIGlmICgtLXMgPiAwKSByZXR1cm47CiAgICAgICAgICAgIHRoaXMucmVtb3ZlKHdhaXRlcik7CiAgICAgICAgICAgIHJlc29sdmUoKTsKICAgICAgICAgfTsKICAgICAgfSk7CiAgIH0KICAgc3RlcCgpIHsKICAgICAgY29uc3QgeyBpdGVyYXRvciB9ID0gdGhpczsKICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgbGV0IG50ID0gaXRlcmF0b3IubmV4dCgpOwogICAgICAgICBpZiAobnQuZG9uZSkgYnJlYWs7CiAgICAgICAgIGxldCB7IHZhbHVlIH0gPSBudDsKICAgICAgICAgaWYgKHZhbHVlLmNvbnN0cnVjdG9yID09PSBGdW5jdGlvbikgewogICAgICAgICAgICB2YWx1ZSgpOwogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgfQogICAgICAgICB2YWx1ZS51cGRhdGUgJiYgdmFsdWUudXBkYXRlKCk7CiAgICAgICAgIHZhbHVlLnJlZHJhdyAmJiB2YWx1ZS5yZWRyYXcoKTsKICAgICAgfQogICB9CiAgIHRleHQoc3RyaW5nLCB4eCwgeXksIHNpemUsIGZvbnQpIHsKICAgICAgbGV0IGluZm8gPSB0aGlzLnRleHRCb3VuZHMoc3RyaW5nLCB4eCwgeXksIHNpemUsIGZvbnQpOwogICAgICB0ZXh0Rm9udChpbmZvLmZvbnQpOwogICAgICB0ZXh0U2l6ZShpbmZvLnNpemUpOwogICAgICB0ZXh0KGluZm8uc3RyaW5nLCBpbmZvLngsIGluZm8ueSk7CiAgIH0KICAgdGV4dEJvdW5kcyhzdHJpbmcsIHh4LCB5eSwgc2l6ZSwgZm9udCkgewogICAgICBsZXQgbXlGb250ID0gZm9udDsKICAgICAgbGV0IHRleHQxID0gc3RyaW5nOwogICAgICBsZXQgZm9udFNpemVTbWFsbCA9IHNpemU7CiAgICAgIGxldCB4ID0geHg7CiAgICAgIGxldCB5ID0geXk7CiAgICAgIGxldCBib3VuZGluZ19ib3ggPSBteUZvbnQudGV4dEJvdW5kcyh0ZXh0MSwgeCwgeSwgZm9udFNpemVTbWFsbCk7CiAgICAgIHggLT0gYm91bmRpbmdfYm94Lng7CiAgICAgIHkgLT0gYm91bmRpbmdfYm94Lnk7CiAgICAgIHJldHVybiB7CiAgICAgICAgIHg6IHggKyB4eCwKICAgICAgICAgeTogeSArIHl5LAogICAgICAgICBzaXplOiBmb250U2l6ZVNtYWxsLAogICAgICAgICBmb250OiBteUZvbnQsCiAgICAgICAgIHN0cmluZzogc3RyaW5nLAogICAgICAgICByZWN0OiB7CiAgICAgICAgICAgIHg6IHggKyBib3VuZGluZ19ib3gueCwKICAgICAgICAgICAgeTogeSArIGJvdW5kaW5nX2JveC55LAogICAgICAgICAgICB3OiBib3VuZGluZ19ib3gudywKICAgICAgICAgICAgaDogYm91bmRpbmdfYm94LmgsCiAgICAgICAgIH0sCiAgICAgIH07CiAgIH0KfQpmdW5jdGlvbiBkcmF3KCkgewogICBrb2thYy5zdGVwKCk7Cn0KCmNvbnN0IGtva2FjID0gbmV3IEtva2FjUDVFeHQoKTsKYXN5bmMgZnVuY3Rpb24gc2V0dXAoKSB7CiAgIC8vIOuhnOyngeydgCBzZXR1cCDslYjsl5DshJzrp4wg7IaQIOuMgOuptCDrkJjrj4TroZ0g7L2U65Oc66W8IOq1rOyEse2VqAogICBsZXQgc2l6ZVdpZHRoID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiI3N0ZyIpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoOwogICBsZXQgc2l6ZUhlaWdodCA9IHNpemVXaWR0aCAqIDE7CiAgIGNyZWF0ZUNhbnZhcyhzaXplV2lkdGgsIHNpemVIZWlnaHQpOwogICBrb2thYy5hZGQoKGUpID0+IGJhY2tncm91bmQoIiMwMDAwMDA0MCIpKTsKICAgbm9TdHJva2UoKTsKICAgbGV0IHJvdGF0ZSA9IDA7CiAgIGZ1bmN0aW9uIGdlbkxpbmUoKSB7CiAgICAgIHJvdGF0ZSArPSAwLjAwMDE7CiAgICAgIGxldCBhZCA9IHsKICAgICAgICAgbGlmZTogMSwKICAgICAgICAgeDogc2l6ZVdpZHRoIC8gMiwKICAgICAgICAgeTogc2l6ZUhlaWdodCAvIDIsCiAgICAgICAgIGRpcjogUEkgLyAyICsgcm90YXRlLAogICAgICAgICBuZWVkOiB0cnVlLAogICAgICB9OwogICAgICBhZC5zZXREaXIgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgIHRoaXMuZnJvbSA9IHsgeDogdGhpcy54LCB5OiB0aGlzLnkgfTsKICAgICAgICAgbGV0IGdhayA9IDAuMDQ7CiAgICAgICAgIHRoaXMuZGlyICs9IFBJICogZ2FrICogKE1hdGgucmFuZG9tKCkgPCAwLjUgPyAtMSA6IDEpOwogICAgICAgICB0aGlzLmxlbmcgPSAyMDsKICAgICAgICAgdGhpcy5sZW5naW5jID0gMDsKICAgICAgICAgdGhpcy5uZWVkID0gZmFsc2U7CiAgICAgIH07CiAgICAgIGFkLnVwZGF0ZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICAgdGhpcy5saWZlICs9IE1hdGgucmFuZG9tKCkgPiAwLjUgPyAxIDogLTE7CiAgICAgICAgIGlmICgKICAgICAgICAgICAgMCA+PSB0aGlzLmxpZmUgfHwKICAgICAgICAgICAgdGhpcy54IDwgMCB8fAogICAgICAgICAgICB0aGlzLnkgPCAwIHx8CiAgICAgICAgICAgIHRoaXMueCA+IHNpemVXaWR0aCB8fAogICAgICAgICAgICB0aGlzLnkgPiBzaXplSGVpZ2h0CiAgICAgICAgICkgewogICAgICAgICAgICBrb2thYy5yZW1vdmUoYWQpOwogICAgICAgICAgICBnZW5MaW5lKCk7CiAgICAgICAgIH0KICAgICAgICAgaWYgKHRoaXMubmVlZCkgdGhpcy5zZXREaXIoKTsKICAgICAgICAgdGhpcy5sZW5naW5jICs9IDU7CiAgICAgICAgIGlmICh0aGlzLmxlbmdpbmMgPj0gdGhpcy5sZW5nKSB7CiAgICAgICAgICAgIHRoaXMubGVuZ2luYyA9IHRoaXMubGVuZzsKICAgICAgICAgICAgdGhpcy5uZWVkID0gdHJ1ZTsKICAgICAgICAgfQogICAgICAgICBsZXQgeyB4LCB5IH0gPSB0aGlzLmZyb207CiAgICAgICAgIGxldCBwb3MgPSBHZW9tZXRyeS5nZXRQb2ludEJ5UmFkaWFuKHgsIHksIHRoaXMuZGlyLCB0aGlzLmxlbmdpbmMpOwogICAgICAgICB0aGlzLnggPSBwb3NbMF07CiAgICAgICAgIHRoaXMueSA9IHBvc1sxXTsKICAgICAgfTsKICAgICAgYWQucmVkcmF3ID0gZnVuY3Rpb24gKCkgewogICAgICAgICBmaWxsKCIjZmZmZmZmZmYiKTsKICAgICAgICAgY2lyY2xlKHRoaXMueCwgdGhpcy55LCAzKTsKICAgICAgfTsKICAgICAga29rYWMuYWRkKGFkKTsKICAgfQogICBmb3IgKGxldCBpID0gMDsgaSA8IDEwMDA7IGkrKykgewogICAgICBnZW5MaW5lKCk7CiAgIH0KfQoKCmlmIChmYWxzZSkgewogICBsZXQgc2l6ZVdpZHRoID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiI3N0ZyIpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoOwogICBsZXQgc2l6ZUhlaWdodCA9IHNpemVXaWR0aCAqIC41OwogICAvLyBzaXplV2lkdGggPSBpbm5lcldpZHRoOwogICAvLyBzaXplSGVpZ2h0ID0gaW5uZXJIZWlnaHQ7CiAgIGNyZWF0ZUNhbnZhcyhzaXplV2lkdGgsIHNpemVIZWlnaHQpOwp9
class KokacP5Ext { #tasks = new Map(); add(v) { this.#tasks.set(v); } remove(v) { this.#tasks.delete(v); } get iterator() { return this.#tasks.keys(); } delay(s) { if (!s) return new Promise((resolve) => setTimeout(resolve)); let waiter = {}; this.add(waiter); return new Promise((resolve) => { waiter.update = () => { if (--s > 0) return; this.remove(waiter); resolve(); }; }); } step() { const { iterator } = this; while (true) { let nt = iterator.next(); if (nt.done) break; let { value } = nt; if (value.constructor === Function) { value(); continue; } value.update && value.update(); value.redraw && value.redraw(); } } text(string, xx, yy, size, font) { let info = this.textBounds(string, xx, yy, size, font); textFont(info.font); textSize(info.size); text(info.string, info.x, info.y); } textBounds(string, xx, yy, size, font) { let myFont = font; let text1 = string; let fontSizeSmall = size; let x = xx; let y = yy; let bounding_box = myFont.textBounds(text1, x, y, fontSizeSmall); x -= bounding_box.x; y -= bounding_box.y; return { x: x + xx, y: y + yy, size: fontSizeSmall, font: myFont, string: string, rect: { x: x + bounding_box.x, y: y + bounding_box.y, w: bounding_box.w, h: bounding_box.h, }, }; } } function draw() { kokac.step(); } const kokac = new KokacP5Ext(); async function setup() { // 로직은 setup 안에서만 손 대면 되도록 코드를 구성함 let sizeWidth = document.querySelector("#stg").getBoundingClientRect().width; let sizeHeight = sizeWidth * 1; createCanvas(sizeWidth, sizeHeight); kokac.add((e) => background("#00000040")); noStroke(); let rotate = 0; function genLine() { rotate += 0.0001; let ad = { life: 1, x: sizeWidth / 2, y: sizeHeight / 2, dir: PI / 2 + rotate, need: true, }; ad.setDir = function () { this.from = { x: this.x, y: this.y }; let gak = 0.04; this.dir += PI * gak * (Math.random() < 0.5 ? -1 : 1); this.leng = 20; this.lenginc = 0; this.need = false; }; ad.update = function () { this.life += Math.random() > 0.5 ? 1 : -1; if ( 0 >= this.life || this.x < 0 || this.y < 0 || this.x > sizeWidth || this.y > sizeHeight ) { kokac.remove(ad); genLine(); } if (this.need) this.setDir(); this.lenginc += 5; if (this.lenginc >= this.leng) { this.lenginc = this.leng; this.need = true; } let { x, y } = this.from; let pos = Geometry.getPointByRadian(x, y, this.dir, this.lenginc); this.x = pos[0]; this.y = pos[1]; }; ad.redraw = function () { fill("#ffffffff"); circle(this.x, this.y, 3); }; kokac.add(ad); } for (let i = 0; i < 1000; i++) { genLine(); } } if (false) { let sizeWidth = document.querySelector("#stg").getBoundingClientRect().width; let sizeHeight = sizeWidth * .5; // sizeWidth = innerWidth; // sizeHeight = innerHeight; createCanvas(sizeWidth, sizeHeight); }