medaka TwitterログからのThyme知見

medaka 返信: 0件 2ヶ月前

対象: created_at < 2023-01-01。アーカイブ全12,991件のうち9,940件を対象にし、Algodoo、Phun、Thyme、Scene API、制御、物理機構、PHZ共有に関する投稿を手作業で整理した。

このファイルは、本人の投稿・返信・RT @...を含むログから抽出した調査メモである。ツイートは実験時点の経験談であり、Algodooの全バージョンに対する仕様保証ではない。特にID、ヒンジのLegacyMode、Bend、PostStepの実行順は、現在の実行環境で再検証してからスキルやテンプレートに反映する。

先に結論

  1. 既存オブジェクトの参照は、画像からIDを推測せず、実行時のGeomID/EntityIDを取得して解決する。 Scene.entitybygeomID(...)、Scene.entitybyID(...)、ヒンジのreadable(entity).geom0/geom1、レーザーイベントのe.geomが繰り返し使われている。保存後も同じ数値IDが残るという証拠ではない。
  2. 物理接続を先に成立させ、Thymeは制御・計測に限定する。 2019年には、スクリプトに慣れると物理機構が稚拙になるという自己反省や、意図的にNoThymeで機構を作る方針が記録されている。
  3. ヒンジのLegacyModeは明示的に選び、Mode 0/1を混同しない。 0はPhunに近い挙動、1は別の質量依存・伸び特性という経験談があるが、版依存のため固定値として断定しない。
  4. 制御は角度誤差だけでなく角速度・誤差の変化を入れる。 PIDの微分項は振動を抑えるが、係数過多なら暴走する。Bendは収束が速い一方、回転速度の細かな設定にはモーター併用が必要という比較結果がある。
  5. レーザー、PostStep、配列処理はコストを見積もる。 レーザーの大量・連続発動、PostStepでの単純な数値更新、長い配列の並べ替えが重いという実測・体感が複数ある。

1. ID参照と現在フレームの値

1.1 GeomID / EntityID

ログ上の最小パターンは次の通り。

p = Scene.entityByGeomID(targetGeomID);
speed = p.vel;

Scene.entitybygeomID(指定のgeomID).velで対象図形の値を読む、という説明がある。2016-07-18 / 755002755396153344
GeomIDを「Algodoo上の図形に割り振られる固有の番号」と説明し、Scene.entitybygeomID(id).物性で読み書きする投稿もある。2017-03-08 / 839333997960318976

Scene.entityByIDについては、数値やentityID、e.other.entityid、e.laser.entityidを引数にできるという整理がある。一方、frictionなど物性値をそのまま渡すと働かず、同じ物体内のスクリプトでその値をentityIDに代入した場合は動いた、という限定的な実験報告である。2016-07-16 / 754219999728807936、2016-07-16 / 754221284196614144

1.2 ヒンジやレーザーからIDを渡す

ヒンジについている図形の片方をreadable(entity).geom0またはgeom1で取り出し、そのIDでScene.entitybygeomIDを引くパターンがある。2017-03-11 / 840540328998260736、2017-03-11 / 840543215866396676

レーザーイベントからは、readable(entity)で自分のGeomIDを得て、e.geom._Sousin := p.geomIDのように別図形へ送る例がある。2018-02-09 / 961927115594592256

1.3 staleな参照を避ける

PostStepの発火順は図形のID順らしい、という未検証の観察があり、別図形のプロパティを同一フレームに直接受け渡すと前フレーム値を見てしまう場合がある。そのため、現在フレームの値はGeomIDから再取得する方針が使われていた。2018-03-10 / 972440445610377218、2018-03-10 / 972441775708098560、2018-03-10 / 972444184933105664

現行スキルへの反映: これはフォーラム調査の「明示IDは同一実行の配線用で、保存後の恒久IDではない」という注意と整合する。Scene.myにはオブジェクト参照ではなく数値IDだけを置き、onSpawn等で再捕捉する定石を優先する。

2. 物理接続・ヒンジ・機構

2.1 LegacyMode

これらは相互に完全一致する仕様表ではない。Mode 0/1の意味をテンプレートで隠さず、対象バージョンと目的(Phun互換、質量非依存、高速回転)をコメントに残すのが安全である。

2.2 Bendと物理機構

BendはPIDより収束が速いが、回転速度を直接細かく調節しにくく、モーターとの併用が必要になる可能性がある。2017-04-15 / 853088620336394241
BendConstantはPIDの微分制御(角速度の抑制)に似る、という理解も記録されている。2017-04-20 / 855084320108630016

実際のトラブルシュートでは、BendConstantを1,000にすると動いた例、大きな値にしない方がよいという助言、逆に機構に耐えさせるには非常に大きな値が必要だった例が混在している。2017-09-17 / 909431761729232902、2017-09-17 / 909433295112257536、2017-09-17 / 909434888708689922

実装上の含意: BendConstantを一律に増やすのではなく、まず接続位置・接着・Fixjoint・密度・LegacyModeを確認し、短い再生で発散を検出する。重なりは接続ではないため、車輪やアクスルは実ヒンジを作ってから走行テストする。

2.3 物理機構を先に作る

2015年の尾翼では、スラスター部の接着を固定具から回転軸に変更して問題を解決し、空気抵抗体を四角から円に変更して機動性を上げた。2015-06-27 / 614660577252642817

2019年には、スクリプトに慣れると物理機構が稚拙になりやすい、という自己反省がある。2019-08-15 / 1161848379619414016
同時期のヘビ型戦車では、敢えてスクリプトを使わず機構だけで作る方針を明言している。2019-08-10 / 1160042873649164289

これは現在のMCPワークフローにもそのまま使える。車体・車輪・ヒンジの視覚確認 → 無動力の短時間再生 → その後に制御・装飾の順にする。

3. Thymeの制御パターン

3.1 PID / PD

PIDを汎用的な火器管制・姿勢制御へ再利用したいという方針が繰り返し現れる。2016-12-05 / 805712897628192770
角度だけで姿勢制御すると振動が増え、角速度も加味すると振動を抑えられるが、強くしすぎると姿勢復元まで妨げるというトレードオフがある。2016-06-15 / 743107633893146624、2016-06-15 / 743108556069601281

記録されている再利用関数は概ね次の構造である(原文は会話用の短縮コードで、変数名や積分の扱いは要検証)。

// pid0: 誤差、積分状態、微分差をまとめる
scene.my.pid0 = (er, pid, ic) => {
  [er, pid(1) / ic + er, pid(0) - er]
};

// pid1: PID係数を適用
scene.my.pid1 = (pid, kp, ki, kd) => {
  pid(0) * kp + pid(1) * ki + pid(2) * kd
};

control = scene.my.pid1(scene.my.pid0(target - angle, previous, 1.5), kp, ki, kd);
motorSpeed = control * scale;

出典: 2017-03-13 / 841278573537251328、841278610744860676、841279548608061441。別の投稿では、PIDが暴走したら係数を全体的に下げる、としている。2017-05-04 / 860185466741506048

角度差はラップ処理が必要で、目標と現在の角度差を-90° < θ < +90°に保つためにThymeのatanの範囲を利用する、という方針がある。2019-04-06 / 1114579482541608960

3.2 PostStep / Update / sim.tick

PostStepで微分・積分を実装する解説記事を作っていた。2017-03-17 / 842609258013188096、2017-03-18 / 842948446726176768

スラスターの推力をスクリプトで変えた実験から、物理演算後にPostStep等の演算が行われるのではないか、と推察している。これはスクリプトで静止させても物理演算由来の加速度を観測できるという応用につながった。2017-12-03 / 937128543888146433、937132957378035712

レーザーイベントをsim.tickに記録し、PostStep側で経過フレームを待つデバウンス例は、イベントと毎フレーム処理を分離する参考になる(RT経由・コードは途中省略)。2018-03-07 / 971298522539745280

PostStepで既存の数値を書き換えるだけでも重くなった、という報告がある。2018-01-30 / 958336884240863232
現在のスキルでは、物理の毎ステップ制御はpostStepに限定し、表示・停止中にも必要な処理だけupdateに置く。無制限のspawnや毎フレームの大量探索は避ける。

3.3 初速と機体速度

Algodooでは速度を直接設定できるため、砲弾・機銃の初速を角度から作る例がある。

vel := speed * [cos(angle), sin(angle)] + e.this.vel;

出典: 2019-09-04 / 1169213414821875712、1169217064059322368。機体速度を足さないと、移動中の発射体が不自然な方向へ飛ぶという説明もある。1169216978826883077

3.4 発射体・レーダーの軽量化

初速を付けてからPostStepで半径を大きくする方式は、威力と処理速度の両面で優秀だったという経験談がある。2017-03-15 / 842001842489901056

一方、Algodooのレーザーはかなり処理を消費する、レーザースクリプトを連続発動すると重くなる、という観察がある。2016-08-24 / 768271599195738112、2017-01-18 / 821552353560104960、2017-01-18 / 821738994568339457

引力レーダーでは、velと加速度の関係を利用し、引力体のpos/velをPostStepで毎フレーム補正していた。2017-10-01 / 914386684644610053、2017-10-02 / 914778929394802688。これは面白い計測手法だが、現行版の更新順序を前提にせず、短い実験で確認する。

4. 数値計算・物性の注意

4.1 物理安定性

レーダーや大きな機構の数値誤差を減らす経験則として、図形をできるだけ大きくする、引力を小さくする、引力・斥力を持たない部品の密度を大きくする、極端に大きい値を避ける、というメモがある。2016-09-22 / 778919820871933952

Phunでのトンネル現象について、100fps・700m/sなら、砲弾が1フレームに進む7mより厚い装甲が必要、というスケール計算がある。2016-09-22 / 778891428717993984
これはAlgodooの全設定にそのまま適用する法則ではないが、高速物体の衝突テストではFPS・速度・厚みを同時に見るという設計上の警告になる。

4.2 摩擦

摩擦係数は、接している2物体のFrictionの相乗平均として説明されている。

effective friction = sqrt(this.Friction * other.Friction)

出典: 2019-05-24 / 1131945997045649408、1131951544046313473。MaterialVelocityは物体の速度を表し、値が大きいと出力は増えるが、摩擦力の本質は摩擦係数×垂直抗力という整理もある。1131944466841866240

2016年の摩擦値実験では、シミュレーション開始前に直接変更した値はスクリプトで期待通りに働かず、シミュレーション中にスクリプトで変更すると働いた、と報告している。2016-06-11 / 741475482214879234。版や対象プロパティの更新タイミングに依存する可能性が高いため、現在のテンプレートでの一般則にはしない。

4.3 Thymeの計算量

配列要素の入れ替えが扱いづらく、当時のスクリプトは配列長の3乗に比例するほど遅くなったという自己報告がある。2017-12-26 / 945621966026817538
その後、Thymeでマージソートを実装し、速い方法だと考えていた。2017-12-30 / 946972621547102208

MCPへの含意: 生成・検索・再計算を1つの巨大なコマンドに詰め込まず、車体→接続→制御の順に分ける。forやScene.add*の大量実行は上限と停止条件を持たせる。

5. Scene.add*とイベントの記録

5.1 生成ループ

RT経由の例では、forで円形にScene.addCircleを並べている。

for(48, (n) => {
  Scene.addCircle({
    radius := 0.1;
    pos := [0.4 * math.cos(n * 7.5 * math.pi / 180),
            0.4 * math.sin(n * 7.5 * math.pi / 180)]
  })
})

出典: 2018-08-21 / 1031783385717399552、改良版の中心角計算は1031787057100681216。大量生成の見本ではあるが、現在はMCPのコマンド長・視認性・停止条件を優先する。

5.2 :=と終端

フォーラム調査の確度が高い知見では、Scene.add*({...})内の生成フィールドは:=、生成後の代入は=で統一する。Twitter上では、Dropbox経由のスクリプト送信でセミコロンを書き忘れると、後続の読み取り終了コマンドが実行されず、Scene.addboxだけが発動したという運用上の事故も記録されている。2018-03-13 / 973566977632382976

この投稿のScene.addbox例は会話用の短縮コードで括弧やセミコロンの表記揺れがあるため、文法の根拠にはフォーラムの抽出記録を使う。生成レコードの:=と、コマンド全体を1回で終端することを別々に検証する。

5.3 onCollideと更新対象

onCollide等のイベント変数を追加できるというメモがある。2017-08-14 / 897006143733616643
衝突判定以外も変更したい場合、update内のp.collideset = 0を変更すれば別の値を操作できる、という説明もある。2019-05-18 / 1129712304969269253

後者はプロパティ更新の内部挙動を含むため、現在のMCPテンプレートでは、onCollideは接触イベント、postStep/updateは明示した状態更新として分離する。

6. PHZ / 共有ファイルの扱い

2019年のAlgodooOnline実装では、PHZ判定のチェックサム仕様を確定できなかったため、次のファイル構成をヒューリスティックに検査していた。

  • scene.phn: UTF-8テキスト(PhunのPHZではANSIだったという追試あり)
  • checksum.txt: ASCIIテキスト
  • thumb.png: PNG画像
  • その他のテクスチャ: 画像ファイルのみ

出典: 2019-07-21 / 1152866130622500864、2019-08-08 / 1159464080442134528。これはアップロード検査の経験則であり、Algodoo公式の完全なPHZ仕様ではない。MCPでファイルを生成・検査するときは、拡張子だけで信頼せず、展開後の構成・文字コード・画像形式を確認する。

関連するThyme資料として、本人が2019年に基礎チュートリアルをAlgodooOnline Wikiへ移した記録がある。2019-01-07 / 1082131741001826304
2.1.0β追加関数リストの記録もある。2018-08-20 / 1031384232998760448

ログインしてください(返信一覧はログイン後に表示されます。)