本講座では、UnityとC#を用いて3DFPSゲームを作成していきます。
前回はUnityプロジェクトを作成し、アセットの追加、フィールドの配置を行いました。
前回の記事 :
今回は自身の分身となるプレイヤーを作成していきます。今回からC#スクリプトを書いていきますので、「VisualStudio」や「VisualStudio Code」などのコードエディタを準備しておきましょう。
では始めます。
一人称視点のFPSゲームプレイヤーの作成
まずはFPSでもっとも重要なプレイヤーを作成します。
そもそもFPSとは何かというと、「First Person Shooter(Shooting)」の略です。つまり「一人称視点」=「自分の目からみた視点」のシューティングゲームを指しています。
なので「自分の目から見た」映像をカメラに映します。ということは「プレイヤーの移動」という操作が「カメラの移動」という操作になっていきます。
まずはこのことを念頭に置いて作成していきましょう。
プレイヤーオブジェクトとカメラオブジェクトの設定
まずはプレイヤーのオブジェクトを作成していきます。
今回は簡易的に人型のようなアバターは作成せずにプレイヤーとします。とは言え何もないとわかりにくいです。
そこで、Hierarchyで右クリックして「3D Object→Capsule」でカプセルを作成します。このカプセルの名前を「Player」とします。
次にHierarchyに既に配置してある「Main Camera」をドラック&ドロップして「Player」の子にしてください。
そして子に配置した「MainCamera」を選択して、InspectorでTransformを下記のように設定してください。カメラがカプセルの少し上あたりに来ます。高さは任意で変更しても構いません。
1 2 3 4 |
MainCamera の Transform Position( 0, 1.5, 0) Rotation( 0, 0, 0 ) Scale( 1, 1, 1) |
さらに「Player」を選択してまずは大雑把で構いませんので、フィールドの開始位置にしたいところに移動します。「Forest」をPosition( 0, 0, 0 )にしている場合、大きく上の方に行っているかと思いますので、下記を参考に「Player」を移動してみましょう。値の多少の違いは問題ありません(Forestの位置によっては下記とは違う場合もありあます)。
プレイヤーのカプセルが地面から少し浮いているくらいの位置に配置しましょう。
1 2 3 4 |
Player の Transform Position( 219.24, 305.09, 263.35 ) Rotation( 0, 0, 0 ) Scale( 1, 1, 1 ) |
移動ができたら「Player」のInspectorの下の方にある「Add Component」というボタンを押してください。
ウインドウが出るので、その検索枠に「rigidbody」と入力し、下に表示された「Rigidbody」コンポーネントを選択します。すると、「Rigidbody」コンポーネントが付与されます。
付与された「Rigidbody」をみてください。まずは一番上の「Mass」を「5」に変更します。
次に真ん中あたりにある「Constraints」という項目の「Freeze Rotation」というところの3つのチェックボックスにチェックを入れておきましょう。
「Mass」は質量を表し、「Freeze Rotation」は物理的な影響による回転をフリーズする、つまり回転しないようにします。
できたら、一旦再生してみましょう。
開始したら、プレイヤーが少し落ちて地面で止まったでしょうか?
少し味気ないですが、これが今回操作するプレイヤーになります。今回はFPSなのでこのカプセルは画面に映りません。
スクリプトの作成
C#ファイルの作成と付与
ここからC#スクリプトを書いて移動する処理を作成していきます。
まずはファイルを作成していきます。「Assets/AppMain/Script」の中で右クリック「Create→C# Script」でC#スクリプトを作成し「AppPlayerController」という名前にします。
そして作成した「AppPlayerController」をInspectorの「Player」にドラック&ドロップします。すると「Player」にAppPlayerController」が付与されます。
ではスクリプトを記載していきましょう。「AppPlayerController」をダブルクリックしてコードを開きます。
スクリプトの基本を理解しよう
まずスクリプトを開くと
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class AppPlayerController : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } } |
この状態かと思います。
Unityでスクリプトを作成するとこれらの記載が最初から書かれているので、まずはこの解説を簡単にしていきます。
1 2 3 |
using System.Collections; using System.Collections.Generic; using UnityEngine; |
この部分は、このスクリプトで使用する部品を用意するといった意味になります。
「using UnityEngine」と書くことで「UnityEngine」の部品をこのスクリプトで使用しするという意味になります。
この「UnityEngine」の部分を「名前空間(namespace)」といい、自分で作成することも可能です。
今後別の部品を使用するときには例えば「using」に「UnityEngine.UI」を追加する、という言い方をしますので覚えておきましょう。
最後の「;」はC#の命令の区切りと覚えればOKです。
1 |
public class AppPlayerController : MonoBehaviour |
次にこの部分ですがまず「public」というのは「公開する」ことを意味します。
これは関数なども同じように「public」を付けることで他のスクリプトからアクセスができるようになります。逆に公開しない(非公開)場合は「private」を付ける、もしくはなにもつけないと非公開になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } } |
この部分のまずは「 { } 」に関して。
これは一つのグループ示しており、上記で一番上から最後まで囲われているカッコはクラスを人まとまりとしたカッコで、「Start」「Update」などの下にあるものはそれぞれの関数のカッコになります。
このカッコはなければならない部分とあることで意味をなす部分がありますが、今回の講座ではなければならないカッコしか出てこないので必要なものだと考えてください。
もしあることで意味をなすカッコを記載するときはそのときにまた解説いたします。
「// (英文)」の部分は「コメント」です。
ここは処理に関係なく文字を書くための部分で日本語を書いてもOKです。解説を書いたりなど自由に使用しましょう。
「void Start()」「void Update()」はUnityが用意している関数です。
関数というのは処理をひとまとまりにしたもので、この二つはUnityが用意しているので記載してあるだけで実行されます。
他にもこのように記載するだけで実行される関数もたくさんありますが、自作する場合は実行処理を記載する必要があります。
まず「Start」関数は、ゲームスタート時に一回だけ自動的に実行されます。
「Update」関数は、ゲームの再生中1フレーム毎に自動的に実行され続ける関数です。
どちらにもついている「void」ですが、この部分は「戻り値(返り値)」の型を記載します。「void」というのは「戻り値なし」を意味します。
例えば「string Test()」という関数があった場合、これは実行することで「string(文字列)」が結果として返ってきます。
では、この基本状態から自分で処理を追加していきます。
FPSゲーム開発に向けてスクリプトを書いてみよう
少し難しくなりますので、ゆっくり解説していきます。
まずは上記の作成したばかりの状態に、プレイヤーが移動するための処理を記載します。
Unityで移動処理を作成するには大きく分けると二種類あり、一つは「位置を変更し続けて移動する」、もう一つが「Rigidbodyに力を加えて移動する」です。
今回はこの「Rigidbodyに力を加えて移動する」方法を使用します。
では、まず移動処理を記載する前の準備を書いていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class AppPlayerController : MonoBehaviour { // 移動速度. [SerializeField] float moveSpeed = 300f; // 速度制限値. [SerializeField] float speedLimit = 100f; // リジッドボディ. Rigidbody rigid = null; void Start() { // リジッドボディの取得. rigid = GetComponent<Rigidbody>(); } void Update() { } void FixedUpdate() { } void MoveResistance() { } void StopForce() { } } |
「//」の行は解説用のコメントです。
まず、処理を記載するのは「public class AppPlayerController」のカッコの中です。
その中の一番上から「Start」関数の前にあるものが「変数」になります。「変数」というのは値を保管する箱のようなものと考えてください。
変数はこの場所でなく、「Start」と「Update」の間とかでも構いませんが、関数の外の見やすい位置に書いておきましょう。
まず変数の基本は
となり、例えば「Rigidbody」や「float」が型、「rigid」「moveSpeed」が変数名、「null」「300f」が初期値です。そして一部変数についている「[SerializeField]」というのは「属性」といいます。
「型」には「int(整数)」「float(少数)」「string(文字列)」「bool(真偽)」などの基本の型と「Rigidbody」などのようにクラスを型にすることがあります。
「変数名」はそのまま変数の名前です。
「初期値」は最初に入っている値です。「300f」のような数値(float方の数値は数値に「f」を付ける)や文字列の他に、「null」という値をとる場合があります。
「null」というのは特殊な値です。エラーの原因を特定したりする上でも重要な値ですが、今は「なにもないということを表す値」と覚えておけばOKです。
次に「属性」です。[ ]でくくって変数前につけると、その変数に特徴を持たせるものです。
そして[SerializeField]は「変数をシリアライゼーションするもの」という意味を持ちます。
しかしこの説明では流石によくわからないかと思うので、最初のうちは「privateな変数をUnityのInspectorで設定できるようにするためのもの」と覚えておきましょう。
1 |
rigid = GetComponent<Rigidbody>(); |
コメントにもあるように、ここではリジッドボディを取得しています。
という形で今回は「Rigidbody」を取得して、左辺の「rigid」変数に代入しています。
この「=」は右辺の値を左辺に代入するという意味を持ちます。
これを「Start」関数内に記載することで、ゲーム開始時に「rigid」に取得したリジッドボディが代入されます。
続いて、追加した関数「FixedUpdate」です。まだ中の処理は書いていません。
これは先に解説した「Update」関数に似た関数で、記載しておくと自動的に繰り返し実行される関数です。
「Update」「FixedUpdate」の違いは、「Update」は1フレームごとに繰り返され「FixedUpdate」は一定時間ごとに繰り返されます。
なぜこれら二つが必要かというと、1フレームというのは時間が一定ではありません。そのため「Update」関数で、ゲームオブジェクトに力を加えるような処理を行うと力のかかり方にムラが出てしまい、結果その力によって動くゲームオブジェクトの動きがガタガタしてしまいます。
そのため力を加えて動かすような処理を行う場合この「FixedUpdate」を使って、一定時間毎に一定の力を加えて滑らかに動かします。
図解すると下記のようになります。
残りの二つの関数「MoveResistance()」「StopForce()」はまた内容を追加する際に解説します。
FPSゲームプレイヤーの移動処理
では移動するための処理のうちまずは「FixedUpdate」関数内の処理を追加していきます。
まずは追加した処理の全文です。
Unityでの確認
Hierarchyで「Player」を選択しInspectorの「AppPlayerContoroller」をみてみましょう。
この「MoveSpeed」「SpeedLimit」が先ほど「SerializeField」を付けた変数です。ここで変更した値はちゃんと動きに影響しますので、便利ではありますが変更するとスクリプトでの初期値と違う値になり得ますので注意してください。
では、再生してみましょう。
まだカメラがプレイヤーに固定されていますのでわかりやすいように、左がSceneウインドウ、右がGameウインドウになります。
PCの「↑↓←→」キーもしくは「WSAD」を押して移動できたでしょうか?移動速度が速い場合はInspectorで「MoveSpeed」や「SpeedLimit」を調整してみましょう。
今回の記事はここまでになります。
次回はカメラの回転処理を作成しあたりを見渡せるように、そこからFPSゲームとしてさらに詳細を作成していきます。
また、今回もっと詳しくUnityやC#の文法を学びたい場合は「Unity C#プログラミング入門講座」も参考にしてみてください。今回の講座で出てきたエッセンスを詳しく解説しています。
ただし、かなり細かいところまで書いているので全部を一回で理解する必要はないです。引き続きゲームを作りながら慣れていきましょう。
次回の記事 :
コメント