xmath-usage について
xmath に依存する Defold プロジェクト向けの利用ガイドです。ベクトル、クォータニオン、行列をインプレースで演算し、オブジェクトを再利用して頻繁なループでの割り当てを減らす方法を説明します。
主な機能
- 01xmath が依存関係にあるか確認
- 02数学オブジェクトをインプレースで変更
- 03再利用する一時変数を事前確保
- 04ベクトルとクォータニオンの演算
- 05行列変換と補間
活用シーン
- 01update ループ内の割り当て削減
- 02一時的なベクトル値の再利用
- 03クォータニオン回転の計算
- 04投影行列とビュー行列の作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ indiesoftby/ defold-agent-config --skill xmath-usageインストール後、Claude Code で/xmath-usageを入力して読み込まれたか確認します。
詳細
Defoldでxmathを使用したゼロアロケーションの数学演算
前提条件:xmath依存関係の確認
このスキルのガイダンスを適用する前に、プロジェクトでxmathが使用されていることを必ず確認してください。game.projectファイルで、thejustinwalsh/defold-xmathを含む依存関係URLを確認します(例:dependencies#N = https://github.com/thejustinwalsh/defold-xmath/archive/...)。または、.deps/ディレクトリにxmath/が存在するか確認してください。
game.projectにxmath依存関係がなく、ローカルのxmathモジュールも見つからない場合は、このスキルを適用しないでください。プロジェクトでxmathが使用されていないことをユーザーに伝え、依存関係の追加を提案してください:
[project]
dependencies#N = https://github.com/thejustinwalsh/defold-xmath/archive/refs/heads/main.zip
中核となる考え方:インプレース変更でヒープアロケーションを排除する
標準のvmathは演算のたびに新しいLuaオブジェクトを作成するため、ホットループでGCの負荷が絶えず発生します:
-- BAD: vmath allocates 3 new objects every frame
function update(self, dt)
local v = self.dir * 5 * dt -- alloc #1
local pos = go.get_position() -- alloc #2
local result = pos + v -- alloc #3
go.set_position(result)
end
xmathは既存の変数をインプレースで変更し、結果を第1引数に書き込みます。一度だけ確保し、その後はずっと再利用します:
-- GOOD: xmath reuses pre-allocated variables, zero allocations per frame
go.property("dir", vmath.vector3(0, 1, 0))
local v = vmath.vector3() -- allocate ONCE at module scope
function update(self, dt)
local pos = go.get_position()
xmath.mul(v, self.dir, 5 * dt) -- writes into v
xmath.add(v, pos, v) -- writes into v
go.set_position(v)
end
主なルール
- スクラッチ変数はモジュールスコープまたは
init()で事前に確保してください —update()やon_message()の中では確保しないでください。 - 出力変数は常に第1引数です — これは
vmathとの基本的な呼び出し規約の違いです。 - 関数は何も返しません — 呼び出しをチェーンできません。各ステップでスクラッチ変数を使用してください。
- 初期オブジェクトの作成には
vmathを使用してください —vmath.vector3()、vmath.vector4()、vmath.quat()、vmath.matrix4()でスクラッチバッファを確保し、その後の演算にはxmathを使用します。 - 型ポリモーフィズム —
xmath.lerpなどの関数は、出力引数の型に応じてvector3、vector4、quaternionで動作します。
最適化パターン
-- Scratch variables — allocated once
local temp_v = vmath.vector3()
local temp_q = vmath.quat()
function update(self, dt)
-- Instead of: local dir = vmath.normalize(target - pos)
xmath.sub(temp_v, self.target, self.pos)
xmath.normalize(temp_v, temp_v) -- can use same variable as both input and output
-- Instead of: local rot = vmath.quat_rotation_z(angle)
xmath.quat_rotation_z(temp_q, self.angle)
-- Instead of: local rotated = vmath.rotate(rot, dir)
xmath.rotate(temp_v, temp_q, temp_v)
end
APIリファレンス全体
すべての関数は結果を第1引数に書き込みます。戻り値はありません。
ベクトル演算(vector3 / vector4)
| 関数 | 等価な式 | 説明 |
|---|---|---|
xmath.add(out, v1, v2) | out = v1 + v2 | 2つのベクトルを加算 |
xmath.sub(out, v1, v2) | out = v1 - v2 | ベクトルを減算 |
xmath.mul(out, v, n) | out = v * n | ベクトルにスカラーを乗算 |
xmath.div(out, v, n) | out = v / n | ベクトルをスカラーで除算 |
xmath.cross(out, v1, v2) | out = cross(v1, v2) | 外積(vector3のみ) |
xmath.mul_per_elem(out, v1, v2) | out.x = v1.x * v2.x, ... | 要素ごとの乗算 |
xmath.normalize(out, v) | out = normalize(v) | ベクトルを正規化 |
xmath.rotate(out, q, v) | out = rotate(q, v) | vector3をクォータニオンで回転 |
xmath.vector(out) | out = (0,0,0) | ゼロベクトルにリセット |
補間(vector3 / vector4 / quaternion)
| 関数 | 等価な式 | 説明 |
|---|---|---|
xmath.lerp(out, t, v1, v2) | out = lerp(t, v1, v2) | 線形補間 |
xmath.slerp(out, t, v1, v2) | out = slerp(t, v1, v2) | 球面補間 |
クォータニオン演算
| 関数 | 説明 |
|---|---|
xmath.quat(out) | 単位クォータニオン(0, 0, 0, 1)にリセット |
xmath.conj(out, q) | クォータニオンの共役 |
xmath.quat_axis_angle(out, axis, angle) | 軸と角度からクォータニオンを作成 |
xmath.quat_basis(out, x, y, z) | 3つの基底ベクトル(vector3)からクォータニオンを作成 |
xmath.quat_from_to(out, v1, v2) | v1からv2への回転クォータニオン |
xmath.quat_rotation_x(out, angle) | X軸周りの回転 |
xmath.quat_rotation_y(out, angle) | Y軸周りの回転 |
xmath.quat_rotation_z(out, angle) | Z軸周りの回転 |
行列演算(matrix4)
| 関数 | 説明 |
|---|---|
xmath.matrix(out [, m1]) | 単位行列にリセットするか、m1 からコピーします |
xmath.matrix_axis_angle(out, axis, angle) | 軸と角度から回転行列を作成します |
xmath.matrix_from_quat(out, q) | クォータニオンから行列を作成します |
xmath.matrix_frustum(out, left, right, bottom, top, near, far) | 視錐台の射影行列です |
xmath.matrix_inv(out, m) | 行列の逆行列です |
xmath.matrix_look_at(out, eye, look_at, up) | ビュー行列です |
xmath.matrix4_orthographic(out, left, right, bottom, top, near, far) | 正射影です |
xmath.matrix_ortho_inv(out, m) | 正射影の逆行列です |
xmath.matrix4_perspective(out, fov, aspect, near, far) | 透視射影です |
xmath.matrix_rotation_x(out, angle) | X 軸周りの回転です |
xmath.matrix_rotation_y(out, angle) | Y 軸周りの回転です |
xmath.matrix_rotation_z(out, angle) | Z 軸周りの回転です |
xmath.matrix_translation(out, position) | vector3/vector4 から平行移動行列を作成します |
コメント
Markdown 対応