豆知識

Last-modified: 2023-12-01 (金) 19:20:24

知っているとスクリプトが作りやすくなるかもしれない小ネタ。


 

パスから外す(車)

その辺に走っている車を制御するとき、たとえば

07D5: set_car 0@ velocity_in_direction_XYZ 9@ 10@ 0.0 rotation_velocitiesXY 0.0 0.0 unk 0.0

このようなコードを使うだけでは どんな値を設定しても車に対して反映されません。
これは車がパスに沿って走っているからです。
スクリプトのパスとは違うので、05D6 や 05EC を使っても意味がありません。
このパスは、物が当たったり攻撃されたり外的要因が加わると外れるようです。
なるべく車を傷つけずパスだけ外したいという場合、

04FE: deflate_tire 2 on_car 0@
0699: set_car 0@ repair_tire 2

このようなコードを入れます。パンクさせすぐに直しているだけです。
(0001:wait を挟んでいないので、パンクしているのを見ることは出来ません)

パスから外す(人)

083C: set_actor $PLAYER_ACTOR velocity_in_direction_XYZ 0.0 0.0 0.0

人が地面についている場合、このコードではZ方向のみで、XとYにいくら高い値を入れても反映されません。
ですので一度地面から離してやる必要があります。

  • 方法1
    00A0: store_actor $PLAYER_ACTOR position_to 0@ 1@ 2@
    00A1: put_actor $PLAYER_ACTOR at 0@ 1@ 2@
    00A1を実行すると地面より少し高い位置に置き換えられるのを利用。
  • 方法2
    083C: set_actor $PLAYER_ACTOR velocity_in_direction_XYZ 0.0 0.0 10.0
    wait 0
    083C: set_actor $PLAYER_ACTOR velocity_in_direction_XYZ 10.0 0.0 0.0
    Z方向は適用されるので一度Z方向のみを適用させ、1フレーム待って地面から浮いた後にXY方向を適用させる。

タイマー

32@と33@には1フレームの時間が加算されます。
通常25FPSのGTA:SAでは毎フレーム最大40が加算されます。
これを利用して、フレームが一定で無くても等間隔に同じスピードでオブジェクトや煙などを配置することが出来ます。
また、タイマーは整数型なので、1フレームが 1 > t(ms) > 0 の場合(つまり、通常あり得ませんが1001FPS以上出ている時)は0が加算され、タイマーや0001:wait 1以上 を使用することが出来なくなります。
この現象は主に 015D: set_gamespeed でゲームスピードを 0.025 以下にした場合等に発現します。

コロナ、レーシングチェックポイント

動かない場合は問題ありませんが、基点が高速で移動するとコロナやレーシングチェックポイントが思った位置より後ろに出現してしまいます。
コロナの場合は速度ベクトルの 1/25.0 を、レーシングチェックポイントの場合は速度ベクトルの 1/12.5 をそれぞれ足すことによって遅れを修正することができます。
おそらくフレームレートの影響を受けているので、タイマーから値を取るとより正確になるでしょう。
以下に車に乗って移動する時のレーシングチェックポイントの例を書きます。

0093: 0@ = integer 32@ to_float //毎フレーム32@を0にする必要あり。
0017: 0@ /= 3.2 //32@の最大を40とし常に比を一定にするためタイマー値を 40/12.5=3.2 で割る。
06A2: get_car 15@ velocity_in_direction_XYZ 20@ 21@ 22@
0073: 20@ /= 0@ // (float) //タイマー不使用の場合は 12.5で割る
0073: 21@ /= 0@ // (float) //タイマー不使用の場合は 12.5で割る
0073: 22@ /= 0@ // (float) //タイマー不使用の場合は 12.5で割る
00AA: store_car 15@ position_to 4@ 5@ 6@
005B: 4@ += 20@ // (float)
005B: 5@ += 21@ // (float)
005B: 6@ += 22@ // (float)
07F3: move_racing_checkpoint 29@ to 4@ 5@ 6@
0006: 32@ = 0

人物車の解放

01C2: remove_references_to_actor $PLAYER_ACTOR // Like turning an actor into a random pedestrian
01C3: remove_references_to_car 0@ // Like turning a car into any random car
01C4: remove_references_to_object 0@ // This object will now disappear when the player looks away

勘違いされている方が多いのですが、このコードはcleoで作成した人物車のみに使用します。
その辺にある車を変数に代入し、用が済んだから 01C3 で解放…とかしてはいけません。
もしミッションなどで作成されたものを勝手に解放してしまうと、その後存在しない対象を制御しようとしてエラーが出る可能性が非常に高くなります。
Ryderミッションの床屋から出た時エラーが出るのはほぼ全てこれが原因です。

オブジェクト制御

オブジェクトを制御するとき

0381: throw_object 0@ velocity_in_direction 0@ 1@ 2@

このコードをよく使われると思います。
しかし、オブジェクトには(詳しく調べていないのですが)150~200m/s程度の速度上限があります。
それ以上の速度で移動させる必要がある場合、オブジェクトの座標を直接操作します。
毎フレーム移動させることになるので、フレームレートに依存します。
この方法で移動させる場合前述のタイマーの項目通り、ゲームスピードが著しく低い場合は使うことが出来ません。

0006: 32@ = 0
for 4@ = 0 to 250
    wait 0
    0093: 10@ = integer 32@ to_float
    0006: 32@ = 0
    0013: 10@ *= 1.0
    0400: store_coords_to 1@ 2@ 3@ from_object 0@ with_offset 0.0 0.0 10@
    01BC: put_object 0@ at 1@ 2@ 3@
end

このコード場合、1000m/sで10km飛んでいきます。(25FPSの場合)
速度の調整は 0013 で行います。1.0=1000m/s 0.1=100m/s という感じです。
もちろん、ただの移動なので 04DA などで衝突判定をすることは出来ませんので

06BD: (check) no_obstacles_between 0@ 1@ 2@ and 0@ 1@ 2@ solid 1 car 0 actor 0 object 0 particle 0

を使って、障害物があればアクションを起こすようにすれば擬似的な衝突判定が出来ます。

しかしこのコードにも問題があり、01BC を使用すると移動後の座標に近い人、物、車が消えてしまします。
(人物車その他を作るときに注意すべき事を参照)
近くの場合はメモリを操作して移動させることが出来るのですが、
プレイヤーから一定の距離を離れるとメモリで操作しても"表示上"の座標が更新されないという仕様があります。
今のところ回避方法は分かっていませんが、0381 を併用することで速度は変わってしまいますが、見かけは問題なく動作します。