ひつじを動かそう

Last-modified: Wed, 15 Nov 2023 19:27:12 JST (163d)
Top > ひつじを動かそう

はじめに

プロジェクトを作成しようの続きです。

 

プロジェクトを作成しよう」では重力操作や当たり判定などの簡単な物理演算による操作を勉強しました。
しかし、さらに複雑な操作をしようと思うとプログラミングでの操作が必要になります。
そこで、このページでは Unity 上での C# のプログラミングの基本を勉強します。

 

今回は

1. ひつじを移動させる
2. 徐々に移動させる
3. スピードを調整できるようにする
4. キー入力で操作できるようにする

の4つをステップごとに実装して、 C# を学んでいきます。

 

ひつじをC#で動かす

C# を使って、他の重力操作や当たり判定などのようなコンポーネントを自作することができます
C# のファイルをコンポーネントとしてひつじにつけてみましょう。
AddComponent > NewScript を押し、「MoveSheep」と入力してください。
すると、プロジェクトの Assets に「MoveSheep.cs」というのが追加されました。

 

画像

 

これをダブルクリックします。

 
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class MoveSheep : MonoBehaviour
  6. {
  7.     // Start is called before the first frame update
  8.     void Start()
  9.     {
  10.     }
  11.  
  12.     // Update is called once per frame
  13.     void Update()
  14.     {
  15.     }
  16. }
 

エディターが開いて、このようなコードが出てきたと思います。
これがデフォルトの C# のコードになります。
初めて見る人には、何が何だかわからないと思いまが、少しづつ勉強していきましょう。

 

1. ひつじを移動させる

 

では、ここにいろいろ書き足して、実際にひつじを動かしてみましょう。

 
  1. // 省略
  2.     void Start()
  3.     {
  4.         // ここから書いていく
  5.         Vector3 pos = this.transform.position; // このオブジェクト(ひつじ)の位置を変数として取得
  6.  
  7.         pos.x = 3; // x座標を変更
  8.         pos.y = 4; // y座標を変更
  9.  
  10.         this.transform.position = pos; // 変数を代入
  11.     }
  12. // 省略
 

「void Start()」 の後に続く {} の中に上の通りに書き込んでください。
「//」から後は書かなくても大丈夫です。
(「//」より後はコメントアウトといって、プログラムとして読み込まれなくなります)

 

少し説明すると、ここでは関数の定義というのを行っています。
関数とは、簡単にいうと一連の命令をまとめたものです。
「Start」というのが関数の名前です。
「()」は、関数定義をする際に必要な記号です。
(「()」にも役割があるのですが、今回は割愛します。細かい関数に関する話はまた今度!)
関数を定義する際は、必ずその関数の呼び出し元に返す値として、戻り値というものを指定する必要があり、
その値のを定義の際に宣言しなければなりません。
ただし、今回は戻り値が必要ありません。
その場合は値を返さないことを指定するために、戻り値の型として「void」を使用します。
型というワードが出ましたが、型というのは値(データ)の種類のことです。
整数を入れる整数型、文字列を入れる文字列型やデータの集合を入れる配列型などがあり、C#ではこの型というのをその都度指定して書く必要があります。

 

Start() は、そのオブジェクトがゲームに出現したときに一番初めに一度だけ呼び出される関数です。
今回ひつじは、初めからゲームに出現しているので、ゲームを起動するとすぐに Start() 関数の中身の命令(後に続く {} の中の命令)が実行されます。

 

命令の中身を見ていくと、1行目は「 Vector3 という型の『pos』という名前を持つ変数にこのオブジェクトの位置を代入する」というものです。
は、C#では「左辺に右辺を代入する」といった意味で使われます。
Vector3 とは三次元ベクトルを扱う型になります。
ひつじ位置は(0,0,0)ですので「pos」には(0,0,0)が代入されたことになります。
2、3行目は「その変数のxy座標を(3,4)にする」、4行目は「このオブジェクトの位置を、新しい変数で代入する」といったものになります。
つまり2,3行目で「pos」が(3,4,0)になり、4行目でひつじの位置も(3,4,0)に変更されます。

 

以上の命令をまとめると、「ゲームが開始されてすぐに一度だけ、ひつじの位置が(0,0,0)から(3,4,0)に変わる」という命令になります。

 

実際に動かしてみましょう。
ファイルの変更を保存して、エディターを閉じ、ゲームを再生してみると、
ひつじは右上に移動したと思います。

 

2. 少しずつ動かす

 

ひつじは移動できましたが、これだと一瞬での移動になってしまいます。
しかし、多くのゲームでは瞬間での移動より少しづつ移動していくことが多いかと思います。
ということで次は、少しずつ移動できるように改良してみましょう。

 
  1. // 省略
  2.     // Start is called before the first frame update
  3.     void Start()
  4.     { 
  5. // 全部消す
  6.     }
  7.  
  8.     // Update is called once per frame
  9.     void Update()
  10.     { 
  11.         // ここから書いていく
  12.         Vector3 pos = this.transform.position; // このオブジェクト(ひつじ)の位置を変数として取得
  13.  
  14.         pos.x += 0.01f; // x座標を変更
  15.         pos.y += 0.01f; // y座標を変更
  16.  
  17.         this.transform.position = pos; // 変数を代入
  18.     }
  19. }
 

次は、一旦「void Start()」の中身を消して、「void Update()」の中身を上のように変えてください。

 

Update()そのオブジェクトがゲームに出現してから毎フレーム呼び出される関数です。
フレームとは、アニメーションのコマ割り、パラパラ漫画の一コマのようなもので、1つの静止画を表示させてから、次の静止画を表示するまでの間隔のことを言います。
先ほどと同様ひつじは最初からいますので、ゲームが開始したら毎フレームで Update() 関数の中身が実行されます。
中身についてみていくと、1行目と4行目はさっきと同じですね。
+」は「足す」演算子で、
特別に、

  1. A = A + B;

  1. A += B;

と書くことができます。
それを踏まえてみると、2、3行目では、「現在の変数のXY座標にそれぞれ 0.01 足す」というものになります。
ちなみに、数値の後にある f は数値が float 型(小数の型)であることを識別するためにつけます。(小数を扱う際は必ずつけます

 

まとめると、「ゲームが開始してから毎フレームごとに、XY座標がそれぞれ 0.01 ずつ増えていく」となります。

 

実際動かしてみると、少しずつ右上に移動するようになるかと思います。

 

3. スピード調節をする

 

今は、ひつじのスピードの係数(毎フレームに加算される数値の大きさ)は 0.01 で固定ですが、
ゲームによっては「これより早くしたい、遅くしたい」ということが多々あると思います。
しかし、調整のために毎回コードを書き換えるのは手間かと思います。
そこで、スピードを Inspector から自由に調節できるように改良してみましょう。

 
  1. // 省略
  2.     //ここに書き加える
  3.     public float speed = 0.01f; // 初期値付きで変数を定義
  4.  
  5.     // Start is called before the first frame update
  6.     void Start()
  7.     {
  8.     }
  9.  
  10.     // Update is called once per frame
  11.     void Update()
  12.     { 
  13.         Vector3 pos = this.transform.position;
  14.  
  15.         pos.x += speed; //0.01f から speed に書き換え 
  16.         pos.y += speed; //0.01f から speed に書き換え 
  17.  
  18.         this.transform.position = pos;
  19.     }
  20. }
 

Start() 関数の上と、 Update() 関数の中身をこのように変えます。

 

3行目では、変数の定義をしています。
変数は、データを保存しておく入れ物のようなものです。
変数の定義では、その変数の型と名前を宣言する必要があります。
今回はfloat型(小数を扱う型)として「speed」という名前の変数を定義します。
また、初期値を代入の形で指定することができます。(指定がない場合はそれぞれの型に設定されたデフォルトの値が入ります。)
今回は予め0.01fを初期値として入れておきます。
ところで、前にある「public」は、 Unity Editer の Inspector や他のスクリプトから「speed」の値を変更できるようになる合言葉のようなものです。(クラスの直下の{}記号の場所でだけ付けます。)
詳しい話は今度しますが、ここではこのように覚えておいてください。
変数の宣言場所に関してですが、基本的にどこでもできます。(もちろん例外はありますが。)
ですが、その変数を利用できる範囲は宣言した場所を含む直下の{}記号の内側だけです。
そのため、その変数の使用する範囲を考えて変数を宣言する必要があります。
今回の場合は、このクラスの外部( Unity エンジンの Inspector )からの利用があるため一番外側に書きました。

 

14,15行目では、数値を変数に置き換えています。
こうすることで、これまでは 0.01 で固定だったものが「speed」に入れる数値を変えることで変えられるようになりました。

 

実際にひつじの Inspector から「speed」の数値を変えて、ゲームを開始してみましょう。
ひつじのスピードは変わったでしょうか。

 

4. キー入力で操作できるようにする

 

今のままでは、ずっと同じ方向に行くばかりです。
しかし、ゲームではプレイヤーの操作(キーボードやマウスなどの入力)による操作が必要不可欠です。
そこで、次はひつじをキー入力で操作できるようにします。

 
  1. // 省略
  2.     // Update is called once per frame
  3.     void Update()
  4.     { 
  5.         Vector3 pos = this.transform.position;
  6.  
  7.         //pos.x += speed; ->消す
  8.         //pos.y += speed; ->消す
  9.  
  10.         //ここから編集
  11.         if (Input.GetKey(KeyCode.D)) // Dキーの入力があったら
  12.         {
  13.             pos.x += speed; // x座標に speed 分だけ加算
  14.         }
  15.  
  16.         if (Input.GetKey(KeyCode.A)) // Aキーの入力があったら
  17.         {
  18.             pos.x -= speed; // x座標に speed 分だけ減算
  19.         }
  20.  
  21.         this.transform.position = pos;
  22.     }
  23. }
 

これまでは、Update() 関数が呼び出されるたびに無条件で「pos」を増加させてきましたが、
今回は「特定のキーが入力されたら」という条件が満たされていれば「pos」を変化させる、という風に命令の実行に条件を設けたいわけです。
そこで使われるのが if 文になります。
if 文の書き方は、

  1. if (条件文) 
  2. {
  3. 命令文
  4. }

と、なっています。
条件文が満たされていれば(条件文の結果が「真」であれば){}の中の命令文が実行され、
条件文が満たされていなければ(条件文の結果が「偽」であれば){}の中の命令文は無視されるようになっています。
「真」「偽」と表現しましたが、コードの中ではそれぞれ truefalse という値で扱います。
この二値はbool 型と呼ばれる型で保存される値(bool 型は true 、false のみを扱う型)で、
if分を始め条件判定の際に頻繁に使われます
(以後、「真」を true 、「偽」を false として表記します)

 

次に「Input.GetKey(KeyCode.〇)」について解説します。
ここでは、Unity があらかじめ定義してくれている「特定のキーが入力されたか判定を取る」という命令をまとめた「Input.GetKey() メソッド」の関数の呼び出しになります。
先ほど、Start() 関数などの関数定義をしましたが、本来関数(場合によってはメゾットと呼ぶ)は定義のみでは利用できず、実際に使用する場所で呼び出す必要があります
(Start() 関数も Unity が私たちの見ないところで呼び出してくれています)
先ほど保留にした関数の「()」にも少しふれましょう。
これは、引数を指定するために用意されているものです。
引数とは、関数に渡す値のことです。
少し前で関数を「一連の命令をまとめたもの」と説明しましたが、
関数に値を渡すことで、その値に対して、またはその値を用いて一連の命令ができるようになります。
今回の場合は「特定のキーが入力されたか判定を取る」メソッドということですが、
「特定のキー」を引数として当たすことで、そのキーに対して、入力があったのか判定を取ることができるようになっています。

 

ということで、今回の例を見ていくと、
「Input.GetKey(KeyCode.D)」というのが、Dキーが入力されれば true 、されていなければ false が返されるため、
Dキーを押していると、「pos」のx座標が「speed」の大きさ分増えるようになり、
「Input.GetKey(KeyCode.A)」というのが、Aキーが入力されれば true 、されていなければ false が返されるため、
Aキーを押していると、「pos」のx座標が「speed」の大きさ分減るようになります。
(「-」は「引く」演算子で、「+」と同様に「-=」とすることで左辺から右辺を引くことができます)
何もキーを押していないと、どちらのif文の条件式も満たされないので、「pos」の値は変化しないことになります。

 

これを実行してみると、
ひつじはDキーを押している間は右に、Aキーを押している間は左に移動して、何も押していないと動かないようになったはずです。
(ただし「speed」が正の数の時だけ。負の数の時は左右逆に。 Inspector から正の数に直そう!)