俺に解るように説明する "Godot Engine 3.x" 入門+

ゲームエンジン Godot Engine に関すること。入門とか使い方とかチュートリアルとか、あれとかこれとか。日本語解説。

Godot 玉転がし 09 「RigidBody Player Controller 2/2」

スクリプトを貼っ付けていこう。貼る場所はもちろん「RigidBody」ノード。リネームして"RigidBody_Player"にしたやつね。今回やる事が上手くいけば、WASDで、このGIFのように玉を動かせるようになる。 f:id:ore2wakaru:20180307191730g:plain


スクリプト

ズバリやるのが流。ということで、スクリプトを公開。詳しい解説付き。
f:id:ore2wakaru:20180307202004p:plain

  1. extendsと、その後ろに書ける有効な文字列に関しては、ずっと前の記事にあるから、それ見て。
  2. リジッドボディーを押す時の力の大きさを設定。適当に"20.0"としたが、この単位はキログラムなのか、ニュートンなのか、ジュールなのかは分からん。色々数値を変え、動かしてみて、自分的にシックリ行くのにすればいい。。。と思うがどうだろう。
  3. 前回紹介した、リジッドボディーを安全に動かせるタイミングを提供してくれるバーチャル関数
  1. キーワードifは、
    if 条件:
        やりたいこと
    みたいに書く。で、「条件」「真(true)」のときに、「やりたいこと」の内容を実行する。大事なのは、「条件」の後ろにコロン「:」を書くことと、「やりたいこと」の前にインデント(TAB)を置く事。
    この行では、Input Mapで設定したActionの、"my_left"が発生してるかを調べている。大事なのは、Aキーが押されているかではなく、(Aキーが押されたことによって)"my_left"という文字列が発生してるかを調べているところ。
    発生しているかどうかは、Inputクラスのis_action_pressed()を呼ぶことで分かる。()内には文字列を書く。ま、ここInputクラスがいろんな入力データを握っていると考えればいい。発生していれば、true(真)を、発生してなければ、false(偽)を返す。
  2. 「条件」が「真」、つまり、Input.is_action_pressed("my_left")trueを返した時、ここが実行される。
    add_force()という関数を使ってリジッドボディーに力を加えるのだが、その前に、state.を忘れずに書く事。このstatefunc _integrate_forces(state):で書いたstateのこと。こいつが、このスクリプトを貼ったリジッドボディーの状態を保持している。だから、書き忘れてはならない。
    add_force()は、
    add_force( 力の大きさ , 力を加える場所 )
    のように書く。「力の大きさ」も「力を加える場所」も、どっちもVector3型で書く。
    ここでは左に行きたいので、Vector3(-my_power, 0, 0)と、x軸にはマイナスに力を働かせている。また、Vector3()というのは、Vector3(0, 0, 0)のこと。だから、物体のど真ん中に、-x軸方向の力を加えたことになる。
  3. 同様に、
    "my_right"なら、+x軸方向に、
    "my_up"なら、-z軸方向に、
    "my_down"なら、+z軸方向に、
    動くようにしているだけ。簡単。

このスクリプトを貼って、シーンの再生(又はゲームの再生)をしてみれば分かるが、このままでは、ちょっと問題もある。それは、、、次回解決。と思ったけど、やっぱ書いておこう。


スリープ(sleep)の解除とダンプの設定

[1] スリープ

実際にやってみると分かるが、急いでキー入力をして玉を動かさないと、その後一切のキー入力を発見してくれなくなるのだ。これは、リジッドボディーがスリープの状態に入ってしまうからだ。

シーンの再生後、玉はすぐに上から落ちてくる。ゴン。そして動かなくなる。ピタッ。そのまま、しばらくじっと見てると、Godotは「これ、止まったな。」と判断する。「これ、止まったな。」と思ったら、Godotは以後その物体に対して物理演算をしなくなってしまうのだ。この状態がスリープだ。

物理演算っていうのは、動いてないものに対して行うのはパワーの無駄遣いでしかないので、止まったと判断した物体には行わない。演算を行わないので、_integrate_forces(state):関数は呼ばれなくなる。よって、このバーチャル関数の中に書いた処理はなされない。

つまり今回は、_integrate_forces(state):関数内でAction(キー入力)データのチェックをしてるから、スリープ状態になると、キー入力のチェックはしなくなると言うわけ。

で、この解決方法なんだが、色々あるが、リジッドボディーがスリープしないようにしちゃうってのが、一番手っ取り早い。場所はココ。
f:id:ore2wakaru:20180307222703p:plain
チェックを外そう。これでリジッドボディーがスリープしなくなる。

何百個、何千個もスリープさせないようにするのは流石にどうかと思うが、1個だけだからね、今回は。これで解決としよう。

[2] ダンプ

これで玉は動くが、ちょこっとキーを押すと、その後も動きっぱなしで止まらない感じではなかろうか? ということで、ココをいじる。
f:id:ore2wakaru:20180307223821p:plain
"damp"ってのは「弱める」ってことらしい。"-1"の時は何もしないってこと。"0"超~"1"以下で、弱める強さを設定できる感じだ。俺は、"0.9"を入れたので、結構な強さで弱めている感じだ。「強さで弱める」とか、意味不明かもしれないが、数字がデカければ早く止まるってことね。ま、いろいろ数字を入れて試してみて。

ちなみに、今回は、"Linear""Damp"を設定して、移動の速度を減じたが、この下の項目、"Angular""Damp"だと、回転を減じることが出来る。


それから、最後に、玉が落ちてくるスピード、遅くなったはず。これは下方向に動くときもダンプが効いてるから、重力が弱められた感じになってしまう。

これがイヤなら、_integrate_forces(state):の中身にx軸方向とz軸方向だけ弱めるコードを書けばいいんだけど、でもまー、今回はこれで。


コードのコピペ用

extends RigidBody

var my_power = 20.0

func _integrate_forces(state):
    if Input.is_action_pressed("my_left"):
        state.add_force(Vector3(-my_power, 0, 0), Vector3())
    if Input.is_action_pressed("my_right"):
        state.add_force(Vector3(my_power, 0, 0),  Vector3())
    if Input.is_action_pressed("my_up"):
        state.add_force(Vector3(0, 0, -my_power), Vector3())
    if Input.is_action_pressed("my_down"):
        state.add_force(Vector3(0, 0, my_power),  Vector3())