ローカル環境でp5.jsHelloWorld

p5.jsは

https://editor.p5js.org/https://openprocessing.org/
  • とかを使えばオンライン上で編集できるので,動かすのはそれほど困らない
  • だけどローカル環境でも開発したい

やること

  • ローカル環境でp5.jsを使ったコンテンツ開発をする
  • なのでViteTypeScriptReactを使う

hr

Viteのプロジェクトの作成

$ npm create vite@latest react-ts-p5-kitchensink
$ Select a framework: > React
$ Select a variant: > TypeScript + SWC

プロジェクト名はreact-ts-p5-kitchensinkとしたが,これはなんでも良い

hr

生成されたフォルダの中身を確認する

.
├── README.md
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── public
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── assets
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

hr

まずは動作確認

$ npm run dev

これを変えていく

hr

p5.jsが動くようにする

$ npm i p5
$ npm i -D @types/p5

App.tsxを書き換える

import { useRef, useEffect } from 'react'
import './App.css'
import p5 from 'p5'

const App = () => {
  const sketchRef = useRef<HTMLDivElement | null>(null);

  let pos: p5.Vector;
  let vec: p5.Vector;
  const r: number = 50;

  useEffect(() => {
    const sketch = (p: p5) => {
      p.setup = () => {
        p.createCanvas(window.innerWidth, window.innerHeight);
        p.frameRate(60);
        pos = p.createVector(p.width / 2, p.height / 2);
        vec = p.createVector(p.random()*3+2, p.random()*3+2);
      };

      p.draw = () => {
        p.background("#E0E0E0");
        pos.x += vec.x;
        pos.y += vec.y;

        p.noStroke();
        p.fill("#507D8B");
        p.ellipse(pos.x, pos.y, r*2, r*2);

        if (pos.x > p.width - r || pos.x < r) {
          vec.x *= -1;
        }
        if (pos.y > p.height - r || pos.y < r) {
          vec.y *= -1;
        }
      };
    };

    const myP5 = new p5(sketch);
    return () => {
      myP5.remove();
    };
  }, []);

  return <div ref={sketchRef}></div>;
};

export default App

実行する

$ npm run dev

hr

左の方に黒いバーのような領域ができてしまうのでindex.css修正する

デフォルトで書かれている内容は全部消してしまっていいので以下のように修正した

body {
  margin: 0;
  padding: 0;
}

#root {
  margin: 0;
  padding: 0;
}

hr

今の状態だとスクロールに反応してしまうのが嫌

スクロールイベントをキャンセルさせる

...
...
...
    const myP5 = new p5(sketch);
    const preventDefault = (e: Event) => e.preventDefault();
    window.addEventListener('scroll', preventDefault);
    return () => {
      myP5.remove();
      window.removeEventListener('scroll', preventDefault);
    };
  }, []);

  return <div ref={sketchRef}></div>;
};

export default App

index.css側も編集する

body {
  overflow: hidden;
  margin: 0;
  padding: 0;
}

#root {
  margin: 0;
  padding: 0;
}

これでスクロールしても画面は動かなくなったはず

hr

フレームレートを確認したいのでstats.jsを導入する

$ npm i stats.js
$ npm i -D @types/stats

App.tsxを書き加える

  • importする
  • 初期化
  • draw()の処理を囲む
  • return()の処理
...
import Stats from 'stats.js'

const App = () => {
  const sketchRef = useRef<HTMLDivElement | null>(null);
  const statsRef = useRef<Stats | null>(null);
	...
	... 
  useEffect(() => {
    const stats = new Stats();
    stats.showPanel(0);
    stats.dom.style.position = 'absolute';
    stats.dom.style.top = '0px';
    stats.dom.style.left = '0px';
    document.body.appendChild(stats.dom);
    statsRef.current = stats;
		...
		...
      p.draw = () => {
        stats.begin();
        ...
        ...
        ...
        stats.end();
      };
    };
    ...
    ...
     return () => {
      myP5.remove();
      window.removeEventListener('scroll', preventDefault);
      if (statsRef.current) {
        document.body.removeChild(statsRef.current.dom);
      }
    };
  }, []);
  ...
  ...

左上にFPSが表示されるようになったはず

hr

今のままだとウィンドウサイズを変更した時に対応できない

App.tsxでウィンドウのリサイズに対応させる

	...
	...
	... 
  useEffect(() => {
  ...
  ... 
    const sketch = (p: p5) => {
      p.setup = () => {
      ...
      ...
      ...
      };

      p.draw = () => {
      ...
      ...
      ...
      };
      p.windowResized = () => {
        p.resizeCanvas(window.innerWidth, window.innerHeight);
      };
    };
    
...
...
...

setup(), draw()に加えて,windowResized()を追加

ここで公開してる

https://shinyaoguri.github.io/react-ts-p5-kitchensink/

#blog