はじめに
タイトル通りの内容で、「つぶやきProcessing(Twitter の制限文字数内で動くプログラムを書くもの)」のために書かれた「Processing のプログラムと、それとは別の p5.js のプログラム」を、それぞれ p5.js用に書きかえたという話です。
「p5.js を p5.js で書きかえる?」と思われたかもしれませんが、これは「つぶやきProcessing用に短く書ける記法が用いられているものを、短縮版でない記法に展開する」という内容になります。
書きかえには以下の 3つの観点があり、今回の書きかえ対象の 2つのうち、一方は「主に 1 の観点での書きかえをしていて」、「もう1つは、以下の 2・3 の 2つの観点での書きかえ」という形になります。
1) Processing と p5.js とで文法が異なる部分を書きかえる
2) つぶやきProcessing用に短く書ける記法が用いられている部分を展開する
3) その他の書きかえ
なそ、書きかえ版は、普段よく利用している「p5.js Web Editor」を使って動かしています(もちろん、それ以外の環境・方法でも問題ありません)。
ちなみに、出来上がったもの 2つは以下の通りです。
大幅な変更はしてないので、元作品と同じか、ほぼ同じ(一部のパラメータをちょっと書きかえた)なのですがw
書きかえたもの 1つ目(@nicolasbaez さんの作品)
1つ目の話の出力結果などはこちらです。
元のものと同一の動作・見た目になった後、パラメータを少し変えています。
↓こちらの件の、動いている様子を動画にしたもの。https://t.co/0PJ0SCJ5eN#p5js pic.twitter.com/5QXIfb48rZ
— you (@youtoy) February 12, 2022
Processing用に書かれてたもの、 #p5js 版に書きかえができた! https://t.co/QG2GWzxIp0 pic.twitter.com/rbLztvCJWY
— you (@youtoy) February 12, 2022
書きかえたもの 2つ目(@sh_sys_ さんの作品)
2つ目の話の出力結果などはこちらです。
途中まで手をつけていた件の続き。
— you (@youtoy) February 11, 2022
自分用に扱いやすくなるように書き直したもの、こんなところかな。 pic.twitter.com/Q4OTvwMa2A
書きかえを行った話の詳細
1つ目のほう
元のプログラムは、冒頭のツイート内に書いてあるとおり、以下となります(ハッシュタグは除いています)。
void setup(){size(500,500,P3D);colorMode(HSB,3);}float i,j,r,k,w=250;void draw(){clear();translate(w,w);rotateX(k);rotateY(k/2);for(i=0;i<=3;i+=.02){for(j=0;j<6;j+=.02){r=noise(i,j,k)*w;stroke(i,j,PI);point(r*sin(i)*cos(j),r*sin(i)*sin(j),r*cos(i));}}k+=.01;}
改行を入れると、このような感じでしょうか。
void setup(){
size(500,500,P3D);
colorMode(HSB,3);
}
float i,j,r,k,w=250;
void draw(){
clear();
translate(w,w);
rotateX(k);
rotateY(k/2);
for(i=0;i<=3;i+=.02){
for(j=0;j<6;j+=.02){
r=noise(i,j,k)*w;stroke(i,j,PI);
point(r*sin(i)*cos(j),r*sin(i)*sin(j),r*cos(i));
}
}
k+=.01;
}
そして、書きかえ後のほうは、以下のとおりです(一部、コメントを残してます)。
let r, k, w;
function setup() {
createCanvas(500, 500, WEBGL);
colorMode(HSB, 3);
w = width / 2;
k = 0;
}
function draw() {
background(0); // clear(); をこちらに変更
// translate(w, w); // 不要っぽい
rotateX(k);
rotateY(k / 2);
// 以下、for分の増分を *5 にしてみた
for (let i = 0; i <= 3; i += 0.02 * 5) {
for (let j = 0; j < 6; j += 0.02 * 5) {
r = noise(i, j, k) * w;
stroke(i, j, PI);
point(r * sin(i) * cos(j), r * sin(i) * sin(j), r * cos(i));
console.log(r * sin(i) * cos(j), r * sin(i) * sin(j), r * cos(i));
}
}
k += 0.01;
}
書きかえ: Processing用の処理を p5.js用に
書きかえをした話の補足を書いていきます。
まずは、「Processing用の処理を p5.js用に書きかえた」という話の部分です。
例えば、「void setup()」や「void draw()」は、「function setup()」・「function draw()」にしています。また、キャンバスの作成のところも「size(500,500,P3D)」という書き方を「createCanvas(500, 500, WEBGL)」に変更します。
その他にも、「float i,j,r,k,w=250」という部分は「let r, k, w」と、setup()内の「w = width / 2」という指定をしています(w の値の決め方の意図も反映させるような書きかえをまじえつつ)。
それと、「clear()」だと背景色のあたりが意図通りにならないため、「background(0)」としていたり、「translate(w, w)」が不要っぽいので外したり、ということもやっています(デフォルトの背景色や 3D を扱うモードの原点の違いがあるっぽい)。
細かいところで「for(i=0。。。」というところを「for (let i = 0。。。」としていたりもします。
主には、このような書きかえをしました。
あとは、動作させるだけなら不要な書きかえですが、「for文の中の i+=.02 を i += 0.02 * 5 と変える」パラメータの変更をしたくらいです(後で変更しやすいように、乗算の形で書いています)。
2つ目のほう
元のプログラムは、冒頭のツイート内に書いてあるとおり、以下となります。
v=0
p=[]
draw=_=>{
v||createCanvas(w=640,w)+noFill(colorMode(HSB,9))
B=blendMode
R=random
B(BLEND)
background(0,.2)
B(ADD)
if(v++%30==0)p.push([R(9),R(w),R(w),0])
p .map(([c,x,y,r])=>stroke(c,9,9,5)+circle(x,y,r))
p=p.filter(q=>q[3]++<w/2)
}
そして、書きかえ後のほうは、以下のとおりです。
let cxyrArray = [];
function setup() {
createCanvas(600, 550);
noFill();
colorMode(HSB, 9);
}
function draw() {
blendMode(BLEND);
background(0, 0.2);
blendMode(ADD);
if (frameCount % 30 == 0) {
cxyrArray.push({
"c": random(9),
"x": random(width),
"y": random(width),
"r": 0,
});
}
for (const val of cxyrArray) { // map を for...of に
stroke(val.c, 9, 9, 5);
circle(val.x, val.y, val.r);
val.r++;
}
cxyrArray = cxyrArray.filter(
(elem) => elem.r < width / 2);
}
書きかえ: 主に「つぶやきProcessing用に短く書ける記法」を展開する話
ここから、短縮記法などの部分を展開するような書きかえの補足を書いていきます。
まず、「setup()」を省略できるように書かれていたのを、「1回だけ実行する処理は、setup()内に書く」という形に書き直しました。
v||createCanvas(w=640,w)+noFill(colorMode(HSB,9))
の部分の ||
より後ろを展開したような形です。
また、文字数制限を気にしないならば、「v」というカウントアップしていく部分を「frameCount」にしてしまえば意図が分かりやすくなりそうです。
それと、「B=blendMode」や「R=random」と短縮のための処理は、書く処理が必要な部分で「blendMode」・「random」を用いるようにしました。
余談ですが、上記のような書きかえをしていると、つぶやきProcessing用のノウハウが見られて、勉強になります。
さて、続きで以下の部分の話です。
if(v++%30==0)p.push([R(9),R(w),R(w),0])
p .map(([c,x,y,r])=>stroke(c,9,9,5)+circle(x,y,r))
p=p.filter(q=>q[3]++<w/2)
ここは、何となくそうしたかったという変更も含め、以下のようにしています。
以下の処理に関連して、プログラムの最初で「let cxyrArray = []」という空の配列を初期値にして、というものも書いています。
if (frameCount % 30 == 0) {
cxyrArray.push({
"c": random(9),
"x": random(width),
"y": random(width),
"r": 0,
});
}
for (const val of cxyrArray) { // map を for...of に
stroke(val.c, 9, 9, 5);
circle(val.x, val.y, val.r);
val.r++;
}
cxyrArray = cxyrArray.filter((elem) => elem.r < width / 2);
「何となくそうしたかった」という部分は、push により [c,x,y,r] の 4つの値をランダムに作っては追加する、という部分のところです。
これを、「配列の 0番目から 4番目の値」という形でなく、オブジェクトの「key で設定したい内容を示す文字を、value でその値を指定する」という形にしました。
もちろん、これをやらなくても OK です。
あと、map でやっている処理は「for...of」を使う形にしていたりもします。
オブジェクトの配列となっている中身を 1つずつ取り出し、その取り出したオブジェクトの中の必要な値を key の文字で指定して使っています(val.c や val.x など)。
これで、書きかえ後のプログラムができあがりました。
おわりに
今回、つぶやきProcessing用に書かれた Processing・p5.js のプログラムを、p5.js で書きかえてみました。
書きかえの中で、特に「つぶやきProcessing用に短く書ける記法」を展開す部分は、短く書くためのノウハウの勉強になる部分なので、またこれからもたまにやっていければと思います。
ちなみに、以前も以下のように、今回やったようなのと似たことを試して記事にしていたりしました。
●#つぶやきProcessing で気になった作品を p5.js Web Editor で動かしてみる 【その2】 - Qiita
https://qiita.com/youtoy/items/ac2f953d9a0ced3b881a
●#つぶやきProcessing で気になった作品を p5.js Web Editor で動かそうとしてみる【 #GWアドベントカレンダー 2021/5/2 】 - Qiita
https://qiita.com/youtoy/items/0806ba53db59261da3f8
余談
今回の記事の 1つ目に出てきていたものは、その後に、少しだけ追加実装をしました。
なお、今回の記事のメイン部分に含めると、トピック的に少しだけ発散するように思ったので、余談としてここに書いています。
やったことは、「mouseX・mouseY(マウスカーソルの位置座標を取得するもの)を使って、一部の表示に関わるパラメータを動的に変化させる」というものでした。
#AltEdu2022 Day12「普段と違う場所・時間にコードを書く」で、Day6 の要素もあるやつ。@nicolasbaez さんの #つぶやきProcessing https://t.co/QG2GWzxIp0
— you (@youtoy) February 12, 2022
に関して「Processing用 ⇒ #p5js 用の書きかえ」をして、さらにカーソル位置の移動による変化が起こる要素を足したものを、出先で書いた! pic.twitter.com/mb3d8PsFnD
この追加実装をしたものも、ソースコードをのせておこうと思います。
let r, k, w;
let dist = 1.0,
weight = 5;
function setup() {
createCanvas(500, 500, WEBGL);
colorMode(HSB, 3);
w = 0.7 * width;
k = 0;
}
function draw() {
background(0);
rotateX(k);
rotateY(k / 2);
const temp = 3;
for (let i = 0; i <= 3; i += 0.02 * temp) {
for (let j = 0; j < 6; j += 0.02 * temp) {
r = noise(i, j, k) * w;
stroke(i, j, PI);
dist = map(width - mouseX, 0, width, 0.3, 1);
weight = map(height - mouseY, 0, height, 12, 2);
strokeWeight(weight);
const x = dist * r * sin(i) * cos(j),
y = dist * r * sin(i) * sin(j),
z = dist * r * cos(i);
point(x, y, z);
}
}
k += 0.01;
}
【追記】 コメントをいただきました
メンションつけてツイートしてたところに、コメントをいただきました。
「OMG」と「Gracias」と断片的な単語は意味が分かるのですが(選択必修科目の第二外国語で、スペイン語を選択していた過去より)、他の部分は分からないので DeepL で訳してみました。
OMG!!! Miren mireeen 🙈😍🙈😍🙈😍, se siente super bien cuando eres inspiración para algo!! Gracias!! ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ https://t.co/HE1ixaq6s2
— nicolás báez (@nicolasbaez) February 20, 2022
「自分が何かのきっかけになると、とても気持ちがいいものです!!!」というような内容を書いていただいたようです。
そうえいば、英語圏の方から英語のコメントをいただくことはあったものの、スペイン語でのコメントツイートをいただいたのは初めてかも?