p5.jsの関数まとめ part.13 beginContour() ~トライフォースを作ろう~

この記事は Qiita p5js アドベントカレンダー18日目の記事です。

## これはなに
p5.jsが用意している関数について理解を深める記事です。
今回はVertexのbeginContour()について。

## Vertexとは
通常のShapeが持つ関数とは異なる、少し複雑な図形を描画したい時に使用するもので、
`beginShape()`と`endShape()`の間に`vertex(x, y)`で頂点を指定し、図形を作ります。
[【p5.js】beginShapeとvertex関数](https://qiita.com/shibuya01055/items/8ed83b9c13cfb2754999)

## beginContour()
図形の型抜き？を行う関数で、beginShape()の中で使用する関数です。

### リファレンスより
> beginContour()とendContour()関数を使用して、文字「O」の中心のような形状の中に負の形状を作成します。beginContour()は形状の頂点の記録を始め、endContour()は記録を停止させます。負の形状を定義する頂点は、外側の形状とは反対の方向に「巻く」必要があります。まず、時計回りに外側の頂点を描画し、次に反時計回りに内部の頂点の形状を描画します。
>
>これらの関数は beginShape()/endShape() の組の中でしか使用できず、 translate(), rotate(), scale() などの変換は beginContour()/endContour() の組の中では機能しない。また、ellipse()やrect()などの他の形状を使用することもできません。（DeepL翻訳）

beginShapeと同様に中では使用できない関数がいくつかるようですね。
vertexで頂点を指定していくようです。
また必ず`endContour`で終了させる必要があります。

また外側は時計回り、beginContour()の中は反時計回りなことも注意が必要です。
下記の記事が分かりやすかったです。
これなんでなんだろ...
[P5.js 日本語リファレンス(beginContour)](https://qiita.com/bit0101/items/8be1eacd64819413411b)

### Type
```typescript
beginContour(): p5;
endContour(): p5;
```


### 使ってみる
型抜きで思いついたのがゼルダの伝説のトライフォースだったので、これを作ってみましょう。
これは見事な型抜き感です。
![トライフォース.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/b51a6317-a180-3746-3479-68ad7f0c4d47.png)


まずbeginShape()で正三角形を作ります。
正三角形の作り方はこちらの記事を参考にさせていただきました。
http://blog.livedoor.jp/reona396/archives/55107577.html

```javascript
function setup() {
  createCanvas(600, 600);	
  background(0)
}

r = 100

function draw() {
  translate(width / 2, height / 2)
  rotate(radians(-90));
  beginShape()
  for (let i = 0; i < 3; i++) {
    vertex(r*cos(radians(360*i/3)), r*sin(radians(360*i/3)));
  }
  endShape()
}
```
![スクリーンショット 2021-12-17 12.10.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/c950df2f-021e-35fe-e985-b70596cb2c25.png)


そしたら真ん中に逆三角形の穴を開けます。
ちょっと苦戦しましたがこれでいけました！

```javascript
function draw() {
  translate(width / 2, height / 2)
  rotate(radians(-90));
  beginShape()
  for (let i = 0; i < 3; i++) {
    vertex(r*cos(radians(360*i/3)), r*sin(radians(360*i/3)));
  }
  
  beginContour()
  for (let i = 0; i < 3; i++) {
    vertex(-r/2*cos(radians(360*i/3)), r/2*sin(radians(360*i/3)));
  }
  endContour()
  endShape()
}
```
![スクリーンショット 2021-12-17 12.40.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/0acc190c-3763-ec16-498a-e31303bd05c3.png)

そしたら最後にfill()で色をつけます。
beginContour()の中は穴が空いているので色付けされません。

```javascript
function draw() {
  translate(width / 2, height / 2)
  rotate(radians(-90));
  fill('gold') // 追加
  beginShape()
  for (let i = 0; i < 3; i++) {
    vertex(r*cos(radians(360*i/3)), r*sin(radians(360*i/3)));
  }
  
  beginContour()
  for (let i = 0; i < 3; i++) {
    vertex(-r/2*cos(radians(360*i/3)), r/2*sin(radians(360*i/3)));
  }
  endContour()
  endShape()
}
```
![スクリーンショット 2021-12-17 12.52.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/0a316f68-fa50-b882-5bf6-6629bc5eea01.png)


トライフォースの完成！
やったー！


## 参考
[p5.js reference | beginContour()()](https://p5js.org/reference/#/p5/beginContour)
[Processing で三角形を描く](http://blog.livedoor.jp/reona396/archives/55107577.html)
[P5.js 日本語リファレンス(beginContour)](https://qiita.com/bit0101/items/8be1eacd64819413411b)