Moji ga MojiMoji
p5.js v2
View Source Code
let font;
// let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const hiragana =
"あいうえおかきくけこさしすせそたちつてと" +
"なにぬねのはひふへほまみむめもやゆよ" +
"らりるれろわをんゐゑ" + // 歴史的仮名
"がぎぐげござじずぜぞだぢづでどばびぶべぼ" + // 濁音
"ぱぴぷぺぽ" + // 半濁音
"ぁぃぅぇぉゃゅょっゎ"; // 拗音・小書き文字
const katakana =
"アイウエオカキクケコサシスセソタチツテト" +
"ナニヌネノハヒフヘホマミムメモヤユヨ" +
"ラリルレロワヲンヰヱ" + // 歴史的仮名
"ガギグゲゴザジズゼゾダヂヅデドバビブベボ" + // 濁音
"パピプペポ" + // 半濁音
"ァィゥェォャュョッヮ"; // 拗音・小書き文字
let chars = (hiragana + katakana).split("");
const MAX = 256;
class MyChar {
constructor(txt) {
this.txt = txt;
const outPx = 100;
this.pos = {
x: random(-outPx, width + outPx),
y: random(-outPx, height + outPx),
};
// = createVector(10,10, 0)//r, random(-50, height + 50));
this.color = color(random(0, 255), random(0, 255));
this.currentColor = color(255, 0);
textSize(random(100, 300));
this.pathCommands = font.textToPaths(this.txt, 0, 0);
this.bounds = fontBounds(this.txt, 0, 0);
this.count = 0;
this.lifeMax = random(300, 600);
}
get isLive() {
return this.count < this.lifeMax;
}
update() {
this.count++;
this.pos.x += random(-1, 1);
this.pos.y += random(-1, 1);
if (this.count < 100) {
this.currentColor = lerpColor(
color(255, 0),
this.color,
this.count * 0.01
);
} else if (this.count > this.lifeMax - 100) {
this.currentColor = lerpColor(
this.currentColor,
color(255, 0),
(this.count - (this.lifeMax - 100)) * 0.01
);
} else {
this.currentColor = this.color;
}
}
display() {
this.drawPathCommands(
this.pathCommands,
this.bounds,
this.pos.x,
this.pos.y
);
}
drawPathCommands(pathCommands, bounds, x, y) {
push();
// const r = 10
// const rx = random(-r, r);
// const ry = random(-r, r);
translate(x - bounds.w / 2, y - bounds.h / 2);
// scale(random(0.95,1));
// rotate(radians(this.count) * 0.1);
// noFill()
// rect(bounds.x, bounds.y, bounds.w, bounds.h)
stroke(color(0, alpha(this.currentColor)));
fill(this.currentColor);
beginShape();
for (let i = 0; i < pathCommands.length; i++) {
const cmd = pathCommands[i];
const type = cmd[0];
const r = 8;
const rx = random(-r, r);
const ry = random(-r, r);
switch (type) {
case "M": {
// Move to (start a new contour)
const x = cmd[1];
const y = cmd[2];
endContour(); // In case we were already drawing
beginContour();
vertex(x + rx, y + ry);
break;
}
case "L": {
// Line to
const x = cmd[1];
const y = cmd[2];
vertex(x + rx, y + ry);
break;
}
case "Q": {
// Quadratic bezier
const cx = cmd[1];
const cy = cmd[2];
const x = cmd[3];
const y = cmd[4];
bezierOrder(2);
bezierVertex(cx, cy);
bezierVertex(x + rx, y + ry);
break;
}
case "C": {
// Cubic bezier
const cx1 = cmd[1];
const cy1 = cmd[2];
const cx2 = cmd[3];
const cy2 = cmd[4];
const x = cmd[5];
const y = cmd[6];
bezierOrder(3);
bezierVertex(cx1, cy1);
bezierVertex(cx2, cy2);
bezierVertex(x + rx, y + ry);
break;
}
case "Z": {
// Close path
endContour(CLOSE);
beginContour();
break;
}
}
}
endContour();
endShape();
pop();
}
}
// --------------------
let objs = [];
let isLoading = false;
async function load() {
isLoading = true;
font = await loadFont("BIZUDPGothic-Regular.ttf");
isLoading = false;
}
async function setup() {
createCanvas(windowWidth, windowHeight);
background(220);
load();
setInterval(addObject, 100);
}
function addObject() {
if (isLoading) return;
if (objs.length >= MAX) return;
objs.push(new MyChar(random(chars)));
}
function draw() {
background(220, 128);
if (isLoading) {
displayLoading();
return;
}
displayGame();
}
function displayLoading() {
push()
stroke(0);
noFill();
textSize(random(30, 40));
textAlign(CENTER, CENTER)
text("Loading...", width / 2 + random(-5, 5), height / 2 + random(-5, 5));
pop()
}
function displayGame() {
stroke(0);
noFill();
for (const obj of objs) {
obj.update();
}
objs = objs.filter((obj) => obj.isLive);
for (const obj of objs) {
obj.display();
}
}