個人開発で3Dのゲームを作っています。コードはほとんど自分では書いていなくて、AIと一緒に作っています。
キャラクターのジャンプモーションで、こんな症状が起きました。
設定を変えたのに、画面が1ミリも変わらない。
エラーも警告も出ません。設定した値は保存されています。なのに再生される絵が変わらない。今日はこの「静かに無視される設定」を見つけるまでの話です。
そもそも、なぜ再生位置をずらす必要があったか
キャラクターのモーション素材は Mixamo(無料でモーションデータを配っているサイト)から持ってきています。1本の素材に「しゃがむ → 踏み切る → 空中 → 着地 → 立ち戻る」が全部つながって入っています。
これを頭から再生すると、ジャンプボタンを押した瞬間に「しゃがむ」から始まってしまうので、見た目としては「踏み込む前に飛んでいる」ように見えます。
そこで、「素材の何秒目から再生を始めるか」を指定する必要が出てきます。Godot(無料の3Dゲームエンジン)には、これ用の設定があります。
# AnimationNodeAnimation(AnimationTreeの中で1つのモーションを表すノード)
animation_node.start_offset = 0.4 # 0.4秒目から再生を始める、はずだった
start_offset は名前の通り「開始位置のオフセット」です。数値を大きくすれば、その分だけ頭を飛ばして再生されるはずでした。
症状:数値を変えても、絵が変わらない
start_offset を 0.4 にしても 0.8 にしても、再生される絵はまったく同じでした。
最初に疑ったのは自分のコード側でした。「値の代入に失敗しているのでは」「別の場所で上書きされているのでは」と、代入している行の周りを何度も見直しました。エラーは出ていないので、ここで時間を溶かしました。
原因:もう1つの設定が「ONになっていないと丸ごと無視する」仕様だった
調べていくと、AnimationNodeAnimation には use_custom_timeline という、もう1つの設定があることが分かりました。
Godotの公式ドキュメントで start_offset の説明を読むと、こう書いてあります(要約すると)。
start_offsetはuse_custom_timelineが有効な場合にのみ使われる。
つまり、こういう関係でした。
use_custom_timeline |
start_offset の扱い |
|---|---|
false(既定値) |
完全に無視される。エラーも警告も出ない |
true |
指定した通りに再生開始位置がずれる |
既定値が false なので、何も知らずに start_offset だけ設定すると、静かに無視されます。 設定した値そのものは保存されているので、コードを読んでも「効いていない」ことには気づけません。
これが「エラーも出ないのに絵が変わらない」の正体でした。
この手のバグへの対処:「設定した」で終わらせず、「効いたか」をテストで測る
use_custom_timeline を有効にすれば直る話ではあるのですが、同じ構造のバグは他の設定でも起こりえます(Godotに限らず、既定値がOFFで別の条件が要る設定は他のツールにもよくあります)。
なので、直したあとに「本当に効いているか」を自動で確かめる仕組みを足しました。
# 再生を1フレーム進めて、実際の再生位置(秒)を読み取って比較する
func _test_trimmed() -> bool:
var actual_pos: float = animation_player.current_animation_position
var expected_pos: float = 0.4
return abs(actual_pos - expected_pos) < 0.05
考え方としては、設定した値を信じるのではなく、実際に再生させて出てきた数値を見るというだけです。地味ですが、この確認を挟んでから初めて「直った」と言えるようになりました。
もう1つ気をつけたこと:「使わない部分を消す」と「見た目まで消える」は別
再生位置を直したあと、別の問題も出ました。素材の「使わない部分」を切り詰めたら、今度は踏み込みの動き自体が消えてしまったんです。
原因は単純で、「この区間は今回使わない」と「この区間の動きは要らない」を混同していたことでした。着地の直前でモーションを区切ったつもりが、実際には「体が沈み込んで着地の勢いを受け止める」動きの部分ごと削っていました。
見た目のどの部分が何を表現しているかを確認せずに、時間だけで機械的に切ると、こういう事故が起きます。「切り出す」のつもりが「捨てる」になっていないか、切ったあとに見た目を確認する一手間が要りました。
まとめ
-
start_offsetのような「値を設定すれば効くはず」の項目でも、別の設定が有効になっていないと丸ごと無視されることがある(今回はuse_custom_timeline) - こういうバグはエラーも警告も出ないので、値そのものを見直しても気づけない。公式ドキュメントでその項目が依存している別の設定を確認する
- 直したら「設定した」で終わらず、実際の再生位置を読み取って数値で確認する(
_test_trimmedのような小さいテストで十分) - モーションの一部を切り詰めるときは、その区間が担っている見た目(今回は着地の沈み込み)まで消していないかを確認する
「設定を変えたのに何も起きない」ときは、その項目が何かの前提条件付きで動く仕様になっていないか、ドキュメントを疑ってみるとよさそうです。
普段は ShibaHub という無料の計算ツールを集めたサイトや、補助金ナビ を作っています。屋号は sesebox です。