2024/12/23(月) [n年前の日記]
#1 [godot] OBになった時の処理が上手く行かなくてハマってた
_昨日
に続き、Windows10 x64 22H2 + Godot Engine 4.3 64bit でゴルフゲームっぽいものが作れないものかなと試してる。
ボールが、OB やペナルティエリア(ウォーターハザード)に入った時に、打った場所に戻す処理を追加したのだけど、これがバグってしまってずっとハマってた。
ボールの動きが止まる → 地面がOB/ペナルティエリアだと検出される → OB/ペナルティエリアと表示して数秒待つ → ボールの座標を打った場所に書き戻す、という処理をするのだけど。書き戻したら、そこの地面はフェアウェイ/ラフ等を検出してくれるはず…。なのに、何故かOBやペナルティエリアに居ると検出されてしまって、またOB/ペナルティエリアが表示されてしまう。
必ずそうなるわけでもなくて、時々何かのタイミングで、地面の属性を正しく取得できない状態になる…。
どうやら RigidBody3D が、スリープを脱してアクティブにならない瞬間があるっぽい。地面の属性の検出は、物理計算用として呼ばれる _integrate_forces(state) の中で処理しているけれど、スリープになったままだとこの関数が呼ばれないから、地面の属性も更新されないのだろう。
結局、フラグを用意して対処した。ボール座標を変更したらフラグを立てて、そのフラグが立ってる間、地面がOB/ペナルティエリアなら何もしない。RigidBody3D がスリープから抜けて、地面の属性が変わってくれたらフラグを下ろして、以降の処理を始める。みたいな。
また、ボール座標を変更する時は、sleeping変数を true にしつつ、下向きに少し大きめの速度を設定してしまうことにした。これでスリープ状態を脱してくれる可能性が高まるのではないかと期待…。
ただ、何か不具合が起きるたびにフラグを新規に用意して場当たり的に対処してる気がする。そのせいか、ソースはもうグチャグチャ。こういう時にこそ、ステップ処理を使って、モード別で処理するべきなのでは…? ごっそり書き換えてしまおうか…。
ボールが、OB やペナルティエリア(ウォーターハザード)に入った時に、打った場所に戻す処理を追加したのだけど、これがバグってしまってずっとハマってた。
ボールの動きが止まる → 地面がOB/ペナルティエリアだと検出される → OB/ペナルティエリアと表示して数秒待つ → ボールの座標を打った場所に書き戻す、という処理をするのだけど。書き戻したら、そこの地面はフェアウェイ/ラフ等を検出してくれるはず…。なのに、何故かOBやペナルティエリアに居ると検出されてしまって、またOB/ペナルティエリアが表示されてしまう。
必ずそうなるわけでもなくて、時々何かのタイミングで、地面の属性を正しく取得できない状態になる…。
どうやら RigidBody3D が、スリープを脱してアクティブにならない瞬間があるっぽい。地面の属性の検出は、物理計算用として呼ばれる _integrate_forces(state) の中で処理しているけれど、スリープになったままだとこの関数が呼ばれないから、地面の属性も更新されないのだろう。
結局、フラグを用意して対処した。ボール座標を変更したらフラグを立てて、そのフラグが立ってる間、地面がOB/ペナルティエリアなら何もしない。RigidBody3D がスリープから抜けて、地面の属性が変わってくれたらフラグを下ろして、以降の処理を始める。みたいな。
また、ボール座標を変更する時は、sleeping変数を true にしつつ、下向きに少し大きめの速度を設定してしまうことにした。これでスリープ状態を脱してくれる可能性が高まるのではないかと期待…。
ただ、何か不具合が起きるたびにフラグを新規に用意して場当たり的に対処してる気がする。そのせいか、ソースはもうグチャグチャ。こういう時にこそ、ステップ処理を使って、モード別で処理するべきなのでは…? ごっそり書き換えてしまおうか…。
◎ 余談。ペナルティエリアについて :
ゴルフコースには、いわゆる「池ポチャ」に繋がるウォーターハザードと呼ばれるものがあると今まで思い込んでいたけれど。
ググってみたら、ゴルフのルールが改正されて、ウォーターハザードなる呼び名は無くなったらしい。代わりに、レッドペナルティエリアとイエローペナルティエリアという呼び方になった、という話を見かけた。
ペナルティエリアに入ったときの打ち直しの仕方も、2〜3パターンあるようで…。打ち直し場所の算出がややこしい…。そもそも、どのパターンを採用すればいいのか、そこからして悩む…。
_「池ポチャ」ルール図解! 知っておきたいペナルティの処置と数え方【2024年版】 - ゴルフ総合サイト ALBA Net
_ゴルフボールが池に入った場合の対処法や新ルールを徹底解説(季節・暮らしの話題 2022年01月04日) - 日本気象協会 tenki.jp
_ペナルティーエリア / ジェネラルエリア|用語解説
何にせよ、ボールが、OB/ペナルティエリアとの境界線を横切った座標を取得できないと、その後の処理ができないのだよな…。
ググってみたら、ゴルフのルールが改正されて、ウォーターハザードなる呼び名は無くなったらしい。代わりに、レッドペナルティエリアとイエローペナルティエリアという呼び方になった、という話を見かけた。
ペナルティエリアに入ったときの打ち直しの仕方も、2〜3パターンあるようで…。打ち直し場所の算出がややこしい…。そもそも、どのパターンを採用すればいいのか、そこからして悩む…。
_「池ポチャ」ルール図解! 知っておきたいペナルティの処置と数え方【2024年版】 - ゴルフ総合サイト ALBA Net
_ゴルフボールが池に入った場合の対処法や新ルールを徹底解説(季節・暮らしの話題 2022年01月04日) - 日本気象協会 tenki.jp
_ペナルティーエリア / ジェネラルエリア|用語解説
何にせよ、ボールが、OB/ペナルティエリアとの境界線を横切った座標を取得できないと、その後の処理ができないのだよな…。
◎ レイを飛ばして地面の高さを知る :
カメラが地面の下に潜り込んでしまって変な見た目になる時があったので、地面の高さを取得してカメラ位置の高さを補正したいなと。上から下にレイ(光線)を飛ばして地面のポリゴンモデルと衝突してるか調べて、衝突位置の座標を得ることで補正できそうかな、と…。
レイの飛ばし方は、以下が参考になった。
_Ray-casting - Godot Engine (stable) documentation in English
一応実装できた。レイと、地面ポリゴンモデルの、衝突位置座標を取得するところだけ抜き出してみる。
衝突していたら、result という変数に情報が入ってくる。そこから座標を取得できる。
レイの飛ばし方は、以下が参考になった。
_Ray-casting - Godot Engine (stable) documentation in English
一応実装できた。レイと、地面ポリゴンモデルの、衝突位置座標を取得するところだけ抜き出してみる。
y_adjust = false var space_state = get_world_3d().direct_space_state var from_pos = Vector3(newpos.x, 50, newpos.z) var to_pos = Vector3(newpos.x, -50, newpos.z) var query = PhysicsRayQueryParameters3D.create(from_pos, to_pos) var result = space_state.intersect_ray(query) if result: var gy = result.position.y if gy > newpos.y: newpos.y = gy + 0.4 y_adjust = true
衝突していたら、result という変数に情報が入ってくる。そこから座標を取得できる。
[ ツッコむ ]
以上、1 日分です。