高校数学がボロボロでも大丈夫です。(
もともと個人的にインプットし貯めていたものですが、書きなおして公開します。
地味ですが、派手な動きはこの地味な数式・概念がベースになってきます。
また、メディアアートとは言ったものの、ゲーム制作などにも役立つでしょう。
「ラジアンとは?」「サイン波を描く」「円軌道を描く」「弾幕(2点間の距離系&角度系)」「多角形を描く」「フラクタル」といったテーマです。
また、そのプレイグラウンドとしてp5.js(Processingのjs版)をご紹介します。2014年にリリースされたものでまだマイナーですがCodePenのような海外サイトでは人気が出つつあります。またProcessing公式プロジェクトなので安心感もありますね。ちなみに、Processing.jsとは別プロジェクトです。
##ラジアンとは?
・ラジアンは単位
角度についてのもう一つの単位です。
角度とラジアンは、ドルと円みたいな違いと思っています。
・1ラジアンの定義
トリビアですが、ラジアンには弧をもとにした基準があって、
「弧の長さ = その円の半径」の時「1になる単位」だそうです。
まぁ、これ知ってもあんまり変わりません。(←)
・ラジアンの出し方
ラジアン = 角度 * π ÷ 180 です。
つまり角度ありきで出すことがほとんどでしょう。
JavaScriptだと
ラジアン = 角度 * Math.PI / 180;
var rad = 0;
var degree = 50;
rad = degree * Math.PI / 180;
console.log(rad); //0.8726646259971648
##まずは、サイン波を描く
サイン波は最もプリミティブなものなので、ここでサイン波の描き方を覚えておきましょう。
深く原理は分からずとも使えるようになれば大丈夫です。
ちなみに、**Sineを良く使う場面
「定期的に、ある値をふわふわ上下させたい時」**に良く使います。
ここらへんは言わずもがなかもしれません。
以下の動きを毎フレームするイメージです。
1 . まず、xをいくらか+します。いくらでもOK。
2 . 角度をいくらか+します。いくらでもOK。
3 . 角度をラジアンに変換します。
4 . yの座標をSin(ラジアン)で決定します。
5 . xとyを元にオブジェクトの座標をセットします。
・・・よく分かりませんよね?w
これだけでイメージすることは不可能かと思います。コードを書いて数値をいじってイメージを掴んでいきます。
コードにすると、
//xをいくらか+する
x += 1;
//角度をいくらか+する
degree += 10;
//角度をラジアンに変換
rad = degree * Math.PI / 180;
//y座標をsin(ラジアン)で決定。最後に掛ける値で振れ幅を調整
y = Math.sin(rad) * 30;
//ポジションをセット
setPosition(x,y);
+する値によってスピードや振れ幅を変えられます。
xに+する値を増やすとx方向のスピードが速くなり、
//x方向に速くする
x += 15;
角度に+する値を増やすとyの振れるスピードが速くなります。
//yの振れるスピードを速くする
degree += 30;
また、yに最後にかける値を大きくすると振れ幅が大きくなります。
//yの振れ幅を大きくする
y = Math.sin(rad) * 100;
##円軌道を描く方法
プログラミングでどうやって円を描けばいいんだ?愕然としますよね、分かります。
そんな時に覚えておくとすぐに使える数式があります。しかも汎用性がとっても高いです。
毎フレーム、角度を+する
毎フレーム、角度をラジアンに変換する
X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)
Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)
オブジェクトを(X,Y)に移動させる
これは鵜呑みして損はありません。
JavaScriptだと、
x = centerX + radius * Math.cos(rad);
y = centerY + radius * Math.sin(rad);
で、これをどう使うか?
毎フレームこんな処理をします。
・角度を増やします
・角度をラジアンに変換します
・X座標 = 円の中心のX座標 + 半径 × Cos(ラジアン)を出す
・Y座標 = 円の中心の中心Y座標 + 半径 × Sin(ラジアン)を出す
・X,Yをもとに座標をセット
JavaScriptだと、
//角度を増やします
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);
使い方としては、毎フレーム、角度が増えるほど円における位置が進んでいくことをイメージしておくと良いと思います。
また、半径を毎フレーム長くすると螺旋を描いたり、
//半径を毎フレーム長くする
radius += 1;
さらに・・・さっきのサイン波が活躍しだします。今後ずっと活躍します。
半径をサイン波で上下させるとウネウネします。
//半径をサイン波で上下させる
sinFactor += 0.1;
radius += Math.sin(sinFactor) * 10;
あとは角度をサイン波で上下させるとこんな風になったり・・・
//角度をサイン波で上下させる
sinFactor += 0.04;
rad += Math.sin(sinFactor) * 3;
値を色々変えてイメージを掴んでいきましょう。
**足す角度を増やすと速くなる、半径を足すと螺旋になる、**ここらへんは分かりやすいのでやってみましょう。
イメージが掴めたら、テキトーに値をいじってみましょう。
関係なさそうな値もいじってみましょう。
たとえば中心の座標を毎フレームずらしてみるとかですね。
##そして弾幕へ・・・
サイン波、円の描き方、弾幕へ行きましょう。
弾幕の仕組みは↓に書いたので割愛します。
こっちでは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
##最新のプレイグラウンド = 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/)にて。
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)に移動させる
を使います。
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
//弾が格納される配列
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 : [email protected]
##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