見出し画像

reactでp5jsも使ってさらにリアルタイムデータベースも使いたい1

p5jsは結構前から使っていましたが、ジェネラティブアートとかクリエイティブコーディングとかその手の類の画像や動画を生成して満足していました。そんでもうちょい進歩したことしたいなと思い今回はreact上でp5jsが出来るようにし、可能ならばリアルタイムデータベースを使ってインタラクティブなサイトを作りたいなと思いました。

とはいえ、すでにreactとp5jsに関してもいろいろなライブラリが出ているのでそれを組み合わせるだけだと思います。早速やっていきましょう。

環境構築

環境構築と言っても大したことはしません。create-react-appして必要なライブラリをインストールするだけです。

$ npx create-react-app p5project

モジュールのインストール

$ yarn add react-p5 --save
$ yarn add react-p5-wrapper --save
$ yarn upgrade p5 --save

ここで一度yarn startできちんとプロジェクトが構築されていることを確認してください。確認し、問題なければ不必要なファイルを削除し、以下のようなディレクトリ構成にします(別にしなくてもいいですが)。赤で塗りつぶしているものは現段階では不必要なものです(スクショを後から撮ったので混じってます)。

スクリーンショット 2020-09-22 15.43.21

App.js

今回はp5jsのキャンバスを画面いっぱいに表示しようと思います。なのでP5Wrapperというラッパーコンポーネントのみを読み込んでいます。このラッパーコンポーネントを通してp5jsをreactに読み込みます。
Sketchはp5jsファイルになります。

import React from 'react';
import P5Wrapper from "react-p5-wrapper"
import { Sketch } from "./sketch";
function App() {
   return (
       <P5Wrapper sketch={ Sketch } />
   );
}
export default App;

Sketch.js

Sketchという関数を定義し、その中に通常のp5jsの文法と同じようにコードを記述していきます。一つ違う点はP5Wrapperからp5jsの機能を引数としてもらうのでその引数からp5jsの機能を呼び出す必要があります(今回でいうとp)。

const Sketch = (p) => {
   p.setup = () => {
       p.createCanvas(p.windowWidth, p.windowHeight);
       window.onresize = function() {
           p.createCanvas(p.windowWidth, p.windowHeight);
       };
   }
   p.draw = () => {
       p.background(0);
       p.fill("#ffbb11");
       p.noStroke();
       p.ellipse(p.mouseX, p.mouseY, 50);
   }
}
export { Sketch }

ここではマウスポインタの場所に円を表示するようにコードを書いています。また、ブラウザのサイズを変更されてもいいように、window.onresizeでブラウザのサイズが変更される度にそのサイズでキャンバスを作成するようにしています。

実行結果

スクリーンショット 2020-09-22 16.09.22

これだと芸がなく触っていて楽しくもないと思うので、クリックすると波紋が広がるように書き換えます。

画面の実装

適切な名詞が思いつかなかったので画面の実装と書きましたが、実際に操作する画面をp5jsを使って実装します。以下がそのコードになります。キャンバス部分の変更なので書き換えるのはSketch.jsのみです。

Sketch.js

コードの説明はコメントを見ていただけば把握出来ると思います。p5js周りの仕様を全然把握していないので、rippleをクラスとして切り出すことが出来ませんでした。このあたりはその内調べなきゃなという感じです。

const Sketch = (p) => {
   /**
    * クリックした時に出来るrippleオブジェクトを格納しておく配列
    * クリックと同時に新しいrippleオブジェクトが追加され、透明度a
    * が0より小さくなると配列から削除される。
    * TODO:クラスオブジェクトの定義が上手くいかなかったのでそれぞれ関数で実装
    * しているのでクラス実装の仕方を調べる。
    */
   const ripples = [];
   let ripple; // rippleオブジェクト
   let itr = 0; // noise生成の種
   /**
    * rippleオブジェクトの状態を更新する関数
    * drawの毎に更新される。
    * @param {*} ripple 
    */
   const update = (ripple) => {
       ripple.r+=2;
       ripple.a-=1;
   }
   /**
    * rippleオブジェクトから実際の波紋を描画する関数
    * drawの毎に表示する。
    * @param {*} ripple 
    */
   const show = (ripple) => {
       p.noStroke();
       p.drawingContext.shadowOffsetX = 0;
       p.drawingContext.shadowOffsetY = 0;
       p.drawingContext.shadowBlur = 1000;
       p.drawingContext.shadowColor = p.color(ripple.c, 255, 255);
       p.fill(ripple.c, 255, 255, ripple.a);
       p.ellipse(ripple.x, ripple.y, ripple.r);
   }
   /**
    * セットアップの関数。
    * ウィンドウサイズが変更される度に呼ばれるので
    * 関数にまとめている。
    */
   const initSetup = () => {
       p.createCanvas(p.windowWidth, p.windowHeight);
       p.colorMode(p.HSB, 255);
       p.blendMode(p.BLEND);
       p.background(0, 0, 255);
   }
   p.setup = () => {
       initSetup();
       window.onresize = () => {
           initSetup();
       }
   }
   p.draw = () => {
       p.blendMode(p.BLEND);
       p.background(0, 0, 255);
       p.blendMode(p.DIFFERENCE);
       // 配列内の全てのrippleオブジェクトに対してudpate, showを実行
       for (let i=0; i<ripples.length; i++) {
           update(ripples[i]);
           show(ripples[i]);
           if (ripples[i].a < 0) {
               ripples.splice(i, 1);
           }
       }
       // マウスをクリックする度に新しいrippleオブジェクトを生成
       if (p.mouseIsPressed) {
           ripple = {
               x: p.mouseX,
               y: p.mouseY,
               c: p.floor(p.noise(itr/50) * 300),
               r: 0,
               a: 100,
           }
           ripples.push(ripple);
       }
       itr++;
   }
}
export { Sketch }

実行すると以下のような感じになります。静止画だと解りませんが、ドラッグすると波紋のように円が広がります。

スクリーンショット 2020-09-23 11.17.28


この記事が気に入ったらサポートをしてみませんか?