前回は、SheepButtonを作成して、羊購入処理等を作りました。
前回の記事↓
今回はそのSheepButtonを複数並べるためのShopオブジェクトを実装していき、一通りクリッカーゲームとして遊べる状態を目指していきます。
また、記事内でこの記事まで実装したプロジェクトファイルをダウンロードできるようにしてあるので適宜活用してください。
Shopオブジェクト
今、Hierarchyビューを見ると、Canvas/Panel(Shop) の下にSheepButtonという状態になっています。
違う種類(金額等)の羊を選んで買えるようにしたいので、複数のSheepButtonを管理するオブジェクトとして、ShopスクリプトをCanvas/Panel(Shop)に作成していきます。
そして、SheepButtonはこのShopスクリプトから作るようにしたいので消してしまいます。
では早速今作ったShopスクリプトを修正していきます。
Shopスクリプト修正
まず、以下の3つのメンバ変数を宣言していきます。
- 前回作成したボタン(
SheepButton
)のプレファブ - 生成元になる羊データ(
SheepData
)の配列 - 生成したボタン(
SheepButton
)を保持するList
1 2 3 4 5 6 7 8 9 |
//購入ボタンプレファブ [SerializeField] private SheepButton sheepButtonPrefab; //生成元になる羊データ配列 public SheepData[] sheepDatas; //作成したSheepButtonをListで保持 public List<SheepButton> sheepButtonList; |
次に、Startメソッドを消し、新たにAwakeメソッドを作成します(Startメソッドの名前を「Awake」と変えるだけでよいです)
Awakeメソッド内では渡されたSheepData
配列の数だけforeach
で回し、SheepButton
プレファブをInstantiate
(生成)していき、sheepButtonList
に追加(Add)していきます。
Awakeメソッドとは
Unityのライフサイクル(裏で動いている初期化→更新→描画 など順番に呼び出す仕組み)の一つです。
今までは
- Start() →ゲームオブジェクトが生成されてからUpdateの前に一度だけ呼び出される
- Update() → 毎フレーム(例:1秒間に60回)呼び出されるメソッド
のみ使用してきましたが、AwakeメソッドはStart()よりも前、生成された時に呼ばれるメソッドになります。
今回のSheepButtonを生成する処理は後ほどセーブロード処理において「他のオブジェクトよりも先に作られていて欲しい」ので、Awakeメソッド内で処理をするようにしています。
これにより、SheepData
配列にSheepData
を準備した数だけボタンが生成されるようになりました。
1 2 3 4 5 6 7 8 9 10 |
void Awake() { //受け取ったSheepData配列の数だけSheepButtonを作成 foreach (var sheepData in sheepDatas) { var sheepButton = Instantiate(sheepButtonPrefab, transform); //transformを指定することで、子要素に生成 sheepButton.sheepData = sheepData; sheepButtonList.Add(sheepButton); } } |
なお、ここでの注意点はInstantiate
の引数に自分自身(Shopオブジェクト)のtransformを指定することで、SheepButton
を自分自身の子要素にしつつ生成している事です。
では一旦スクリプトを保存して、UnityEditorでInspectorのセット、挙動を確認してみましょう。
Sheep Button Prefab には前回作ったSheepButtonプレファブを、
Sheep Datas には、とりあえず作ってあるScriptableObjectであるSheep1とSheep2をセットしておきましょう(羊の値段が安い順が良いです)
さて、再生して確認をしてみると
おや、羊購入ボタンが一つしか見えないですね? しかしHierarchyビューを見ると羊購入ボタン(SheepButton)はちゃんと2つ作られています。
これはまったく同じ場所に作られてしまったため、1つに見えている状態です。
ということは、生成する時(またはした直後)に位置やサイズを変更しながら作る必要があるという事でしょうか。
LayoutGroup(レイアウトグループ)
もちろんその方法でも構わないのですが、Unityの標準UIには LayoutGroup(レイアウトグループ)という、複数UIの位置合わせをしてくれる機能(コンポーネント)があります。
これには
- Horizontal Layout Group(横に並べるレイアウト)
- Vertical Layout Group(縦に並べるレイアウト)
- Grid Layout Group(格子状に敷き詰めるレイアウト)
があります。
今回はGrid Layout Group(格子状)を使いましょう。
Grid Layout Group の追加
HierarchyビューでCanvas/Panel(Shop) を選択し、InspectorからAdd Component で Grid Layout Groupを追加します(Layout→Grid Layout Group と選択しても良いですし、検索ウインドウにGrid Layout Group と直接打ち込んでも構いません)
GridLayoutGroupには色々と設定が出来ますが、とりあえず今は初期設定のままで構いません(後でCell Sizeだけ修正します)
キレイにボタンが並びましたね!
ちゃんと、渡したSheepDataが適用されているか(羊の色、初期価格)も確認しておきましょう。
SheepButtonへ依存オブジェクトのセット
さて、購入ボタンは並びましたが、購入ボタンを押しても羊が作られないですね?
それどころか、Consoleウインドウには赤い文字でエラーが表示されています。
これは、再生中にHierarchyで生成されたSheepButton(Clone)を選択して、Inspectorを見ると分かるのですが、SheepGeneratorオブジェクト と Walletオブジェクト が None(設定されていない)状態になっているのが原因です。
「いや、これ前回セットしたはず・・・」と思うかもしれませんが、それはあくまでもSceneに最初から配置してあったSheepButtonへの設定です。そのSheenButtonは先ほど消してしまいましたね。
プレファブにSceneのオブジェクトはセット出来ない(どのSceneで使われるか分からないため)ので、この2つがNone状態なわけです(この辺り、初学者さんが躓きがちだと思います)
これを解決する方法には
- GameObject.Find 系メソッドを使って、Sceneから探し出す
- WalletやSheepGeneratorはシーンに一つしかないので「シングルトンオブジェクト」にする
- SheepButtonを生成するオブジェクトが責任もって渡してあげる(バケツリレー)
(他にはDI、サービスロケータなど使う事もありますがとりあえず今は考えないことにします)
などなどありますが、今回は
- SheepButtonを生成するオブジェクトが責任もって渡してあげる(バケツリレー方式)
をしてあげることにします。
SheepButtonを生成するオブジェクト、すなわち ShopオブジェクトにWalletオブジェクトとSheepGeneratorオブジェクトを持たせて、生成時に渡すようにしてあげます。
修正後のShopスクリプトは以下のようになります。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Shop : MonoBehaviour { //購入ボタンプレファブ [SerializeField] private SheepButton sheepButtonPrefab; //生成元になる羊データ配列 public SheepData[] sheepDatas; //作成したSheepButtonをListで保持 public List<SheepButton> sheepButtonList; //SheepButtonにセットする羊生成オブジェクト [SerializeField] private SheepGenerator sheepGenerator; //SheepButtonにセットする所持金オブジェクト [SerializeField] private Wallet wallet; void Awake() { //受け取ったSheepData配列の数だけSheepButtonを作成 foreach (var sheepData in sheepDatas) { var sheepButton = Instantiate(sheepButtonPrefab, transform); //transformを指定することで、子要素に生成 sheepButton.sheepData = sheepData; sheepButtonList.Add(sheepButton); sheepButton.sheepGenerator = sheepGenerator; sheepButton.wallet = wallet; } } } |
では保存して、ShopオブジェクトにInspectorでSheepGeneratorとWalletをセットします。
エラーが出なくなっているか、ちゃんと押したボタンに対応する羊が生成されるようになっているか確認してみましょう。
エラーも無くなりましたし、それぞれに設定されたSheepData通りに羊が生成されていますね。
ですが、Woolの売却価格がどれも100円なので、高い羊を買う意味がありません。また、Woolに色が無いので大分地味です。
この辺りを修正していきましょう。
Woolスクリプト修正
今、Woolスクリプトは以下のようになっています。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Wool : MonoBehaviour { [SerializeField] private Rigidbody2D _rigidbody2D; //羊毛の売却価格 public int price = 100; //羊毛の売却処理 public void Sell(Wallet wallet) { wallet.money += price; Destroy(gameObject); } // Start is called before the first frame update void Start() { _rigidbody2D.AddForce(Quaternion.Euler(0, 0, Random.Range(-15, 15)) * Vector2.up * 4, ForceMode2D.Impulse); transform.localScale = Vector3.one * Random.Range(0.4f, 1.5f); } // Update is called once per frame void Update() { if (transform.position.y < -5) { Destroy(gameObject); } } } |
見て分かるように、売却金額を表す変数 price
はありますが、100で固定になってますね。
売却金額についてはこのメンバ変数(price)をSheepから設定してあげればよいので特に修正の必要はありませんが、
色替えについては「何色にするか」を設定するためのColor 変数 が必要ですし、
画像の色を変えるためには羊毛の画像を描画している SpriteRenderer が必要です。
そのため以下のメンバ変数を追加します。
1 2 3 4 5 |
[SerializeField] private SpriteRenderer woolSpriteRenderer; //羊毛の色 public Color woolColor; |
そして、Startメソッド内で受け取った色に変更してしまいましょう。
なお、その際にアルファ値(透明度0~1.0f →0になればなるほど透明)を修正して、半透明にしてあげたいため、woolColor.a
に 0.9f
を設定しています。
こうすることで、羊が羊毛に隠れてしまう対策と一緒にふわふわ感を出します。
1 2 3 4 5 6 7 8 |
void Start() { _rigidbody2D.AddForce(Quaternion.Euler(0, 0, Random.Range(-15, 15)) * Vector2.up * 4, ForceMode2D.Impulse); transform.localScale = Vector3.one * Random.Range(0.4f, 1.5f); woolColor.a = 0.9f; //ちょっと半透明に woolSpriteRenderer.color = woolColor; } |
では、保存をしてUnityEditorに戻ります。
Hierarchyビューのwoolオブジェクトを選択すると、Wool(Script)のWool Sprite Renderer が None になっていると思いますので、自身のSprite Renderer をセットしましょう。
ついでに色々と設定を変更します。
- Price を 10 に(最初から100だと羊が買えすぎてしまうため)
- Wool Color はとりあえず 白に
- Overrides → Apply All で変更をプレファブに適用
再生して確認してみましょう。
羊毛の売却金額が10円になって、羊毛が半透明(後ろが透けている)になっていればOKです!
Sheepスクリプト修正
まだ、羊毛の金額や色が決め打ち(Inspectorで指定したもの)になっているので、これらをSheepスクリプトから設定するようにしてあげましょう。
羊パラメータScriptable Objectの増産
Sheep1とSheep2は既に以前の講座で作っていますので、今回作るのはSheep3~8になります。
Assets/SheepDatas/ フォルダ内の Sheep2 を選択してから、CTRL+Dキーを6回押して、6つ複製します。
当然、この操作で作られたSheep3~Sheep8はコピー元(Sheep2)と同じ内容になってしまっているので、全て設定(レベルデザイン)をしましょう。
羊パラメータ例
あくまでも例でちょっと単調すぎますが、思いつかない方は以下の通りに設定してみてください
名前 | Color | Base Price | Extend Price | Max Count | Wool Cnt |
Sheep1 | ■(E0E0E0) | 10 | 5 | 10 | 5 |
Sheep2 | ■(FFBFBF) | 100 | 50 | 10 | 40 |
Sheep3 | ■(FADDA2) | 1,100 | 500 | 10 | 400 |
Sheep4 | ■(F9FF86) | 12,000 | 6,000 | 10 | 5,000 |
Sheep5 | ■(86FF88) | 130,000 | 60,000 | 10 | 50,000 |
Sheep6 | ■(9FD1FA) | 1,500,000 | 700,000 | 10 | 600,000 |
Sheep7 | ■(CAA0F8) | 18,000,000 | 8,000,000 | 10 | 7,000,000 |
Sheep8 | ■(FFFFFF) | 200,000,000 | 100,000,000 | 10 | 90,000,000 |
何と一番高い羊は基本が200,000,000(2億)円、10匹目まで買うときには1,100,000,000(11億)円になります。良いインフレ感です。
さて、羊データがSheep1~Sheep8まで準備できましたら、Hierarchyビューで、Canvas/Panel(Shop)を選択しShopスクリプトのSheep Datas に設定していきます。
では、再生して確認してみましょう。
色とりどりの8個のボタンが並びましたね!!
しかし・・・右に余白が出来ていてちょっと不格好です。
この羊購入ボタンの1個1個の横幅を広げて、キレイに敷き詰められるようにGrid Layout Group のCellSizeを修正します。
GridLayoutGroup CellSize(格子のサイズ)の修正
このCellSizeはGirdLayoutGroupが格子状に敷き詰めるUIの一つ一つの縦横幅を設定する項目になります。(最初は100×100です)
今回はこのPanel(Shop)で使える幅は横480 縦200なので、横に4列、縦に2列の8のボタンを置くためには、CellSizeには
- Cell Size X は480(横幅) ÷ 4列 = 120
- Cell Size Y は200(縦幅) ÷ 2列 = 100 (そのまま)
を設定しておきます。
では、改めてプレイボタンを押して、確認してみましょう。
ボタンもきれいに敷き詰められていますし、徐々に手に入る金額が大きくなっていく「クリッカーゲームの基本」が出来ているのではないでしょうか。
テスト用の羊の削除
さて、一通りゲームの本筋が出来上がりましたので、今シーンに最初からいるテスト用の羊は消してしまいましょう。
なお。羊毛(wool)も最初から一つ置いてありますが、これはそのままにしておきます。
というのも、この羊毛(wool)を売却することで最初の羊(sheep)が買えるようになるからです。
最初から羊が居るより、最初からお金を10円持っているより、
まったく前提知識が無くゲームを開始した人でも自然と「売却」ボタンを押し、売却したことで所持金が増え、羊が買えるようになる。羊からは最初にもあった羊毛が取れる。
と、語らずともゲームが開始できる仕組みづくり(のつもり)です。
購入テスト
ところで、一番高い羊(sheep)買うのは容易じゃないですよね。
そんな時は、最初からSceneに置いてあるwool のPriceを10→好きな金額に変更してしまいましょう。
(※ただし、intなので、最高で2,147,483,647≒21億です)
もちろん、テストし終わったら10に戻すのを忘れないようにしましょう!!!
おさらいと次回予告
今回はShopオブジェクトの作成と、羊パラメータの増産をして、一通り遊べる状態にできました。
次回はコイン取得演出の追加と、セーブ・ロード、スマホ解像度対応をして一旦の完成を目指します。
次回の記事↓
追記 Shop.csの全体
shop.csがどうなってるかの全体像がわからないという質問があったのでコード置いておきますね(もしかしたらこの先で修正などしてる部分混ざってるかもですがそのあたりは適宜削除したり修正して使ってください)。
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 40 41 42 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Shop : MonoBehaviour { //購入ボタンプレファブ [SerializeField] private SheepButton sheepButtonPrefab; //生成元になる羊データ配列 public SheepData[] sheepDatas; //作成したSheepButtonをListで保持 public List<SheepButton> sheepButtonList; //SheepButtonにセットする羊生成オブジェクト [SerializeField] private SheepGenerator sheepGenerator; //SheepButtonセットする所持金オブジェクト [SerializeField] private Wallet wallet; // Start is called before the first frame update void Awake() { //受け取ったSheepData配列の数だけSheepButtonを生成 foreach(var sheepData in sheepDatas) { var sheepButton = Instantiate(sheepButtonPrefab, transform); //transformを指定することで、子要素に生成 sheepButton.sheepData = sheepData; sheepButtonList.Add(sheepButton); sheepButton.sheepGenerator = sheepGenerator; sheepButton.wallet = wallet; } } // Update is called once per frame void Update() { } } |
コメント