HaLake Magazine

コワーキングスペースHaLakeの技術情報発信サイト!IoT,AR,VRなど最新技術情報をお届け!

P5.JSを使ってみる <導入編>

背景

今回はP5.JSというProcessingというプログラミング初心者のアーティストやデザイナ―でも簡単かつ無料で使えるプログラミング言語JavaScriptに置き換えたものを使っていきます。

最終目的は次回の記事でP5.playと言うP5.JSを拡張したライブラリを使って謎解き系のミニゲームを作ってみたいと思っているので、P5.JSの導入と公式から提供されているお試しプログラムの動作確認など行っていきたいと思います。

目次

  1. 背景
  2. 導入
  3. 試してみる
  4. まとめ

導入

まずは導入から行っていきます。
導入と言っても選択肢が大きく3つで、特に何もしなくて良いし手間がかかる方に分かれます。
どちらも簡単なので好きな方を選んでください。

選択肢1. Web Editor

editor.p5js.org

上記のリンクに飛んでもらえればすでにP5.jsが動かせる環境がととのっています。

特に手間をかけずに試したい方はこちらを選ぶことを推奨します。

選択肢2. ダウンロード

自分でHTMLファイルも用意したり、ちょっと手の込んだことをしたい方や手元の環境で動作させたい方向けです。

https://p5js.jp/download/p5js.jp

上記のリンクに飛んでもらうと、下記の画像のようなページになるので青線で囲まれた場所をクリックすると勝手にZIPファイルがダウンロードされます。

f:id:mischief_cat:20210926101213p:plain

私の場合、寄付に関するページに自動で飛びましたがお気持ちがある方のみで大丈夫なので無視しても問題ありません。下記の画像のようなページが開かれました。

f:id:mischief_cat:20210926101739p:plain

先ほどダウンロードしたZIPファイルを解凍するといくつかのフォルダがあるので画像のように進めてempty-exampleを探してください。

f:id:mischief_cat:20210926102859p:plain

empty-exampleの中身には二つのファイルがあり、これらに追記していくことで好きなプログラムを動かすことが出来ます。

f:id:mischief_cat:20210926103404p:plain

中身はempty-exampleと言うだけあって中身はとても簡単です。

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
    <style> body {padding: 0; margin: 0;} </style>
    <script src="../p5.min.js"></script>
    <script src="../addons/p5.dom.min.js"></script>
    <script src="../addons/p5.sound.min.js"></script>
    <script src="sketch.js"></script>
  </head>
  <body>
  </body>
</html>

scektch.js

function setup() {
  // put setup code here
}

function draw() {
  // put drawing code here
}

こちらの方法はダウンロードするだけで動く環境が整えられますが、今回の記事では使わないもの(index.htmlの記述や別階層のファイル)まで含まれています。初心者からするとファイルが増えると混乱してしまうかもしれません。

選択肢3. CDN

この方法だと自分でHTMLファイルやJavaScriptファイルを用意する必要があり、大変ですが必要最低限のコードとファイルで済ますことが出来ます。

好きな場所で好きな名前のフォルダを作成した後、index.htmlscketch.jsファイルを作成します。そしたらそれぞれ中身に以下をコピペしましょう。

ちなみに私は、分かり易いようにデスクトップにtest_p5フォルダを作ってそこに以下で作成する2つのファイルを配置しました。

f:id:mischief_cat:20210926111612p:plain

index.html

<!DOCTYPE html>
<html>

<head>
    <title>HaLake P5.js test</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js" type="text/javascript"></script>
    <script src="scketch.js" type="text/javascript"></script>
</head>

<body>

</body>

</html>

6行目のhttps://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.jsは、時期によって使えるバージョンが変わったりするため、最新版を使いたい場合は以下のURLに飛んで画像に従ってURLをコピペして書き変えてください。

cdnjs.com

f:id:mischief_cat:20210926113918p:plain

本記事で記載されるコードは2021/9/26に動作確認したものです。

scketch.js

function setup() {

}

function draw() {
    
}

scketch.jsに関しては選択肢2でダウンロードした同名のファイルとほぼ同じ内容になっています。これ以上省略できないので。

以上の3つ(選択肢1選択肢2選択肢3)の方法を説明しました。

以降、記事では選択肢3の方法で進めて行くので初心者の方やわからない方は選択肢3を選んで同じようにすすめてください。

これで実行環境は整いました。

試してみる

だいたいは、下記リンクのサンプルなどを見て学ぶと良いでしょう。

https://p5js.jp/examples/p5js.jp

自分は良い例を新しく考えるのは苦手なので上記URLの例をほんの少しだけ書き換えたものを以下に示します。

基本的な描画APIの確認

まずは線や図形の描画をするAPIを確認していきます。

以降scketch.jsの内容を消して下記のコードをコピペするか、手入力するかして書き込んでください。

実行はWindowsであればエクスプローラからindex.htmlをダブルクリックして起動すると既定のブラウザで開いてくれます。

図形の基本的な形である円の描画です。

scketch.js

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);//背景:白
  
  ellipse(width / 2, height / 2, 100, 100);
}

円の描画は以下のAPIで出来ます。

ellipse(width / 2, height / 2, 100, 100);

引数の設定は第一から順に(円中心のX座標、円中心のY座標、中心からの外枠の幅、中心からの外枠の高さ)になります。

上記プログラムの例では、第1、2引数にwidth / 2height / 2となっていますが、これはP5.JSが提供している変数(widthとheight)でそれぞれcreateCanvas(400, 400);の引数で指定された高さと幅が格納されています。ここではそれぞれ400が格納されていて、それを半分に割った数値が円の中心座標X、Yに設定されているの実際の値はそれぞれ200が割り当てられてキャンバスの中心に円描画されます。

f:id:mischief_cat:20211003114617p:plain

第3、4は100が設定されているので幅と高さが100、つまり半径100の円が生成されます。それぞれ違う数値を入力すると幅と楕円が表示されます。API名のellipse(楕円)となっているので数値を変えれば楕円が描画されます。

試しに0~100の間でランダムな幅と高さの円を1秒ごとに表示するプログラムです。

scketch.js

function setup() {
  createCanvas(400, 400);
  frameRate(1);
}

function draw() {
  background(255);//背景:白
  
  ellipse(width / 2, height / 2, random(100), random(100));
}
  • 注意:先ほど0~100の間でと言いましたが上記の例だとrandom(100)となっていて、これだと0~99.99999....までの数値が返っていきます。random関数は引数が一つだけの場合は0~引数で指定した数値(指定した数値は含まない)となるため正確に言うと100は返り値として返ってきません。つまり上限設定のその指定した数値未満の数値が返ってくることになります(引数が2つの場合も)。英語ですが以下にリファレンスのリンクを貼っておきます。自前のプログラムで使う場合は気を付けてください。(追記:2021/10/17)

p5js.org

そのままだと描画スピードが速すぎるのでsetup()関数内でframeRate()関数を呼び出すことで、引数で入力した数値毎秒(引数/s)で図形が更新されます。これ図形の変化が分かり易いです。デフォルトではたいていのPCで60が設定されているようです。

画像のような楕円が1秒ごとに描画されます。

f:id:mischief_cat:20211003121823p:plain

  • 注意:第5引数も存在しますが、省略可能なので説明は省きます。際しくはリファレンスをどうぞ。

p5js.org

先ほど円の幅と高さを同じにして真円を描きましたが、最初から楕円を描画しない場合はcircle()と言う関数もあります。 こちらは引数を一つ減らして第3引数に半径を指定してあげれば簡単に真円が描画されます。

ellipse関数の行だけを書き変えて動きます。結果は上記の真円の画像と同じです。

scketch.js

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);//背景:白
  
  circle(width / 2, height / 2, 100);
}
四角形

次は四角形を描画するために、rect関数を使って行きます。

引数は(左上の頂点X座標、左上の頂点X座標、左上の頂点からの幅、左上の頂点からの高さ)になります。

早速プログラムを見ましょう

わかり辛かったので背景をここだけ黒くしました。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(0);//背景:黒

  rect(width / 2 , height / 2, 50, 50);//これだと左上の頂点の座標を始点としている
}

結果はこちら

f:id:mischief_cat:20211003151047p:plain

円の描画ではキャンバスの高さと幅の半分を引数で与えればキャンバス中央に表示されましたが、四角形に関しては引数で与えるX、Y座標は左上の頂点の座標を始点としている(円の時は円の中心が始点となる)ため上記画像見るとわかる通り四角形が中央に表示されません。

しかしrect関数にはrectModeと言う関数が用意されているため、直前で呼んであげると

rectMode(CENTER);//引数CENTERで図形の中心を始点とする、ほかにもRADIUS、CORNERSがある
rect(width / 2 , height / 2, lineSize, lineSize);

とすることで四角形の図形の中心を始点として指定できます。

これで中央に表示されます。

rectModeの引数に関しては以下を参照

p5js.org

また引数を4つまで追加することによって、第5引数が左上頂点と対応して時計回りに頂点が第8引数まで対応します。それぞれ円の半径を入力することによって角が丸く削れた四角形が描画されます。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);//背景:白

  rectMode(CENTER)
  rect(width / 2 , height / 2, 50, 50, 1, 10, 15, 30);//これだと左上の頂点の座標を始点としている
}

結果

f:id:mischief_cat:20211003131113p:plain

線はline関数を使いとても簡単です。

引数は(始点のX座標、始点のY座標、終点のX座標、終点のY座標)

function setup() {
  createCanvas(400, 400);
}

function draw() {
  line(0, 0, 400, 400);
}

キャンバスの左頂点から右下の頂点まで線を引くプログラムなっています。

引数を2つ増やすことでZ軸を足した3Dの線を引くことが出来ますが省きます。

点の場合はpoin関数を使います。

引数は(点のX座標、点のY座標)なります。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  point(random(width), random(height));
}

上記を実行して少し経つとゴマみたいなものが増えてくると思います。

f:id:mischief_cat:20211003142910p:plain

これだと少し見づらいので色や大きさを変えてみましょう。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  stroke(250, 100, 100);//色
  strokeWeight(5);//太さ
  point(random(width), random(height));
}

f:id:mischief_cat:20211003143233p:plain

今まで描画してきたものは全てこのstrokestrokeWeightfill関数などで色や境界線の太さなどを自由に変えられます。

今まで描画してきた図形を集めてそれぞれの色や太さなど変えてみました。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  stroke(0);
  strokeWeight(10);
  ellipse(width / 2, height / 2, 100, 100);
  
  noStroke();
  fill(0, 255, 0);
  rectMode(CENTER);
  rect(width / 2 , height / 4, 50, 50);
  
  fill(`#234567`);
  rect(width / 2 , height / 2, 50, 50, 1, 10, 15, 30);
  
  stroke(0);
  strokeWeight(15);
  erase();
  line(0, 0, 400, 400);
  noErase();
  
  noFill();
  stroke(250, 100, 100, 100);
  strokeWeight(10);
  point(random(width), random(height));
   
}

時間がたつとこうなる

f:id:mischief_cat:20211003150244p:plain

以下に使用したAPIの簡単な説明

stroke:線や境界線の色

strokeWeight:線や境界線の太さ

noStroke:線や境界線の描画を無効

fill:指定した色で図形を塗りつぶす

noFill:塗りつぶしの無効

erase:図形分削除する

noErase:eraseの解除

マウス操作

前述したように、次の記事で謎解きゲームを作ってみようと考えているので、それらで使いそうな機能を簡単に試してみようと思います。

まずは簡単なマウスのドラッグ操作で線を書けるようなプログラムです。

Exampleにあったのでそこに3行ほど足して書き込んだものをダブルクリックで消すようなものです。

元のプログラムはこちら↓

p5js.org

scketch.js

let drawState = true;

function setup() {
  createCanvas(displayWidth, displayHeight);
  background(102);
}

function draw() {
  stroke(255);
  if (mouseIsPressed === true) {
    line(mouseX, mouseY, pmouseX, pmouseY);
  }
}

function doubleClicked(){
  background(102);
}

f:id:mischief_cat:20210926175133p:plain

10,11行目にはmouse~~~といった変数を使っていますが、スマホなどのタッチ画面でも動作するようです。

しかし少し挙動がおかしい(線が滑らかに表示されない)ので今後使うかわかりませんが、タッチ操作での線描画の際には気を付ける必要がありそうです。以下にタッチ画面で試した際の画像を載せておきます。

f:id:mischief_cat:20211003100933p:plain

リファレンスの中にTouchという項目があるのでタッチ画面専用のAPIがあるので用途によって使い分ける必要があるかもしれません。

p5js.org

画像

画像のロードはサーバで動かさないとエラーが出てしまうのでpythonのFlaskなどを使って回避しましょう。

GitHubのpages機能を使えばもっと楽なのですが、ページの更新頻度が遅いことがあるためPythonを使ってサーバを立てる方が一番手っ取り早いと感じました。

  • 注意:pythonのインストール説明は今回の記事内容から外れるため解説はしません。

Flaskをインストールしておきましょう。私の場合はpipで行いました。

pip install flask

そしたら、index.htmlと同じ階層にmain.pyファイルを作って下記をコピペします。

main.py

from flask import Flask
app = Flask(__name__, static_folder='.', static_url_path='')
@app.route('/')
def index():
    return app.send_static_file('index.html')
 
app.run(debug=False, host='0.0.0.0', port=8000)

次に画像を用意します。

私は以下の画像を使用し、logo.pngとしておき、scketch.jsと同じ階層に置きます。

f:id:mischief_cat:20210926162931p:plain

本来なら、画像などは別のフォルダで管理するのが良いのですが、今回は試しなので同じ階層に置いて省略します。

プログラムでもlogo.pngとして指定しているので、環境に合わせて画像の名前かJavaScriptで指定する名前を書き変えてください。

下記プログラムをコピぺしたまま使いたい場合は使う画像の名前をlogo.pngにしておきましょう。

scketch.js

var img;

function setup() {
  createCanvas(displayWidth, displayHeight);
  img = loadImage("logo.png");  // Load the image
}

function draw() {
  image(img, 0, 0);
}

そしたら

python main.py

などで実行してください。

そのあと、下記のリンクに飛ぶと画像が表示されると思います。

http://localhost:8000/

  • 注意:上記のlocalhost:8000でアクセスする場合 Unchecked runtime.lastError: The message port closed before a response was received.このようなエラーが出ることがありました。Chrome拡張機能が原因のようなので、すべて拡張機能をオフにしたら問題なく動作しました。

onoredekaiketsu.com

また 304 NOT MODIFIEDこのように出ていて、リロードしても最新の状態に更新されない場合は以下のサイトを参考にリロードしてみてください。キャッシュの問題のようです。

296.co.jp

これだけだとパクってきただけなので、ほんの少しだけ手を加えてみましょう。

マウスの操作を先ほど行ったのでそれにちなんで画像をマウスに追従するようにします。

scketch.js

let offSetX = 300/2;
let offSetY = 218/2;
let moveState = false;
let img;

function setup() {
  createCanvas(displayWidth, displayHeight);
  img = loadImage("logo.png");  // Load the image
}

function draw() {
  if(moveState) 
    image(img, mouseX - offSetX, mouseY - offSetY);
  moveState = false;
}

function mouseMoved(){
    moveState = true;
}

こんな感じになりました。

f:id:mischief_cat:20210926174143p:plain

マウスに合わせてロゴが動いて、その軌跡に画像が残るようになっています。

ゲームを作る際、カーソルに合わせて画像を動かすときに役立ちますが先ほどの例だといくつも画像が残ってしまって邪魔になってしまいますね。

今回は画像の表示やマウスの位置などの使い方を軽く学ぶ程度だったので、次回はP5.playライブラリなどと絡めて簡単なゲームを作っていこうと思います。

まとめ

今回は導入編だったのと、Processing由来のグラフィックを有効活用する良案が思いつかなったため内容が薄くなってしまいました。 次回はスマホで動作するゲームを想定しているのでFlatterのwebviewを活用する予定です。