UnityでFPSをつくる その3-2 [ プレイヤーの移動 ]

2020年5月27日

前回、ブログからソースコードをVisualStudioに貼り付けてもらったので、PlayerMoveスクリプトは以下のようになっていると思います。

No.65

タブの拡張子の後ろに「★」のマークが付いています。

No.66

これはスクリプトが変更されて、まだ保存が完了していない状態を示しているので、「Ctrl + S」を押して上書き保存してください。

次に、Unityの画面に戻ってPlayerを選択、InspectorウィンドウからRigidbodyコンポーネントのConstraints → Freeze Rotation X Y Z 全てにチェックを入れてください。

No.67

これにより全ての軸においてPlayerオブジェクトが回転をしなくなり、摩擦によってオブジェクトが転がる事を防止できます。

No.68


UnityのCubeやPlaneなどのオブジェクトには最初から摩擦や反発を発生させる機能がコンポーネントで付いています。

No.69

「None」となっていますが、これは「無し」という意味ではなく、"設定が変更されていない"="初期設定のまま"という意味です。
そして初期設定では摩擦が「あり」の状態になっているので、摩擦による回転を今回は軸を固定する事で防止しました。

次に、PlayerMoveスクリプトをPlayerオブジェクトにアタッチしてください。

No.70

Playerオブジェクトを選択後、InspectroウィンドウからPlayerMoveスクリプトのMoveSpeedの値を「5」に変更してください。

No.71

HierarchyウィンドウからPlayerオブジェクトをダブルクリックしてズームイン → シーンギズモの y を押して上からの視点にしましょう。

No.72
No.73

ツールバーの再生ボタンを押して実行します。

No.74
No.75

キーボードの矢印キー、もしくはW,A,S,Dキーで前後左右にオブジェクトが移動することが確認できると思います。
確認が終わったら、再生ボタンを押して再生を止めてください。

このスクリプトがどのようにオブジェクトを動かしているのかを見ていきたいと思います。
ProjectウィンドウのScriptsフォルダからPlayerMoveスクリプトをダブルクリックして開いてください。

No.76
No.77

VisualStudioでPlayerMoveスクリプトが起動しました。
まず最初の3行、これは種類ごとに分けられたクラス(スクリプトにおいて設計図の役割を果たすもの)を、省略した名前で使うことを宣言しています。
ファイルとフォルダの関係をイメージしてもらうと分かりやすいと思います。

No.78

スクリプトを書いていく内に、似たような機能を何度も使う場面が出てきます。
例えば、UnityEngine にまとめられている Collision と Physics と Vector3クラスを使おうと思った時、usingで宣言していない場合は
UnityEngine.Collision
UnityEngine.Physics
UnityEngine.Vector3
と同じ事を何度も書くことになります。
これを避けたい場合、using UnityEngine と宣言する事により、記述を省略できる仕組みになっています。
これにより、Collisionクラスを使う時は
Collision
とだけ書けば、内部的には
UnityEngine.Collision
として認識されます。

行の最後は「;」セミコロンで閉じます
これが付いていないと次の行以降もひと続きとみなされてエラーになるので忘れないようにしましょう。

次に5行目です

No.79

「public」これはアクセス度合いを示しています。
これが付いている事により、PlayerMoveクラスが他のクラスからも利用できるようになります。
「 : MonoBehaviour」これはPlayerMoveクラスがMonoBehaviourクラスを元にして作られている事を意味しています。
あるクラスの機能を受け継いで新しいクラスを作ることを「継承」と言い、継承先の新しいクラスは継承元クラスの機能に加えて、新たに定義した機能も使えるようになります。

No.80

6行目の「{」からクラスの内容が始まり、
68行目の「}」で終わります。

No.81

7行目、「//」を付けると、以降は改行されるまでスクリプトとして認識されません。
これは「コメント」と呼ばれ、書かれているスクリプトが何を意味しているのか注釈の用途で使われます。

No.82

これまで紹介してきた スクリプト内の「;」「:」「{}」「//」等の記号や、それ以外の記述は全て半角で書かれています。
スクリプトは半角英数字しか認識できない為、7行目のようにコメントとして全角文字を使う時以外は、「スクリプトは半角英数字で書く」という事を念頭に置いておいてください。

No.83

8行目、

No.84

7行目のコメントの通り、[SerializeField]を付けることで、その項目はInspectorに表示されて数値を変更できるようになります。
さきほどPlayerを動かす際にInspectorウィンドウからMoveSpeedの値を変更しましたよね。

No.85

このように表示されたのは、8行目に[SerializeField]を付けて書いたからです。
7行目のコメントの最後、「外部のクラスからは変更できない。」この意味は5行目で触れた「public」同様、アクセス度合いの事です。
8行目の記述を

No.86

と書き換えてもInspectorウィンドウには同様に表示されますが、この場合、外部のクラスからでも書き換えが出来てしまいます。
状況にもよりますが、外部から書き換えができるという事はエラーが発生した場合に原因の特定が困難になるリスクがある為、その必然性が無い時は基本的にクラス内のみでアクセスできるようにしておきます。

No.87

8行目の「float moveSpeed」これは floatのmoveSpeed変数を宣言しています。
変数が宣言されると、コンピュータのメモリ上にその変数の値を格納するための領域が確保されます。
型で予め指定された範囲内の値をこの領域で扱えるようになります。

No.88

次に11行目、これは10行目のコメントの通りです。

No.89

float型が予め指定された範囲内の値を扱えるのに対して、Rigidbody型は予め定義された項目を扱うことができます。
Inspetctorウィンドウに表示されたRigidbodyコンポーネントには色々な項目がありましたよね?

No.90

これはRigidbody型で定義されている項目の一部が表示されています。
Inspectorウィンドウに表示されていない項目も含めて操作していく為に、Rigidbody型のplayerRigidbody変数を宣言しています。
float型の時と違い、最初に[SerializeField]やpublicを付けていないため、Inspectorウィンドウに表示されず、外部からの変更もできないようになっています。

14行目、こちらも同じく [SerializeField]やpublicを付けていないので、Inspctorウィンドウ表示なし、外部からの変更不可の状態で、小数型(float型は小数点を扱えるため、こういう呼び方もできます)の変数を続けて宣言しています。

No.91

変数を続けて宣言する場合は「,」で区切る決まりになっています。「,」の後ろの半角スペースはあってもなくても構いません、ここでは見やすさ向上の為に付けています。
型と変数の間には半角スペースを必ず入れてください、入れない場合、一続きの字句として認識されてエラーになってしまいます。

16行目、bool型(真偽値型)の変数を宣言しています。float型が小数点の値を扱い、Rigidbody型がRigidbodyの項目を扱うのに対し、bool型は「true」と「false」を扱います。

No.92

真(true)か偽(false)どちらか、という意味で真偽値型とも呼ばれます。

No.93

20~24行目はStart関数で処理する内容が書かれています。
関数」とは、頻繁に使われる機能をまとめて、何度も呼び出せるようにしたものです。
Start関数はコメントの説明通り、最初のフレームだけ実行されます。
その際にどんな処理をしたいのかを { } 内に書きます。
今回はさきほど宣言したRigidbody型のplayerRigidbody変数にRigidbodyコンポーネントを割り当てました。

No.94

ゲーム実行中は1秒間に何十フレーム(FPSと呼ばれる単位、PCの性能や処理の負荷により変わる。Unityの初期設定はモニタのリフレッシュレートと同期していて60Hzなら60FPS)とリアルタイムに生成された画像の更新が行われます。

No.95

28~47行目のUpdate関数は毎フレーム実行されます。

No.96

31,33行目でキー入力を検知する処理を書いています。
「Input.GetAxis」はInputクラスのGetAxis関数を意味します。
そこに"Horizontal"という文字列(文字の連なり)を渡しています。
この"Horizontal"はUnityのInput Managerという入力を管理する部分で、最初から設定されている項目です。
Unityのメニューバーから Edit → Project Settings を選択してください。

No.97

Inputの項目にHorizontalとあるのが確認できると思います。

No.98

実行画面でPlayerオブジェクトが’W’,’A’,’S’,’D’キーと矢印キーで前後左右に移動したのは、ここでキーが設定されている為です。
ここで設定されている名前をInputクラスのGetAxis関数に渡すと、設定されたキーに入力があった場合、入力の度合いに応じて-1~1のfloat型の値を返します。
関数にどんな値を渡せて、どんな値が返ってくるのかは関数名にカーソルを合わせることで判ります。

No.99
No.100

先頭に float と書かれていて、float型の値を返す事を示しています。
()内には string axisName と書かれていてstring型=文字列を渡せる事を示しています。
どういった処理が行われるのかが、 Returns the value of the virtual axis identified by axisName. と書かれています。
さきほどの説明の通り、渡した文字列がInputManagerで設定されていた場合、対応するキーが押されたときに値を返すわけですね。
返された値を14行目で宣言したfloat型の moveX に割り当てます。
33行目は同じ事を"Vertical"と moveZ に置き換えて行っています。

このように関数に渡す値を「引数」、返ってくる値を「戻り値」と呼びます。

No.101

今回でいうと、31行目と33行目の
moveX = Input.GetAxis(“Horizontal");
moveZ = Input.GetAxis(“Vertical");
が上図➀。

23行目の
playerRigidbody = GetComponent<Rigidbody>();
が上図②。

20行目と28行目の
void Start(); ※ void は戻り値がないことを意味します。
void Update();
が上図④に該当します。

36~40行目では、if文を使って条件分岐を行っています。

No.102

if に続く () 内の条件式が満たされている場合、{} 内の処理が実行されます。
35行目のコメント通り、"Vertical"で指定したキーに入力があった場合、moveZ には -1~1 の値が入っているので、(moveZ != 0)の条件を満たし、bool型の変数 moveZpermission に true が入ります。
※「 !=」 は左側にある値と右側にある値が等しくない場合に true 、等しい場合に false を返します。
42~46行目は同じことを moveX と moveXpermission で行っています。

No.103

今回もだいぶ長くなってきたので、続きは次回にします。おつかれさまでした!

FPS

Posted by kenji