【ゲーム開発のためのC#入門講座・基礎拡張編】配列を使ってみよう【#5】

2.0_C#基礎拡張編

配列は初心者が最初にぶつかる壁かもしれません。

複数データを扱う時に便利ではあるのですが、最初のうちは混乱しやすいです。100%理解できなくとも、使うことさえできれば、少しずつ慣れていきます。あとで別のアプローチによる解説も予定してもいるので、今回はまず「こういうものらしい」レベルの理解を目指していきましょう!

複数のデータをまとめて扱いたい時に

例えばスコアを競うミニゲームがあったとしましょう。

この時、スコア結果を最大10個まで保存できるようにしたいとします。

これを今日まで学習してきた内容で実装しようとすると、下記のようなコードになるかと思います(設定している数値は適当なので特に意味はないです)。

int score1 = 0;
int score2 = 10;
int score3 = 20;
int score4 = 30;
int score5 = 40;
int score6 = 50;
int score7 = 60;
int score8 = 70;
int score9 = 80;
int score10 = 90;

それじゃあ保存されたすべてのスコアを表示するプログラムを作ってみましょう。

public class Hello{
    public static void Main(){
        int score1 = 0;
        int score2 = 10;
        int score3 = 20;
        int score4 = 30;
        int score5 = 40;
        int score6 = 50;
        int score7 = 60;
        int score8 = 70;
        int score9 = 80;
        int score10 = 90;
​
        System.Console.WriteLine(score1);
        System.Console.WriteLine(score2);
        System.Console.WriteLine(score3);
        System.Console.WriteLine(score4);
        System.Console.WriteLine(score5);
        System.Console.WriteLine(score6);
        System.Console.WriteLine(score7);
        System.Console.WriteLine(score8);
        System.Console.WriteLine(score9);
        System.Console.WriteLine(score10);
    }
}
出力エリア

0
10
20
30
40
50
60
70
80
90

うーん、非常に面倒臭いですね。

10個だからまだ頑張って実装できますが、これがもしスコア履歴を100個まで、あるいは1000個まで保存できるようにしたいとなると、とてもじゃないですが人力では無理そうです。

とはいえint型は整数のデータをひとつしか格納することができません。だからスコアひとつにつきひとつの変数を用意するしかないんですね。

複数のデータをまとめて管理する便利な機能はないものでしょうか?

それが配列です。

(うーん、何でプログラミングの用語はいちいち名前が堅苦しいんでしょうか)

配列を使うと複数データをまとめて管理できる

配列の解説をする前に、まずはその効果を体験してみましょう。

先程のプログラムを配列とforループを使った実装に変更してみます。

public class Hello{
    public static void Main(){
        int[] scores = {
            0,
            10,
            20,
            30,
            40,
            50,
            60,
            70,
            80,
            90
        };
        
        for (int i = 0; i < scores.Length; i++)
        {
            System.Console.WriteLine(scores[i]);
        }
    }
}

どうでしょうか。

さっきまでの長大なコードがだいぶすっきりして見えますね。

配列って何?

配列とは、指定した個数分の変数をまとめる機能です。

まずは配列の定義方法を確認しましょう。

int[] scores = {
    10,
    20,
    30
};

配列ではこのように、まとめて管理したいデータを一括で定義します。データ型の横についている「[]」という表記が複数データ(配列)であることを表しています。

この命令を受けてコンピュータはまず、定義されたデータ数分、指定のデータ型の変数を作成します。

そして作成した変数に、上から順番にデータを格納します。

そして名前の代わりに、上から順番に数字を割り当てていきます。この時、割り振られる数字は0からスタートします。

これでint型の配列「scores」が完成しました。

変数がCD-RWであるならば、配列はそれをひとつのケースにまとめたようなもの。

つまるところ配列とは複数の変数の集合体なのです。

そして作成した個々の変数を読み書きしたい時は、名前の代わりに割り当てられた番号でアクセスします。

scores[0] = 20; // 0番を割り当てられた変数に20を上書き
System.Console.WriteLine(scores[2]); // 2番を割り当てられた変数を参照

この名前代わりの番号はデータを特定するためのキーであることから、インデックスと呼ばれています。これも単語の意味を考えるとわかりやすいかなと思います。

便利な機能ではあるのですが、インデックスが0からスタートするというのが慣れないと非常に厄介なところ。感覚的には1つ目の変数はインデックス1という方がわかりやすいのですが、1つ目の変数のインデックスは0である点にご注意下さい。

だから先程のプログラムでは、forループの初期値を0にしていたんですね。初期値に1を設定してしまうと、インデックス1から処理されてしまうから。

public class Hello{
    public static void Main(){
        int[] scores = {
            10,
            20,
            30,
            40,
            50,
            60,
            70,
            80,
            90,
            100
        };
        
        // ↓インデックスが0からスタートするので、初期値は0
        for (int i = 0; i < scores.Length; i++)
        {
            System.Console.WriteLine(scores[i]);
        }
    }
}

プログラミング言語によっては何番からインデックスを割り当てるかを指定できるものもあります。ただ、大抵のプログラミング言語は0からスタートします。なので、しばらくは間違えたりすることもあるかと思いますが、0からスタートするものとして慣れてしまった方がよいです。

改めて配列の構文を確認してみましょう。

// 配列を定義する時の構文
データ型[] 変数名 = {
    格納したいデータ定義(複数あれば「,(カンマ)」区切りで)
};

// 配列の個々の変数にアクセスする時の構文
配列の変数名[インデックス]

データ定義の部分は「,(カンマ)」区切りであれば別に改行しなくてもよいです。が、改行した方が見やすいので、そういうものとして覚えてしまうことをオススメします。

forループとの合わせ技が便利

forループの条件で見慣れない「.Length」という記述がありましたね。

あれは配列のデータ数が格納されている変数です。

インデックスが0から始まる関係で、配列に格納されているデータ数がちょうどインデックスの範囲外になるんですね。

なので初期設定に「i = インデックスが始まる0」、条件に「i < 配列のデータ数」を設定してあげると、配列に格納したデータをひとつずつループで処理することができるんです。

ループ処理

1回目のループ:i = 0なので、インデックス0の変数に対して処理を実行
2回目のループ:i = 1なので、インデックス1の変数に対して処理を実行
3回目のループ:i = 2なので、インデックス2の変数に対して処理を実行
……
n回目のループ:i = 配列のデータ数(つまりインデックスの範囲外)なので、ループ処理を終了

配列で複数のデータをまとめて定義し、forループを使って複数データをまとめて処理する。この合わせ技は非常に強力なので、ぜひ覚えておきましょう。

配列の入れ物だけ用意する方法

あらかじめ設定する値が決まっている場合は先述の通りでよいです。が、まだどんな値を設定するかは決めていないが、指定した数の入れ物だけ用意しておきたいという場面もあります。

その場合は下記のように配列の変数を定義します。

int[] scores = new int[2];
<構文>
データ型[] 変数名 = new データ型[データ数];

このように記述すると、指定された個数分の変数だけをまず作成することができます。個々の変数にはそのデータ型の初期値(数値の場合は0)が設定されているので、あとはインデックスでアクセスしてデータの読み書きをしていくことになります。

public class Hello{
    public static void Main(){
        int[] scores = new int[2];
        System.Console.WriteLine(scores[0]);
        
        scores[0] = 20;
        System.Console.WriteLine(scores[0]);
    }
}
出力エリア

0
20

もうひとつの注意点

インデックスが0から始まること以外にもうひとつ、配列には注意点があります。

それは、途中でデータ数を変更することはできないということ。

もし仮に3個のデータを設定した配列を作ったら、その配列のデータ数を後から4個以上に拡張することはできません。

じゃあデータ数を途中で変更したい場合はどうするの? という話になりますが、これは配列以外の複数データ管理方法で実現することができます。そちらはもう少し後で学習予定なので、少々お待ちください。

もし割り当てられたインデックスの最大値よりも大きい番号を指定すると、そんな番号のデータはないとエラーを吐かれてしまいますので、注意しましょう。

public class Hello{
    public static void Main(){
        int[] scores = new int[2];
        // ↓データ数が2なので最大インデックスは1だが、2を指定してみた
        System.Console.WriteLine(scores[2]);
    }
}
出力エリア
Unhandled Exception:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at Hello.Main () [0x00008] in /workspace/Main.cs:5 
[ERROR] FATAL UNHANDLED EXCEPTION: System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at Hello.Main () [0x00008] in /workspace/Main.cs:5 

Unityでの活躍ポイント

Unityではオブジェクト(キャラクターやイラストなど)に対して、コンポーネントと呼ばれる追加パーツを好きなだけくっつけて動かすようになっています。C#のプログラム側から自分に紐づいているコンポーネントを検索する際、下記のようなコードを記述します。

AudioSource audioSource = GetComponent<AudioSource>();

AudioSourceというのは、そのオブジェクトに紐づく効果音などを再生する時に使うコンポーネントです。

もしオブジェクトに紐づく効果音が複数ある場合は、GetComponentsという複数形の命令で検索します。

AudioSource[] audioSources = GetComponents<AudioSource>();

データ型のところに「[]」がついていることからわかるように、この命令の結果は配列として返されます。そのため、返された配列に対してインデックスでアクセスし、ひとつ目の効果音を停止してからふたつ目の効果音を再生するなどのコードを記述していくことになります。

このようにUnityが持つ独自の命令でも配列を使う機会があるので、少しずつ扱いに慣れていきましょう。

実践演習

それでは、実際に配列を使ってみましょう。

演習①配列を定義しよう

仕様

下記のデータが格納されたstring型の配列「skills」を作成してください。
“魔神剣"
“紅蓮剣"
“疾風剣"

テンプレート
public class Hello{
    public static void Main(){
        // ↓ここに配列を定義しよう!
        
        // ここまで
        System.Console.WriteLine(skills[2]);
    }
}

演習②配列をループしよう

仕様

演習①で作成した配列を、forループを使ってすべて表示してください。

テンプレート
public class Hello{
    public static void Main(){
        // ↓ここに配列を定義しよう!
        
        // ここまで
        // ↓この処理をforループに書き換えよう!
        System.Console.WriteLine(skills[2]);
        // ここまで
    }
}

答え合わせ

演習①の答え

public class Hello{
    public static void Main(){
        // ↓ここに配列を定義しよう!
        string[] skills = {
            "魔神剣",
            "紅蓮剣",
            "疾風剣"
        };
        // ここまで
        System.Console.WriteLine(skills[2]);
    }
}
出力エリア

疾風剣

演習②の答え

public class Hello{
    public static void Main(){
        // ↓ここに配列を定義しよう!
        string[] skills = {
            "魔神剣",
            "紅蓮剣",
            "疾風剣"
        };
        // ここまで
        // ↓この処理をforループに書き換えよう!
        for (int i = 0; i < skills.Length; i++)
        {
            System.Console.WriteLine(skills[i]);
        }
        // ここまで
    }
}
出力エリア

魔神剣
紅蓮剣
疾風剣

まとめ

  • 配列とは指定した個数分の変数をまとめる機能
  • 名前代わりの番号「インデックス」で個々の変数にアクセスする
  • インデックスは0からスタートする点に注意
  • 配列のデータ数は途中で変えられない点に注意

それでは、今回もお疲れ様でした!

また次の記事でお会いしましょう!

お借りした素材一覧

この記事では下記サイト様の素材をお借りしています。

ありがとうございました!

かわいいフリー素材集 いらすとや (irasutoya.com)

Posted by 夕目紅