P5.js + Reactでのページの作成

[前回の記事](https://qiita.com/makoto-ogata@github/items/a485e0327269c75f41a1)の続きになります。
前回の記事はセットアップまでだったので今回は実際にページを作成していきます。

## App.tsxの修正

ここから画面いっぱいのアニメーションを作るために編集していきます。

```前回のApp.tsx
import { Background } from "./background/Background"; 
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";

function App() {
	const [count, setCount] = useState(0);

	return (
		<>
			<div>
				<Background /> 
				<a href='https://vite.dev' target='_blank'>
					<img src={viteLogo} className='logo' alt='Vite logo' />
				</a>
				<a href='https://react.dev' target='_blank'>
					<img src={reactLogo} className='logo react' alt='React logo' />
				</a>
			</div>
			<h1>Vite + React</h1>
			<div className='card'>
				<button onClick={() => setCount((count) => count + 1)}>
					count is {count}
				</button>
				<p>
					Edit <code>src/App.tsx</code> and save to test HMR
				</p>
			</div>
			<p className='read-the-docs'>
				Click on the Vite and React logos to learn more
			</p>
		</>
	);
}

export default App;

```

デフォルトの要素はいらないので、どんどん削除していきましょう。

```修正したApp.tsx
import { Background } from "./background/Background"; 

function App() {
	
	return (
		<>
    	  <Background /> 
		</>
	);
}

export default App;

```

## Background.tsxの修正

次に背景ファイルの修正をしていきます。

```前回のBackground.tsx
import { ReactP5Wrapper, P5CanvasInstance } from "@p5-wrapper/react";

function sketch(p5: P5CanvasInstance) {
	p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

	p5.draw = () => {
		p5.background(250);
		p5.normalMaterial();
		p5.push();
		p5.rotateZ(p5.frameCount * 0.01);
		p5.rotateX(p5.frameCount * 0.01);
		p5.rotateY(p5.frameCount * 0.01);
		p5.plane(100);
		p5.pop();
	};
}

export const Background = () => {
	return <ReactP5Wrapper sketch={sketch} />;
};

```

一旦はsketch関数の中を空っぽにします。

```修正したBackground.tsx

import { ReactP5Wrapper, P5CanvasInstance } from "@p5-wrapper/react";

function sketch(p5: P5CanvasInstance) {
// setupとdrawの中身を削除

    p5.setup = () => p5.createCanvas();

	p5.draw = () => {
	};

}

export const Background = () => {
	return <ReactP5Wrapper sketch={sketch} />;
};

```
今回は雪を降らせるようなアニメーションをしたいので、まず雪の空配列を作ります。

```typescript
interface Snowflake {
	x: number;
	y: number;
	size: number;
 }

 const snowflakes: Snowflake[] = [];
```

背景のアニメーションを画面いっぱいにしたいので、`createCanvas`を以下のようにします。

```typescript
    p5.setup = () => {
		p5.createCanvas(window.innerWidth, window.innerHeight);
	};
```

今度は`draw`にロジックを書いていきます。

```typescript
  p5.background(20, 30, 50); // 背景を暗くする rgb(20, 30, 50)
  p5.fill(255); // 塗りつぶしの色を白にする
  p5.noStroke(); // 輪郭線をなしにする
```

```typescript
if (p5.frameCount % 5 === 0) {// カウントが始まって5フレーム事
	snowflakes.push({
		x: p5.random(0, p5.width), // 画面の横ラインでの雪を降らせる位置をランダムで指定
		y: 0, //　縦のラインはいらないので0
		size: p5.random(2, 5), // 雪のサイズをランダムで指定
	});
}
```
雪の準備が整いましたので、あとは雪を降らせるループを書いていきます。

```typescript
for (let i = snowflakes.length - 1; i >= 0; i--) {
	const snowflake = snowflakes[i];
	p5.ellipse(snowflake.x, snowflake.y, snowflake.size);
	snowflake.y += snowflake.size * 0.5;
	if (snowflake.y > p5.height) {
		snowflakes.splice(i, 1);
	}
}
```
そしてCSSで背景を固定させたら完了です。（[emotion](https://emotion.sh/docs/introduction)を使用しました）
雪を降らせる背景がこちらのコードです。

```Background.tsx
import { ReactP5Wrapper, P5CanvasInstance } from "@p5-wrapper/react";

interface Snowflake {
	x: number;
	y: number;
	size: number;
}

function sketch(p5: P5CanvasInstance) {
	const snowflakes: Snowflake[] = [];

	p5.setup = () => {
		p5.createCanvas(window.innerWidth, window.innerHeight);
	};

	p5.draw = () => {
		p5.background(20, 30, 50);
		p5.fill(255);
		p5.noStroke();

		if (p5.frameCount % 5 === 0) {
			snowflakes.push({
				x: p5.random(0, p5.width),
				y: 0,
				size: p5.random(2, 5),
			});
		}
		for (let i = snowflakes.length - 1; i >= 0; i--) {
			const snowflake = snowflakes[i];
			p5.ellipse(snowflake.x, snowflake.y, snowflake.size);
			snowflake.y += snowflake.size * 0.5;
			if (snowflake.y > p5.height) {
				snowflakes.splice(i, 1);
			}
		}
	};
}

export const Background = () => {
	return <ReactP5Wrapper sketch={sketch} />;
};

```

画面も雪が降っています。

![スクリーンショット 2024-12-24 0.48.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3443/489651e7-5592-815a-6bab-0451cb2d1eeb.png)

さらに画面に文字を書いたら完成です。


![スクリーンショット 2024-12-24 23.34.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3443/f7e5c309-577a-f887-00d6-daf41fafd7c0.png)

なんか簡素ですね…
もう少しビジュアルを凝りたかったのですが、今回はここまでにします。
実際に動いているのはこちらになります。

https://p5js-snow.netlify.app/


リポジトリはこちら。

https://github.com/makoto-ogata/my-p5js-test


メリークリスマ〜ス:santa_tone1:

## 参考

https://qiita.com/o8que/items/8036f0b9e37209386611

https://jp.deconbatch.com/2023/01/p5jsframerate.html

https://note.com/deconbatch/n/n0b192fc7d312