CoffeeScript – Boids

Boidsとは

Boidsは鳥や魚が群をなして移動する様をシミュレートするもので、概要はこちらにまとめている

一つ一つの個体は、一定の行動規範に従って「自律的に」動いていながら、全体が群として整然と運動することを再現する。

CoffeeScriptによるBoidsの開発

以下のステップで開発を進める。

  1. Boids 1.xのシリーズで、個体の生成・表示、運動、壁の回避などを実装
  2. Boids 2.xのシリーズで、最もシンプルな運動ルールを個体に与える
  3. Boids 3.xのシリーズで、「敵」を導入する
  4. アプリケーション版

 

スクリプトへの引数渡し

たとえば以下のような場合。

  • CoffeeScript、Javascriptの外部スクリプトに引数を渡したい
  • 外部スクリプトの定数定義を柔軟に変更可能なようにしたい

定数となる変数定義をスクリプト内に書くと、定数の値を変更したいときに再コンパイルやアップロードなどが必要になって煩雑。

以下の方法が考えられる。

  • HTMLの外部スクリプト呼び出しより前に、変数定義のscript要素を書く(変数のスコープはグローバルになる)
    • その際、行の末尾にセミコロン(;)をつけること
  • 外部スクリプト内で上で定義した変数を利用する

HTML

外部スクリプト

CoffeeScriptも実行時にはJSにコンパイルしたものを読み込むので、変数定義もJavascriptの文法で末尾にセミコロン(;)をつけなければならない。

上の例では、定数を意識して変数名を大文字のスネークケースとしたが、通常の変数名でも実行に問題はない。

 

CoffeeScript – geom2dパッケージ

パッケージ名

taustation_geom2d

クラス

taustation_geom2d.Vector
2次元ベクトルを保持し、各種演算を行うメソッドを提供する。
taustation_geom2d.MovingAgent
位置と速度を保持し、互いの位置関係を判定するメソッドを提供する。

コードの骨組み

 

CoffeeScript – geom2d.Vectorクラス

パッケージ

taustation_geom2d

クラス名

taustation_geom2d.Vector

クラス仕様

概要

x、y二つの成分を持ち、絶対値の計算や加減乗算など2次元ベクトルの代数演算を行うメソッドを提供する。

クラス変数

なし

クラス・メソッド

distance(pos1, pos2)
2つのVectorオブジェクトpos1、pos2を点を表す位置ベクトルとして、2点間の距離を返す。

インスタンス・プロパティ

x
ベクトルのx成分
y
ベクトルのy成分

コンストラクタ

constructor(x, y)
x成分とY成分を指定してVectorのインスタンスを生成する。

インスタンス・メソッド

基本メソッド

set(x, y)
Vectorのx成分とy成分をセットする。
toString()
Vectorの文字列形式の表現を返す。
getClone()
元のVectorオブジェクトと同じ内容のクローンを生成して返す。

演算

abs
Vectorの絶対値(長さ)を返す。
times(coeff)
Vectorに定数coeffを乗じたベクトルを新たに生成して返す。
timesEq(coeff)
Vectorに定数coeffを乗じて変更する。新しいオブジェクトは生成しない。
div(coeff)
Vectorを定数coeffで除したベクトルを新たに生成して返す。
divEq(coeff)
Vectorを定数coeffで除して変更する。新しいオブジェクトは生成しない。
plus(other)
Vectorにotherベクトルを加えたベクトルを新たに生成して返す。
plusEq(other)
Vectorにotherベクトルを加えて変更する。新しいオブジェクトは生成しない。
minus(other)
Vectorからotherベクトルを減じたベクトルを新たに生成して返す。
minusEq(other)
Vectorからotherベクトルを減じて変更する。新しいオブジェクトは生成しない。
inprod(other)
Vectorとotherベクトルの内積値を返す。
ang(other)
Vectorとotherのなす角を計算する(0~π)。

新たなVectorの生成

getUnit()
Vectorと同じ向きの単位ベクトル(長さが1)を新たに生成して返す。
getInverse()
Vectorと逆向きのベクトルを新たに生成して返す。
getOrthogonalR()
Vectorから右に90度回転したベクトルを新たに生成して返す。
getOrthogonalL()
Vectorから左に90度回転したベクトルを新たに生成して返す。
getUnitOrthogonalR()
Vectorから右に90度回転した単位ベクトルを新たに生成して返す。
getUnitOrthogonalL()
Vectorから左に90度回転した単位ベクトルを新たに生成して返す。

判定

isHeadingToRightOf(other)
このVectorオブジェクトの進行方向が、引数のVectorオブジェクトotherの進行方向より右方を指しているときtrue、左方を指しているときfalseを返す。
isHeadingToLeftOf(other)
isHeadingToRightOf()と左右逆の判定結果を返す
isInFrontOf(movingAgent)
このVectorオブジェクトが位置ベクトルとして、その点が引数のMovingAgentオブジェクトの前方(左右180度より進行方向の側)にあるときtrue、後方にあるときfalseを返す。真横の時は前方と判定される。
isIntheRearOf(movingAgent)
isInFrontOf()と前後逆の判定結果を返す。
isOnTheRightOf(movingAgent)
このVectorオブジェクトが位置ベクトルとして、その点が引数のMovingAgentオブジェクトの右方にあるときtrue、左方にあるときfalseを返す。進行方向の延長線上にあるときは右方と判定される。
isOnTheLeftOf(movingAgent)
isOnTheRightOf()と左右逆の判定結果を返す。

コード

 

CoffeeScript – グローバル変数

グローバルにならない

CoffeeScriptでグローバル変数を期待して以下のように書いたとする。

一見すると問題なく動いているように見えるが、これを別ファイルのパッケージにして動かそうとすると問題が顕在化する。以下のように”globalVarが存在しないよ”というエラーが出るのである。

これら2つのファイルをjsにコンパイルしてブラウザのscript要素で読み込んだ場合、そのイメージは以下のようになる。

パッケージでグローバル定義したつもりだが、コンパイル時に無名関数でクロージングされるため、グローバルにならず、他のファイルから読み込むことができない。

解決策1

グローバル変数をwindowオブジェクトの要素にしてしまう。

解決策2

rootコンテキストで、以下のパターンを使う。

 

WordPress – Faviconの追加

概要

WordPressで作っているサイトのアイコン(ブラウザのお気に入りなどで表示される小さいアイコン)が透過色の書類マークのままで殺風景なので、自分用のFaviconを作って適用してみた。

Faviconとは、Favorite Iconの略だそうである。

アイコン画像の準備

アイコン画像を作成し、透過色を指定してPNGやGIFで保存する。

今回は、PowerPointで作成した図柄をPNG形式で保存し、ペイントアプリケーションで切り取ってPNG形式で保存。

透過色の指定は、Exce使った方法で行った。

icoファイル化

FavIcon from Picsというサイトで、PNGファイルをicoファイル化。Webサイトにファイルをアップロードし、変換されたファイルをダウンロード。

WordPressへのFaviconの登録

Faviconファイルやその元となったファイルをWordPressのメディアに登録。

テーマのheader.phpを編集する方法とプラグインを利用する方法があるが、今回はFavicon Rotatorというプラグインを使った。

Favicon RotatorをインストールするとWordPressの”外観”メニューに”Favicon”メニューが追加されるので、それをクリック。

ファイルを新たにアップロードするとメディアに追加されるが、ここでは先にメディアに追加済のicoファイルを指定。

これでお気に入りに表示されるFaviconが変更される。

 

WordPressでCanvas要素が消える

消えるcanvas

WordPressのテキストモードでcanvas要素を書いて、ビジュアルモードに切り替えてもう一度テキストモードに戻ったとき、canvas要素が消えてしまうことがあった。

いろいろと試しているうちに、以下のような挙動があることがわかってきた。

  • <canvas>タグと</canvas>タグを直接一行でつないだ時に消えるらしい
  • canvas要素の前後が空行かどうかでも結果が変わるらしい

そこで、タグの書き方と前後の空行の入れ方の組み合わせで、canvasが消えるかどうかをチェックした。

canvasが消える条件

<canvas></canvas>のように開始タグと改行タグが連続して書かれていて、なおかつ以下のケースの時にcanvas要素が消える。

ケース1:ファイルの中に単独で書いた場合

開始タグと終了タグが<canvas></canvas>のように連続しており、それのみがファイルの中に書かれている場合、ビジュアルエディタを経由すると要素が消える。行末の改行があってもなくても結果は同じ。

ケース2:前後に空行がある場合

開始タグと終了タグが<canvas></canvas>のように連続しており、その行の前後に空行がある場合、ビジュアルエディタを経由すると要素が消え、&nbspに書き換えられる。

実質的にファイルの中にcanvas要素のみがあることは稀なので、問題となるのは上記の”<canvas></canvas>の前後に空行がある場合”となる。

canvasが消えない条件

canvasが消えない条件は、上の「canvasが消える条件」の裏返しも含めて以下のようになる。

ケース1:開始タグと終了タグの間に文字があること

開始タグと終了タグの間に文字があれば、周辺条件がどうであってもcanvas要素は消えない。

canvas要素非対応のブラウザ対応のために、この方針をとることには意義がある。

ただし、間にある文字がスペースだけの場合は意味がなく、開始タグと終了タグが連続している場合と同様の結果になる。

ケース2:開始タグと終了タグの間で改行されていること

開始タグと終了タグの間で改行されていれば、周辺状況がどうであってもcanvas要素は消えない。

canvas要素内に文を書かない場合は、簡易な一つの解決策。

ただし、開始タグと終了タグの間に空行が入っている場合は結果は複雑で、要素全体が消えたり、いずれかのタグだけが消えたりと結果は複雑になる。

ケース3:前後に空行がないこと

前後に行があれば(どちらも空行でなければ)開始タグと終了タグが連続していてもcanvas要素は消えない。

ただし、確実にこの記述方法に拠ることを担保しがたい。

結論

以下の2つのうちいずれかを推奨。

  • 開始タグと終了タグの間にcanvas非対応用の文を書く
  • 開始タグ<canvas>の後で改行し、すぐ次の行に終了タグ</canvas>を書く

 

Windows – 透過色の図形

Windowsで透過色を含んだpngやgifファイルを作成するのに、同梱アプリケーションの「ペイント」では、疑似的にしか再現できない。

ネット上で調べると、以下のような方法があることがわかったので記録。

  1. 「ペイント」などで図形を描いて保存(pngやgifで)
  2. 図形ファイルをExcelで読み込み
  3. 「書式」→「色の変更」→「透過色を指定」
  4. 透過色に変更したい色の部分をクリック
  5. web形式で保存し、必要なファイルを取り出す

 

CoffeeScript – パッケージ管理

パッケージ化の方法について

簡単な方法~齟齬あり

クラス/オブジェクトのプロパティにする

クラスやオブジェクトをパッケージの名前とし、パッケージ内のクラスなどはそのプロパティとして定義する。

ただしこの方法は、最適とは言えない。

1行目で名前空間に用いるクラスを定義し、7行目でMyClassPack1のプロパティとしている。

10行目で名前空間に用いるオブジェクトを定義し、16行目でMyClassPack2のプロパティとしている。

20行目でMyClass単独を用いた場合、直前に13行で定義されたMyClassが参照される。

パッケージ内での名前参照の祖語

パッケージ間で名前が重複する場合、下手をすると想定外のオブジェクトが使われてしまう。

次の例は、Pack1Pack2の2つのパッケージで同じクラス名を使い、各パッケージの中ではパッケージ名なしで使おうとしたもの。

ところが29行目で、Pack1のクラスのはずのところがInnerClassにはPack2のものが使われてしまっている。

これは、25行目以降の実行文の前にグローバル変数InnerClassの内容Pack1のものからPack2のものへと上書き定義されたため。

結局この方法だと、各パッケージの中でもクラス名の前にパッケージ名をつけないといけないようで、コーディング上は元のクラス名に識別子を組み込むのとあまり変わらない。

有効な方法~即時実行関数

先の方法は、すべてグローバル領域で行われていたため、パッケージ内でのみ参照するクラスも上書きされてしまった。

そこで、パッケージごとに即時実行される無名関数で括ってみる。

1行目のようにグローバル領域でパッケージ名に使うオブジェクト/クラスを定義し、パッケージごとに即時無名関数で括る。

パッケージ内ではパッケージなしでアクセスし、外からアクセスするときはパッケージ名を付してアクセス。

これで一応、パッケージ化とコーディングの簡易化を両立させることができる。

パッケージ名について

パッケージ名は、「世界規模での名前衝突を避ける」ように潔癖を極めるなら、Javaで行われているようなドメイン名管理が答となる。

なお、Javaの場合はimport文で指定したパッケージはクラス名のみで使えるが、Javascriptではエイリアスを明示的に指定しなければならないらしい。

JavaScriptスタイルガイドでは、「長い型名をエイリアスし可読性を向上させる」ために以下のように示唆されている。

“ローカルのエイリアスを使うことで長い型名の可読性を向上できる場合はそうしてください. エイリアスの名前は型名の最後の部分にしてください.”

なお、npmのサイトでいろいろなパッケージを見てみると、区切りにはアンダースコア(_)ではなくマイナス(-)を使っている。

 

CoffeeScript – タイマ

setInterval

setInterval()関数の引数に、アニメーションフレームを描画する関数と時間間隔を指定する。時間間隔はミリ秒単位。

描画の開始/停止をコントロールするには、setInterval()関数の戻り値を変数に保存しておき、停止するときにclearInterval()関数の引数でその変数を指定する。

一時停止/再開の機能は特に実装されていないが、描画関数を工夫することで可能。

描画関数を、以下のように無名関数で書くこともできる。

この処理を他のオブジェクトのメソッドの中に書いて、オブジェクトのプロパティを利用する場合は、1行目のアローをファットアロー(=>)にする。