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);
}