メディアアート系で重要な数式・概念 & p5.jsで遊ぶ

高校数学がボロボロでも大丈夫です。（
もともと個人的にインプットし貯めていたものですが、書きなおして公開します。
**地味ですが、派手な動きはこの地味な数式・概念がベース**になってきます。

また、メディアアートとは言ったものの、ゲーム制作などにも役立つでしょう。
「ラジアンとは？」「サイン波を描く」「円軌道を描く」「弾幕（2点間の距離系&角度系）」「多角形を描く」「フラクタル」といったテーマです。

また、そのプレイグラウンドとしてp5.js（Processingのjs版）をご紹介します。2014年にリリースされたものでまだマイナーですがCodePenのような海外サイトでは人気が出つつあります。またProcessing公式プロジェクトなので安心感もありますね。ちなみに、Processing.jsとは別プロジェクトです。

##ラジアンとは？

**・ラジアンは単位**
角度についてのもう一つの単位です。
角度とラジアンは、ドルと円みたいな違いと思っています。

・１ラジアンの定義
トリビアですが、ラジアンには弧をもとにした基準があって、
「弧の長さ = その円の半径」の時「1になる単位」だそうです。
まぁ、これ知ってもあんまり変わりません。（←）

・ラジアンの出し方
**ラジアン = 角度 * π ÷ 180**　です。
つまり角度ありきで出すことがほとんどでしょう。

JavaScriptだと 
**ラジアン = 角度 * Math.PI / 180;**

```js
var rad = 0;
var degree = 50;

rad = degree * Math.PI / 180;
console.log(rad); //0.8726646259971648

```

##まずは、サイン波を描く
サイン波は最もプリミティブなものなので、ここでサイン波の描き方を覚えておきましょう。
深く原理は分からずとも使えるようになれば大丈夫です。

ちなみに、**Sineを良く使う場面
「定期的に、ある値をふわふわ上下させたい時」**に良く使います。
ここらへんは言わずもがなかもしれません。

ここでは、うねる直線、つまりサイン波を作ります。
![circlemoving3.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/182558da-9243-39f6-86af-a719f99fef1c.gif)

以下の動きを毎フレームするイメージです。
**1 . まず、xをいくらか＋します。いくらでもOK。
2 . 角度をいくらか＋します。いくらでもOK。
3 . 角度をラジアンに変換します。
4 . yの座標をSin(ラジアン)で決定します。
5 . xとyを元にオブジェクトの座標をセットします。**

・・・よく分かりませんよね？ｗ
これだけでイメージすることは不可能かと思います。**コードを書いて数値をいじってイメージを掴んでいきます。**

コードにすると、

```js
//xをいくらか＋する
x += 1;

//角度をいくらか＋する
degree += 10;

//角度をラジアンに変換
rad = degree * Math.PI / 180;

//y座標をsin(ラジアン)で決定。最後に掛ける値で振れ幅を調整
y = Math.sin(rad) * 30;

//ポジションをセット
setPosition(x,y);
```

＋する値によってスピードや振れ幅を変えられます。
**xに＋する値を増やすとx方向のスピードが速くなり、**

```js
//x方向に速くする
x += 15;
```
![circlemoving4.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/439eb55c-c9ae-ec8d-1327-3df3c1b07367.gif)

---

**角度に＋する値を増やすとyの振れるスピードが速くなります。**

```js
//yの振れるスピードを速くする
degree += 30;
```
![circlemoving5.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/926f9285-f992-f100-a4c0-33cbaa16088d.gif)

---
また、**yに最後にかける値を大きくすると振れ幅が大きくなります。**

```js
//yの振れ幅を大きくする
y = Math.sin(rad) * 100;
```
![circlemoving6.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/14f89533-de0e-cc0d-8e3d-78a4a7c4ce04.gif)



##円軌道を描く方法
プログラミングでどうやって円を描けばいいんだ？愕然としますよね、分かります。
そんな時に覚えておくとすぐに使える数式があります。しかも**汎用性がとっても高い**です。

>
毎フレーム、角度を＋する
毎フレーム、角度をラジアンに変換する
X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)
Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)
オブジェクトを(X,Y)に移動させる

これは鵜呑みして損はありません。

JavaScriptだと、

```js
    x = centerX + radius * Math.cos(rad);
    y = centerY + radius * Math.sin(rad);
```

で、これをどう使うか？
毎フレームこんな処理をします。
**・角度を増やします
・角度をラジアンに変換します
・X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)を出す
・Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)を出す
・X,Yをもとに座標をセット**

JavaScriptだと、

```js
//角度を増やします
degree += 3;

//角度をラジアンに変換します
rad = degree * Math.PI / 180;

//X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)を出す
x = centerX + radius * Math.cos(rad);

//Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)を出す
y = centerY + radius * Math.sin(rad);

//X,Yをもとに座標をセット
setPosition(x,y);
```


そうすると・・・
![circlemoving10.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/7b97cc3d-c190-3882-46a7-5273bc890111.gif)

使い方としては、**毎フレーム、角度が増えるほど円における位置が進んでいくことをイメージ**しておくと良いと思います。



また、半径を毎フレーム長くすると螺旋を描いたり、

```js
//半径を毎フレーム長くする
radius += 1;
```
![circlemoving16.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/af6c7ba7-6a80-efe4-60ca-08c1df010a58.gif)



---
さらに・・・さっきのサイン波が活躍しだします。今後ずっと活躍します。
半径をサイン波で上下させるとウネウネします。

```js
//半径をサイン波で上下させる
sinFactor += 0.1;
radius += Math.sin(sinFactor) * 10;
```
![circlemoving19.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/700b0481-4be9-d6a5-af3d-0c19ad8d1948.gif)

---
あとは角度をサイン波で上下させるとこんな風になったり・・・

```js
//角度をサイン波で上下させる
sinFactor += 0.04;
rad += Math.sin(sinFactor) * 3;
```
![circlemoving20.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/7981cf49-3575-e17a-3064-29d545bcf05f.gif)

値を色々変えてイメージを掴んでいきましょう。
**足す角度を増やすと速くなる、半径を足すと螺旋になる、**ここらへんは分かりやすいのでやってみましょう。
イメージが掴めたら、テキトーに値をいじってみましょう。

関係なさそうな値もいじってみましょう。
たとえば中心の座標を毎フレームずらしてみるとかですね。




##そして弾幕へ・・・
サイン波、円の描き方、弾幕へ行きましょう。
![circlemoving24.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/c80e4517-801e-0abb-5d1a-41429ff995de.gif)

弾幕の仕組みは↓に書いたので割愛します。
こっちでは2点間の距離の公式とかも出てきます。

弾幕の初歩（距離系と角度系）
http://qiita.com/hp0me/items/1164bf9669a825d76ffa

##多角形をどうやって描くか？
先ほどの円の公式を活用します。ここでは6角形を描くとします。
まず、円の1周すなわち360度を6角形の6で割ります。 = 60度
そして、**先ほどの円の周り方で60度ごとにプロットを（座標で）打っていきます。
ここでプロットを配列にpushしていきましょう。**

配列にはこんな感じで値が入るはずです。
配列 = [0度の座標,60度の座標,120度の座標,180度の座標,240度の座標,300度の座標]

これを結びます。
まずは、0度の座標と60度の座標を線で結びます。
その後は60度と120度の座標を結んで・・・
どうでしょうか？

今回、長くなってしまったのでコードは割愛します。
時間が出来たら加筆しますね・・・

##そしてフラクタルへ・・・
先ほどの多角形の書き方（プロットを保存して、線でむすぶ）を応用してフラクタルを書きます。
ここでは三角形の中に三角形ができるフラクタルを作ってみます。
ここからはちょっとややこしいかもしれませんが

順番はこんな感じ
**・三角形を描く （できたプロットはA,B,Cとする）
・A , AとBの中点 , AとCの中点の3点を結んで三角形を作る**

ひたすらこれを入れ子（ネスト）で繰り返します。
これができていればどんなコードでもOKです。
これも需要があればコードを加筆する予定・・・

応用すればアニメーションもできるでしょう。
ちなみに「動くフラクタル 8角形」っていうのを作ってみました。
http://jsdo.it/hp0me_/ycrm
![circlemoving9.gif](https://qiita-image-store.s3.amazonaws.com/0/57193/e7f573aa-25ed-a840-dd43-c2c7ecda0af7.gif)


##最新のプレイグラウンド = p5.jsで遊ぶ
**Processingはなんか今っぽくない、かといってCanvasはなんかちょっと足りない・めんどい、Three.jsはちょっとめんどい、といったニーズを解決するのがProcessingから派生したp5.js（Processing公式プロジェクト）です。**
ここで紹介したような数式・概念を試すにはぴったりです。

ちなみにp5.jsはProcessing.jsとは別プロジェクトです。所感としてProcessing.jsはなんかイケてないなと思っていたのですが、p5.jsはイケてます。
また、**マイクのインプットなど、ちょっとしたAPIも多数あります。**

公式サイトのGetStartedを参考にはじめます。
http://p5js.org/get-started/

p5.jsの基本はsetup()とdraw()です。
**setup()は最初に呼ばれる関数**です。
よくあるinit、またはUnityのStart()にも似ています。
**draw()は毎フレーム呼ばれる関数**です。何かを動かしたいときはここで操作します。
JSのSetTimeOut()、UnityのUpdateに似ています。

また、height（キャンバスの高さ）やwidth（キャンバスの幅）など便利な変数がグローバルで最初からセットされています。これは何気に便利。くわしくはリファレンス（[http://p5js.org/reference/](http://p5js.org/reference/)）にて。

```js
var n = 0;

function setup() {
  //最初に呼ばれます
  console.log("スタート");

  //Canvasを作る
  createCanvas(500, 500);
}

function draw() {
  //毎フレーム呼ばれます。
  n++;
  console.log(n);
}
```

また、基本関数として、図形を描くために
ellipse(x,y,縦の大きさ,横の大きさ);
これで円を描けることはまず覚えておきます。

p5.jsで円軌道を描いてみましょう。先ほどの、
>
毎フレーム、角度を＋する
毎フレーム、角度をラジアンに変換する
X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)
Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)
オブジェクトを(X,Y)に移動させる

を使います。


```js
var circle;
var speed = 30;
var radius = 100;

//最初に呼ばれる
function setup() {
  createCanvas(500, 500);
  circle = new MyCircle();
}

//毎フレーム呼ばれる
function draw() {
  background(255);//再描画
  circle.move();
}

//円のクラス
function MyCircle(){

  this.x = width/2;
  this.y = height/2;
  this.degree = 0;
  this.rad = 0;
  this.radius = radius;

  this.move = function(){
    //角度を増やします
    this.degree += 3;

    //角度をラジアンに変換します
    this.rad = this.degree * Math.PI / 180;

    //X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)を出す
    this.x = width/2 + this.radius * Math.cos(this.rad);

    //Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)を出す
    this.y = height/2 + this.radius * Math.sin(this.rad);

    //X,Yをもとに座標をセット
    ellipse(this.x,this.y,30,30);
  };
}

```

---
**さらに、p5.jsで弾幕を書いてみました。**クリックで打ちます。
http://jsdo.it/hp0me_/zlLi


```js

//弾が格納される配列
var circles = [];

//弾
var cir;

//初期座標(bulletX,bulletY)からangleの角度へ移動
var bulletX = 0;
var bulletY = 0;

//弾速
var speed = 3;


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

function draw() {
  background(255);

  //弾の分だけループ
  for(var i = 0;i<circles.length;i++){
    circles[i].move();
  }

}

function mouseClicked() {
  //弾の分だけループ
  for(var i = 0;i<20;i++){
    cir = new MyCircle(i * 5 +45);
    circles.push(cir);
  }
  return false;
}


//弾幕クラス
function MyCircle(anglee){

  this.x = width/2;
  this.y = 10;
  this.angle = anglee;
  this.vx = Math.cos(Math.PI / 180 * this.angle) * speed;
  this.vy = Math.sin(Math.PI / 180 * this.angle) * speed;

  this.move = function(){
    this.x += this.vx;
    this.y += this.vy;
    fill(0);
    ellipse(this.x,this.y,10,10);
  };
}
```


p5.jsの最大のメリットは、**面倒なCanvasの前準備をせずにいきなりCanvasのアルゴリズムに集中できる**ところです。余談ですが、意外にも（？）これに近いのはCocos2d-jsやenchant.jsといったゲーム系エンジンじゃないでしょうか？

そしてp5.jsで作ったコードはjsdo.itに投稿すれば面白いですね。
実際に投稿してみました。
http://jsdo.it/hp0me_

##後記
これも重要かな、これは間違ってるよ、などあれば教えてください
こちらにコメント or mail : hp0isme@gmail.com


##2015.11.27追記
p5.jsが3Dに対応したようです（10月）。軽くいじってまとめました。
「p5.jsがWebGL＆3D対応。軽くいじってみます」
http://qiita.com/hp0me/items/1570694d9f61368f3ae6

##p5.jsでグローバル汚染を回避するには（2015.12.22追記）
Processingスタイルのグローバル汚染が気になる場合、インスタンスモードで回避できるようです。
「p5.js を instance mode で使う」
http://qiita.com/turusuke/items/c92a13602523d6378cc0