[TypeScript][WebGL][Three.js] Boids (an artificial life program) —shoal simulator written in TypeScript—
Boids とは
Boids は、Craig Reynolds 氏によって作られた人工生命のシミュレーションだ。
Boid の名は、「Bird (鳥) oid (もどき)」から来ており、元は鳥の群れの動きを真似ている。
それぞれの個体を次に上げる 3 つの規則にしたがって動かすというだけで、群れのような動きを実現している:
Boids の 3 つの規則 | ||
---|---|---|
分離 (Separation): | 近くの仲間にぶつからない方向に移動 | |
整列 (Alignment): | 近くの仲間が平均的に向かっている方に向かう | |
集結 (Cohesion): | 近くの仲間の中心方向に移動する |
参考ページ
デモ
TypeScript などで Boids のデモを 3 種類作成してみた。
鳥の群れではなく、魚の群れを意識した。
※ 各画像をクリックするとそれぞれのページへ飛ぶ
2D版では2次元ベクトル、3D版では3次元ベクトルで、個体の位置や速度を計算している。
2つの3D版は、Three.js というライブラリーを使って WebGL で動かしている。
参考:
- [TypeScript][WebGL][Three.js] 3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~ ― 準備編 | プログラミング C# – 翔ソフトウェア (Shos) (Japanese)
- [TypeScript][WebGL][Three.js] 多体問題シミュレーション WebGL版 | プログラミング C# – 翔ソフトウェア (Shos) (Japanese)
3D 裸眼立体視版は、裸眼立体視 (交差法または平行法) ができる人向けだ。
立体視の方法については、次のページなどが参考になる。
参考:
なお、各版ともパラメーターを色々と変更できるので試してほしい。
これらのデモ ページの実装については、ソースコードを参照してほしい。
ソースコード
ソースコードは、GitHub に上げた:
開発環境/言語/ライブラリー
以下を使って作った:
Visual Studio Code
上記デモは、Visual Studio Code 上で作成した。
Visual Studio Code は、プログラミングに最適な Microsoft 製のテキスト エディターで、Windows 版、macOS 版、Linux 版がある。
HTML や CSS はもちろんのこと、JavaScript や TypeScript、C# などの多種多様なプログラミング言語にも対応している。
Git クライアント、ビルド、シンタックス ハイライト、リファクタリング、インテリセンスなどの機能を持ち、とても使いやすいのでお薦めだ。
どのような機能や言語が使えるかは、Extensions for Visual Studio family of products | Visual Studio Marketplace が参考になる。
参考:
TypeScript
TypeScript は、設定を変えることにより、”ES3″、”ES5″、”ES2015″、”ES2016″、”ES2017″、”ES2018″、”ES2019″ にコンパイルすることができる。
デモでは、”ES5″ を使っている。
TypeScript のコンパイル オプションは、”tsconfig.json”というファイルで行う。
今回は次のような内容とした。
tsconfig.json
{
"compilerOptions": {
/* Basic Options */
"target": "ES5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"sourceMap": true, /* Generates corresponding '.map' file. */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
/* Module Resolution Options */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
}
}
TypeScript は、Visual Studio Code から簡単に JavaScript にコンパイルできる。
ちなみに、次のような TypeScript の場合:
class Vector3D {
x: number;
y: number;
z: number;
get absoluteValue(): number {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
constructor(x: number = 0, y: number = 0, z: number = 0) {
this.x = x;
this.y = y;
this.z = z;
}
clone(): Vector3D {
return new Vector3D(this.x, this.y, this.z);
}
plus(another: Vector3D): Vector3D {
return new Vector3D(this.x + another.x, this.y + another.y, this.z + another.z);
}
plusEqual(another: Vector3D): void {
this.x += another.x;
this.y += another.y;
this.z += another.z;
}
minus(another: Vector3D): Vector3D {
return new Vector3D(this.x - another.x, this.y - another.y, this.z - another.z);
}
minusEqual(another: Vector3D): void {
this.x -= another.x;
this.y -= another.y;
this.z -= another.z;
}
multiply(value: number): Vector3D {
return new Vector3D(this.x * value, this.y * value, this.z * value);
}
innerProduct(another: Vector3D): Vector3D {
return new Vector3D(this.x * another.x, this.y * another.y, this.z * another.z);
}
divideBy(value: number): Vector3D {
return new Vector3D(this.x / value, this.y / value, this.z / value);
}
divideByEqual(value: number): void {
this.x /= value;
this.y /= value;
this.z /= value;
}
getDistance(another: Vector3D): number {
return this.minus(another).absoluteValue;
}
}
“ES5” でコンパイルしてできた JavaScript はこんな感じ:
"use strict";
var Vector3D = /** @class */ (function () {
function Vector3D(x, y, z) {
if (x === void 0) { x = 0; }
if (y === void 0) { y = 0; }
if (z === void 0) { z = 0; }
this.x = x;
this.y = y;
this.z = z;
}
Object.defineProperty(Vector3D.prototype, "absoluteValue", {
get: function () {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
},
enumerable: true,
configurable: true
});
Vector3D.prototype.clone = function () {
return new Vector3D(this.x, this.y, this.z);
};
Vector3D.prototype.plus = function (another) {
return new Vector3D(this.x + another.x, this.y + another.y, this.z + another.z);
};
Vector3D.prototype.plusEqual = function (another) {
this.x += another.x;
this.y += another.y;
this.z += another.z;
};
Vector3D.prototype.minus = function (another) {
return new Vector3D(this.x - another.x, this.y - another.y, this.z - another.z);
};
Vector3D.prototype.minusEqual = function (another) {
this.x -= another.x;
this.y -= another.y;
this.z -= another.z;
};
Vector3D.prototype.multiply = function (value) {
return new Vector3D(this.x * value, this.y * value, this.z * value);
};
Vector3D.prototype.innerProduct = function (another) {
return new Vector3D(this.x * another.x, this.y * another.y, this.z * another.z);
};
Vector3D.prototype.divideBy = function (value) {
return new Vector3D(this.x / value, this.y / value, this.z / value);
};
Vector3D.prototype.divideByEqual = function (value) {
this.x /= value;
this.y /= value;
this.z /= value;
};
Vector3D.prototype.getDistance = function (another) {
return this.minus(another).absoluteValue;
};
return Vector3D;
}());
class がないので、prototype と function での実装だ。
一方、”ES2019″ でコンパイルしてできた JavaScript はこんな感じ:
"use strict";
class Vector3D {
constructor(x = 0, y = 0, z = 0) {
this.x = x;
this.y = y;
this.z = z;
}
get absoluteValue() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
clone() {
return new Vector3D(this.x, this.y, this.z);
}
plus(another) {
return new Vector3D(this.x + another.x, this.y + another.y, this.z + another.z);
}
plusEqual(another) {
this.x += another.x;
this.y += another.y;
this.z += another.z;
}
minus(another) {
return new Vector3D(this.x - another.x, this.y - another.y, this.z - another.z);
}
minusEqual(another) {
this.x -= another.x;
this.y -= another.y;
this.z -= another.z;
}
multiply(value) {
return new Vector3D(this.x * value, this.y * value, this.z * value);
}
innerProduct(another) {
return new Vector3D(this.x * another.x, this.y * another.y, this.z * another.z);
}
divideBy(value) {
return new Vector3D(this.x / value, this.y / value, this.z / value);
}
divideByEqual(value) {
this.x /= value;
this.y /= value;
this.z /= value;
}
getDistance(another) {
return this.minus(another).absoluteValue;
}
}
こちらは class があるので TypeScript のコードとあまり変わらない。”ES5″ とは、まるで別の言語のように見えるのが面白い。
ディスカッション
コメント一覧
まだ、コメントがありません