ファイブボックス　Unityカリキュラム　Step6　あつ森風フィッシングゲーム

このサイトは「[プログラミング教室・ファイブボックス](https://www.fivebox.info/)」の　**Unity学習カリキュラム** ステップ６ 「あつ森風、フィッシングゲーム作成」のフェーズ１になります。

**他のサンプルカリキュラム**
[Step1　Unityの基本](https://qiita.com/Yoshida003/items/d2e5ea5445d72a2c1a0b)
[Step2　JumpGame](https://qiita.com/Yoshida003/items/77e87332ceb2d4218bc5)

このプロジェクトでは以下のような作品を作ります。
[あつ森風、フィッシングゲーム作成　(クリックでゲーム開始)](https://unityroom.com/games/fivebox_fish)
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/d1d4b8ab-4fc3-171c-9803-8ea371a1bbd3.png)](https://unityroom.com/games/fivebox_fish)
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/c7f063db-67e0-4306-77e9-28ca905ea02c.png)](https://unityroom.com/games/fivebox_fish)


## フェーズ1　仕様確認と環境構築

### 1-1,ゲームの仕様確認
この作品の通常のフローは以下の通りです。
<font color="Green">**通常のフロー**</font>
>❶魚を発生させる（乱数で魚の種類や大きさ、進行方向、ターン回数決定）
❶エサをセット（初期値は10個とし釣れるごとに1つ減少。なくなったら購入）
❷釣り糸を垂らす（エサと釣り竿の先端をRayでつなぐ）
❹魚の口先とエサがぶつかったら、特定の確率でヒットする
❺釣り上げる（釣り竿の先端にエサが触れたら魚を獲得）
❻釣った魚を記録する

さらに次のオプション機能を追加
<font color="Green">**オプション機能**</font>
>❶進行中のゲーム内容のセーブとロード（釣った魚、所持金、エサなど）
❷ランキング表示機能（大きさ順、金額順、釣った数の順など）
❸釣った魚の図鑑機能（釣った数、合計金額など）
❹エサの購入
❺釣り竿の購入
❻ステージ管理

これらのフローと機能を順に作成していきます。

### 1-2,プロジェクトの作成
**2D** のプロジェクトを指定し、プロジェクト名に **「FishingGame」** などの適当な名前を指定、保存場所に任意の場所を指定し、「プロジェクトを作成」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/83916483-12a3-823d-eb54-fc23db578165.png)
Webブラウザでゲームをプレイできるように、環境を変更します。
上部のメニューから、**File** => **Build Settings** をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/a6e9e209-d5e9-636f-ebd3-efd8d1f601ff.png)
**「WebGL」** を選択して **「Swich Platform」** をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/9d5c547c-d564-a6fd-c4e5-01319c4f625d.png)
さらに **「Player Settings」** のメニューを展開。
**「Player」** => **「WebGL」アイコンタグ** を選択 => **「Resolution」** の項目から
**[Default Canvas Width]** = 960
**[Default Canvas Height]** = 600
に指定されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/9b5f0387-a0d7-7a9f-6cf6-90526305653e.png)


作成されたプロジェクトに、初期状態で用意されている「Sceneフォルダ」、フォルダ内の 「SampleScene」 の名前をそれぞれ次のようにに変更しておきます。
フォルダ「Scene」=> **「01_Scenes」**
Scene「SampleScene」=> **「GameScene」**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/7752347b-0995-0d36-c4bd-a267729bf2f1.png)
Asset 内に次の3つのフォルダを用意しておきます。
<font color="blue">**「02_Scripts」**</font> => スクリプトファイルを保存するフォルダ
<font color="blue">**「03_Predabs」**</font> => プレファブを保存するフォルダ
<font color="blue">**「04_Sprites」**</font> => 画像ファイルを保存するフォルダ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/8ae109d2-ba45-8f09-3136-e623aad23ba4.png)
その他の設定やフォルダ作成は、必要に応じて都度行っていきます。
これでプロジェクト作成の準備は完成です。

### 1-3,魚の配列作成

##### 1-3-1,テキストファイルの用意
素材は　[こちら](https://drive.google.com/file/d/1_d_oqn0j8qltfJPNnR3GImIG0O7uI97M/view?usp=sharing) から取得してください。
Download後、メニューバーの「Asset」⇒「Import Package」でDownload下ファイルを指定し、取り込みます。

この作品では多くの魚のデータを使用しますので、別途用意するテキストファイルからデータを取り込みます。
取り込むデータは以下の通りです。

|データ|変数名|説明|
|:--|:--|:--|
|**Name**|<font color="DarkOrange">**f_Name**</font>|魚の名前|
|**Size**|<font color="DarkOrange">**f_Scale**</font>|魚の基準の大きさ|
|**ImgSize**|<font color="DarkOrange">**f_ImgScale**</font>|表示上の基準の大きさ|
|**Speed**|<font color="DarkOrange">**f_speed**</font>|魚の泳ぐ速さ|
|**Price**|<font color="DarkOrange">**f_Price**</font>|魚の基準の価格|
|**Level**|<font color="DarkOrange">**f_Level**</font>|魚をヒットさせる難易度（大きいほど難易度が高い）|
|**Sprite**|<font color="DarkOrange">**f_Img**</font>|魚の画像（別途用意）|

<font color="Green">**FishData**</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/c4994dab-5459-bd46-b02e-de9f4ab7802c.png)
上のようなイメージで作成します。
Unityの取り込むのは、タイトル行を除いたテキストファイルとなります。
テキストファイルは以下の条件で作成します。

**ファイル名** ：fish.txt
**区切り** ：タブクリり
**文字コード** ：utf-8

Aseets 内に<font color="blue">**「Resources」**</font>という名前のフォルダを作成し、用意した [fish.txt] を格納します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/82691530-b85f-9c38-e8ed-53db6e73b3d0.png)

画像素材は各自用意して頂くか、教室で用意した素材を取り込んで使ってください。
取り込んだ魚の画像は、事前に作成した<font color="blue">**「04_Sprits」**</font>というフォルダの中に<font color="blue">**「fish」**</font>というフォルダを作成し、その中に保存しておきます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/5069fcb2-4cba-11ae-e89e-fa9338375424.png)

##### 1-3-2,テキストデータ取り込み

このフェーズでは用意したテキストデータを取り込んで、2次元配列として保管します。
まずは、Aseets 内に配置した<font color="blue">**「02_Scripts」**</font> フォルダ内に<font color="Green">**[GameManager]**</font> というスクリプトファイルを作成します。
さらにHierarchy上に **「GameManager」** というオブジェクトファイルを作成し、スクリプトファイル **「GameManager.cs」** をアタッチしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/16095328-b52a-da08-2c59-355119b8727d.png)

データ取り込みで行う処理の流れは以下の通りです。
>❶ [fish.txt] 内のテキストデータを全部取り込む
❷ 取り込んだテキスト1行1行を1次配列に入れ込む ⇒ 108個の要素を含む1次配列
❸ テキストの行数と列数を取得して最終的に入れ込む2次配列のサイズを決める
❹ 2で取り込んだ1行1行を、for文を使ってタブ区切りで2次配列に変換する

**[GameManager.cs]** を立ち上げて、以下のコードを記述します。
まず、**NameSpace** に使用するシステムを追加します。


```c#:GameManager.cs
using System;
```
続いて使用する変数を用意します。

```c#:GameManager.cs
string[] textSauce;                 //テキストの加工前の一行を入れる変数
public string[,] fishdata;          //テキストの複数列を入れる2次元配列 
int rowLength;                      //テキスト内の行数を取得する変数
int columnLength;                   //テキスト内の列数を取得する変数
```
ここでは最終的なデータが格納される配列、<font color="DarkOrange">**fishdata[,]**</font> のみ <font color="Orange">**public変数**</font> にしています。
これは後に他classからも参照したいためです。

さらにデータ取り込みの関数 <font color="Green">**Initialization()**</font> を作成します。

```c#:GameManager.cs
void Initialization()      //データ取り込み処理
{
    //fish.txtのデータを取得するインスタンスを作成
    TextAsset textasset = new TextAsset();
    //Resourcesフォルダから対象のテキストファイルを取得
    textasset = Resources.Load("fish", typeof(TextAsset)) as TextAsset;
    //string型の変数を用意して、上で取得したテキスト全体を入れる
    string TextLines = textasset.text;
    //Splitで一行づつを代入した1次配列を作成、（改行で分けるので1行の文字列となる）
    textSauce = TextLines.Split('\n');
    //行数と列数を取得
    columnLength = textSauce[0].Split('\t').Length;     //タブ区切りで分けられたブロック数⇒6
    rowLength = textSauce.Length;                       //データ数⇒108    
    fishdata = new string[rowLength, columnLength];     //2次配列を定義 [108,6]
    for (int i = 0; i < rowLength; i++)
    {
        //textMessageをタブごとに分けたものを一時的にtempに代入,
        //temp[0]⇒魚名、[1]⇒大きさ、[2]⇒Spritの大きさ、[3]⇒速さ、[4]⇒価格、[5]⇒難易度
        string[] temp = textSauce[i].Split('\t');
        for (int j = 0; j < columnLength; j++)    //Dataの数だけ繰り返す
        {
            //2次配列fishdata[,]にタブごとに分けたtempを代入していく
            fishdata[i, j] = temp[j];
        }
    }
}
```

作成した関数を <font color="Green">**Start関数**</font> 内で起動させます。

```c#:GameManager.cs
void Start()
{
    Initialization();
}
````    
実際に起動させてみましょう。
Inspector の表示形式を **「Debug」** にすると、詳細を確認することができます。
「GameManager」のInspectorで **GameManager(Script)** の <font color="DarkOrange">**[TextSouce],[RowLength],[ColumnLength]**</font> がそれぞれ取り込んだ値と同じか確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/e43c5171-5259-c810-9e69-bcb36ff8cb7d.png)
Inspector の表示形式を **「Normal」** に戻しておきましょう。

:thinking:<font color="Green">**問題１**</font>
作成した配列に、正しくデータが格納されているか、<font color="Green">**foreach()**</font>関数を使って表示させてみましょう。

<details><summary><font color="Green">答え１</font></summary><div>
<font color="Green">foreach()文</font>を使えば、指定した配列の中身をすべて取り出すことができます。

```c#:GameManager.cs
void Initialization
{
    /*省略*/
    foreach (string s in fishdata)
    {
        Debug.Log(s);
    }
}
````    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/0fda9b81-dcce-92e8-4799-65c7ab7228dc.png)

<font color="Green">foreach() 文</font> の記述方法は以下の通りです。

```c#
foreach( 型名 オブジェクト名 in コレクション) {
    処理文
}
```
foreach文ではfor文のように、インデックス番号を指定する int型変数 i を定義したり、それをループごとにインクリメント(i++)する必要はありません。
また、コレクションの要素数を取得する必要もありません。ですので、簡潔に記述することができて便利です。

</div></details>

このプロジェクトでは、この後も多くの配列やリストを作っていきます。
リストから任意のデータを取り出す方法や、確認する方法をマスターしておきましょう。

##### 1-3-3,魚のスプライト
魚のスプライトは、GameManagerクラスにスプライト用の配列を作成し、Unity側からセットします。
では **「GameManager.cs」** を立ち上げて、配列を追加します。

```c#:GameManager.cs
public Sprite[] fishSprit;          //魚のイラストの配列
```

「GameManager」 の **Inspector** に宣言した <font color="DarkOrange">**FishSprite[]**</font>が表示されるので、index 数に ***108*** を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/6028cc9f-0d2a-f5b8-26dc-202a3ad7f920.png)
後は「fish.txt」と同じ順番で、要素に魚のスプライトをセットしていけばいいだけです。
魚のスプライト名は、fish.text の魚の名前と同じになっていることを確認しながら進めましょう。
順番を間違えたり、スプライト名が違ったりすると、この後作る機能の一部が正しく動かない状態になります。
完成イメージは下のような状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/4a2252fb-8b20-b4b6-0896-ba3d5c7b8eac.png)


### 1-4,背景画像作成
ここからステージ上のオブジェクトを作成、配置していきます。
まずは背景画像を作成します。
背景は画面下部に「海」の素材を、上部に「空」の素材をセットします。

##### 1-4-1,素材の準備
**「海」の素材**
「海」の素材は「フリー素材」を使っています。
ベースとなる画像を1つ、ベースの前面を左右に揺らし画像が動いているように見せる画像を1つ用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/2b12a454-310a-cc6b-8a3a-eaaf6f3f0715.png)
<font color="blue">**「04_Sprits」**</font>フォルダの中に<font color="blue">**「BackGround」**</font>  フォルダを作成し、そこに入れておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/c6ea7409-0f50-ce0a-7038-9ff1d9cac26a.png)

**「空」の素材**
「空」の画像は **AssetStore** から取得します。
**「AllSky」** の無料版を選択し、取り込んでおきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/62d318e4-8105-d342-fd16-9020ad8dd822.png)

##### 1-4-2,「海」の背景をセット
まずは、ゲーム画面の表示サイズを設定します。
[1-2]で選択したWebGL上での見え方に統一しておきましょう。
**「Game」タブ** を選択し、画面サイズ変更メニューから一番下にある **「+ボタン」** を押します。
展開された **「Add」メニュー** で以下のように指定。
**[Type]** => **Fixed Resolution**
**[Width & Height]** => **960 × 600**
 最後に **「OK」ボタン** を押して確定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/47d9d7a2-8665-6dd8-2b56-6804facc5cbd.png)

続いてHierarchy上で、オブジェクトを作成。
UI => Image を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/23654895-6e35-b119-a0f1-295f0955b449.png)
生成された「Image」を **Inspector** から設定します。
❶名前を **「SeaImage」** にリネーム
❷RectTransformコンポーネントで位置、サイズを下のように指定。
❸Imageコンポーネントで「Source Image」に取り込み済みの **「SeaImg1」** を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/3c8f799c-c27f-2a6f-f4b7-a10fc197d249.png)
この段階では以下のような表示となっているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/18d629ad-8d48-c781-01cf-14d766a694ac.png)

##### 1-4-3,「空」の背景をセット
空の背景には、AssetStoreから取得した「AllSkyFree」の「Epic_BlueSunset」フォルダの中の「Epic_BlueSunset_Cam_0_Front+Z」という素材を使用したいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/a411e801-7a2b-cc28-c6d6-4b13d56625c7.png)
ただこのままでは使用できないので、選択した画像の **Inspector** から画像タイプの修正を行います
**Texture Type** => **Sprit(2D and UI）**
最後は **「Apply」ボタン** で確定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/17c56a67-4a06-54f5-243b-77ccd6e0d5e5.png)
先程の「海」の画像の追加と同様に、Canvas上に新たな **Image** のオブジェクトを追加します。
海の画像よりも奥のレイヤーにしたいので、「Canvas」の子要素の一番上に配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/4da3da1a-6640-410e-0dd9-05582cd60acd.png)
生成された「Image」を **Inspector** から設定します。
❶名前を **「SkyImage」** にリネーム
❷RectTransformコンポーネントで位置、サイズを下のように指定。
❸Imageコンポーネントで「Source Image」に取り込み済みの **「Epic_BlueSunset_Cam_0」** を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/7e0ee005-2cce-e3c3-70ad-185779ab2404.png)
以下のようなイメージとなっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/c97bab2c-37c9-597f-98f7-9e5e9d9359c9.png)

##### 1-4-4,「波」の背景をセット
波はプログラムから動かしますが、その為には「worldSpace」に指定する必要があります。
Scene上に配置されるオブジェクトと同じ「worldSpaceに位置する」という意味になります。
しかしもともとのCanvasはとても大きいため、ベースの大きさを縮小します。
「Canvas」の Inspector から以下のパラメータを修正します。
❶RectTransformコンポーネント
 ・PosZ　の値を　10　に指定　 
　　※今後の課題で作る釣り糸を表示するために必要になります
 ・Scale の X Y をそれぞれ 0.04 に指定 
❷Canvasコンポーネント
 ・RenderMode を World Space
 ・EventCamera を Main Camera
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/68fec6bc-2bcd-d5a6-171b-682b3e8ac820.png)

Hierarchy上に新たな「image」オブジェクトを作成し、**Canvasの子要素の一番下** に配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/f1bc4f4d-ce84-ad2f-1586-f6ee07e8bace.png)
Inspectorから以下のように設定します。
❶名前を「WaveImage」に指定
❷RectTransformコンポーネント
　**Width** => 1500  左右に揺らすので、画面幅より大きめに指定します
　**Height** => 500
　**PosY** => -91  ちょうど海面と同じ高さになるように調整します
❸Imageコンポーネント
　**Source Image**  => 「Wave」　取得した画像を使います
　**Color**  => A（Alpha値：不透明度）を 0.5　後ろの海の画像が透けて見えるようにセット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/f044ba2e-a2cd-3d31-e80d-58b0f658687b.png)
さらに、<font color="Green">**RigidBody2D**</font>コンポーネントを追加します。
スクリプトファイルでのみ動かすので、**Body Type** を **「Kinematic」** にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/fc7863de-a97f-d950-020f-6106a2b08064.png)

続いて波を動かすスクリプトファイルを作成します。
「02_Scripts」フォルダ内に、<font color="Green">**[ WaveManager ]**</font>スクリプトファイルを作成してください。
作成した **「WaveManager.cs」** は **「WaveImage」** にアタッチしておきます。

:thinking:<font color="Green">**問題２**</font>
RigidBody2D　を使って、**「WaveImage」** を波のように左右に揺らし続けるプログラムを作ってみましょう。

<details><summary><font color="Green">答え２</font></summary><div>
この課題はtransform の Position を使ってみできるのですが、y座標の変更があった際など、都度プログラムの修正が必要になります。またRigidBody2Dの方が滑らかに動くようなので、今回はRigidBody2Dを使って動かします。
解答例：

```c#:WaveManager.cs
Rigidbody2D rb2d;
void Start()
{
    rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
    rb2d.velocity = new Vector2(Mathf.Sin(Time.time / 2), 0);
    //Time.time で周期をとっていますが、早すぎるので2で割って調整しています。
}
````    
</div></details>

これで背景の調整は完了しました。

ではここで、WebGlで正しく表示されるか確認しておきます。
上部メニューの「File」から **「Build And Run」** を選択。
初回のみファイルを保存する場所を聞いてくるので、任意のフォルダを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/d6e52c5f-86a6-f96a-d556-421a44d07532.png)
初回は特に時間がかかるので、余裕を見て実行します。
成功すると以下のようにブラウザ上でゲームのSceneを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556505/3ed54e2b-c836-af86-f3f2-8a02414d29ed.png)

最後までご覧いただき、ありがとうございます。
引き続きカリキュラムを参照したい場合は、「ファイブボックス」までお気軽にお問い合わせください。

https://www.fivebox.info/
Mail:ueda@fivebox.info
Tel:0268-71-7294

---
&copy; 2020 - 2022 FiveBox CORPORATION.