行列
記号の意味
- ベクトル- 矢印付きの文字
- 長さ- ベクトルの大きさ
- 単位ベクトル- 長さ1のベクトル
- 内積- 2つのベクトルから数値を計算
- シータ- 角度を表すギリシャ文字
- 余弦- 角度から比率を求める関数
概要
複数のベクトルをまとめて扱う行列という数学的構造を使って、回転・拡大縮小などの変換を効率的に表現する方法を学びます。
行列とは何か
ゲーム開発では、オブジェクトの回転・拡大縮小・複数の点の一括変換など、複雑な座標変換を効率的に扱う必要があります。これらを統一的に表現するのが行列で、複数の数を格子状に並べて「変換」の情報を持たせたものです。
2×2行列(2行2列)は次のように書きます:
この4つの数()の配置が「変換」の情報を持ちます。例えば、次の行列は「2倍に拡大する変換」を表します:
行列の各要素が表すもの
2×2行列の各要素は、座標軸がどこに移動するかを表します:
- 左列 : 右方向 がどこに移動するか
- 右列 : 上方向 がどこに移動するか
各要素の意味を整理すると次のようになります:
| 要素 | 位置 | 意味 |
|---|---|---|
| 左上 | X軸の変換先のX成分 | |
| 右上 | Y軸の変換先のX成分 | |
| 左下 | X軸の変換先のY成分 | |
| 右下 | Y軸の変換先のY成分 |
つまり、行列を見るだけで「X軸とY軸がどこに移動するか」が分かります。
具体例: 2倍拡大
- X軸 → に変換(横に2倍)
- Y軸 → に変換(縦に2倍)
具体例: 90度回転
- X軸 → に変換(上向きに)
- Y軸 → に変換(左向きに)
行列の役割
行列は「ベクトルをどう変換するか」を記録します:
- 左側: 変換行列
- 中央: 元のベクトル
- 右側: 変換後のベクトル
例: 2倍拡大
→ に変換されました!
実用例
行列を使うと、回転や拡大縮小などの変換を統一的に扱えます。
オブジェクトの回転
JavaScript
// 45度回転の行列
const angle = Math.PI / 4; // 45度(ラジアン)
const cos = Math.cos(angle);
const sin = Math.sin(angle);
const rotationMatrix = [
[cos, -sin],
[sin, cos]
];
拡大縮小
JavaScript
// X方向に2倍、Y方向に3倍
const scaleMatrix = [
[2, 0],
[0, 3]
];
複数点の一括変換
JavaScript
// 三角形の3つの頂点を一度に回転
const triangle = [
{ x: 0, y: 1 },
{ x: 1, y: 0 },
{ x: -1, y: 0 }
];
const rotated = triangle.map(point =>
transformVector(rotationMatrix, point)
);
デモ: 行列による変換の可視化
下のデモで、行列がベクトルをどう変換するか観察しましょう!
ポイント
青い破線は元のベクトル (3, 0) と (0, 3)、赤い実線は変換後のベクトルを示します。
変換行列
X方向の倍率
2.000.00
0.00
Y方向の倍率
1.50x
3.00y
0.00x'
6.00y'
0.00例: ベクトル (3, 0) を変換した場合
x' = 2.00 × 3 + 0.00 × 0 = 6.00
y' = 0.00 × 3 + 1.50 × 0 = 0.00
JavaScript実装
2×2行列クラスの基本構造
JavaScript
/**
* 2×2行列クラス
*/
class Matrix2x2 {
constructor(a, b, c, d) {
// [[a, b], [c, d]] の形式で保存
this.values = [
[a, b],
[c, d]
];
}
/**
* 行列とベクトルの積
*/
transform(vector) {
const [[a, b], [c, d]] = this.values;
return {
x: a * vector.x + b * vector.y,
y: c * vector.x + d * vector.y
};
}
/**
* 単位行列(何も変換しない)
*/
static identity() {
return new Matrix2x2(1, 0, 0, 1);
}
/**
* 拡大縮小行列
*/
static scale(sx, sy) {
return new Matrix2x2(sx, 0, 0, sy);
}
/**
* 回転行列
*/
static rotation(angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return new Matrix2x2(cos, -sin, sin, cos);
}
}
// 使用例1: 2倍拡大
const scaleMatrix = Matrix2x2.scale(2, 2);
const point = { x: 3, y: 4 };
const scaled = scaleMatrix.transform(point);
console.log(scaled); // { x: 6, y: 8 }
// 使用例2: 45度回転
const rotMatrix = Matrix2x2.rotation(Math.PI / 4);
const rotated = rotMatrix.transform(point);
console.log(rotated); // 回転後の座標
ゲームでの実装例
JavaScript
// キャラクターの姿勢を行列で管理
class GameObject {
constructor(x, y) {
this.position = { x, y };
this.transform = Matrix2x2.identity(); // 初期姿勢
}
/**
* オブジェクトを回転
*/
rotate(angle) {
const rotation = Matrix2x2.rotation(angle);
// 現在の変換に回転を合成(次章で学習)
this.transform = rotation;
}
/**
* ローカル座標をワールド座標に変換
*/
localToWorld(localPoint) {
// 変換行列を適用
const transformed = this.transform.transform(localPoint);
// 位置を加算
return {
x: transformed.x + this.position.x,
y: transformed.y + this.position.y
};
}
}
// 使用例
const player = new GameObject(100, 100);
player.rotate(Math.PI / 4); // 45度回転
// プレイヤーの前方1マスの座標
const forward = { x: 0, y: 1 };
const worldPos = player.localToWorld(forward);
console.log(worldPos); // ワールド座標
行列の重要性
行列を使うと以下のような操作が簡単になります:
- 回転・拡大縮小: 1つの行列で表現
- 複数変換の合成: 次章で学ぶ行列の積
- 効率的な計算: 複数点を一度に変換
- コードの整理: 変換ロジックを1箇所に集約
次章では、行列同士の演算(積、加算など)を学びます。