前回は、羊オブジェクトの生成・移動処理を作りました。
前回の記事↓

今回は羊オブジェクトのパラメータを管理するオブジェクトを作っていきます。
羊パラメータの作成 ScriptableObjectの使い方をマスターしよう
さて、ちょっとずつ画面がにぎやかになってきましたが、まだ羊が1種類しかいません。
クリッカーゲームはインフレが特徴なので、お金をためて、違う種類の羊を買っていけるようにしていきましょう。
この「違う種類の羊」を表すために、少なくとも色は変えられるようにしたいところです。
その他色々考えると
- 羊の色
- 初期値段
- 1頭追加するごとに上がる値段の額
- 何頭まで購入できるか
- 羊が持つ羊毛の量
が、生成する羊の初期設定で必要です。
これらの初期データを設定するために「ScriptableObject」というものを作成したいと思います。
ScriptableObjectの作成
ScriptableObjectというのは、普段よくSceneに配置しているGameObjectのPrefabから、位置情報など(Transform)を抜いて、データを保持することに特化したもの。(位置などが無いので、Sceneに直接置けないPrefab?)だと思ってもらうとちょっと理解しやすいです。
Scriptable Objectはインスペクター上で設定できるデータファイルなわけですね。
同じようなデータ構造が色々出てくるものを一括でまとめておけて、コードをいちいちいじらずにデータ編集できるので便利です。例えばRPGだったら敵モンスター、魔法やアイテムのデータなどをScriptable Objectでファイルとして保存できます。
実際に使ってみるのが一番理解しやすいものでもあるので、早速作っていきましょう。
Assets/Scriptsを右クリックして、「Create」→「C# Scirpt」でスクリプトを追加します。
スクリプトファイルは名前変更状態になっていますので、「SheepData」という名前に変更します。
では早速、SheepDataスクリプトを修正していきます。
まず、最初は以下のような状態になっていると思います。
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 SheepData : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } } |
Unityでスクリプトを作ると、勝手にMonoBehaviourを継承した、GameObject用のスクリプトがテンプレートとして作られてしまいますが、今回は ScriptableObject を作りたいので、
SheepData : MonoBehaviour
は SheepData : ScriptableObject
に、
StartメソッドやUpdateメソッドも必要ないので消してしまいます。
1 2 3 4 5 6 7 8 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SheepData : ScriptableObject { } |
そして先ほど挙げた、羊データに必要なものを全てメンバ変数で宣言していきましょう。
- 羊の色 → Color color;
- 初期値段 → int basePrice;
- 1頭追加するごとに上がる値段の額 → int extendPrice;
- 何頭まで購入できるか → int maxCount;
- 羊が持つ羊毛の量 → int woolCnt;
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SheepData : ScriptableObject { /// <summary> /// 羊の色 /// </summary> public Color color; /// <summary> /// 初期値段 /// </summary> public int basePrice; /// <summary> /// 値段上昇額 /// </summary> public int extendPrice; /// <summary> /// 購入上限数 /// </summary> public int maxCount; /// <summary> /// 羊毛の量 /// </summary> public int woolCnt; } |
(※ コメント(“//”の後ろ)は大変なら書かなくても良いです。 できれば書いた方が良いですが)
そして、ScriptableObjectはこの単体では意味が無く、このスクリプトをベースに「Asset(アセット:Projectに配置出来るファイル)を作る必要があるため、クラスの宣言のひとつ前に1行、メニューからAssetを作れるように属性(Attribute:アトリビュート)を追加します。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu] public class SheepData : ScriptableObject { /// <summary> /// 羊の色 /// </summary> public Color color; /// <summary> /// 初期値段 /// </summary> public int basePrice; /// <summary> /// 値段上昇額 /// </summary> public int extendPrice; /// <summary> /// 購入上限数 /// </summary> public int maxCount; /// <summary> /// 羊毛の量 /// </summary> public int woolCnt; } |
さて、ではスクリプトを保存して、UnityEditorで実際にSheepDataのAsset(ファイル)を作っていきます。
まず、SheepDataを置くためのフォルダを作りましょう。
Assetsフォルダを右クリック→ Create → Folder で、「SheepDatas」フォルダを作りましょう。
(ついでに、スクリプトファイルがAssets直下に散らばっているようでしたら、Assets/Scriptsに移動させて、整理整頓しましょう。(私も忘れがちですが))

ここにスクリプトファイルいっぱい置かれていませんか・・・?
作ったAssets/SheepDatas フォルダで右クリックをし、Create→SheepData という追加されたメニュー項目を選択します(この右クリックメニューに追加するために[CreateAssetMenu] という属性(Attribute)を追加しました)
→
すると、このようにSheepDataのAsset(ファイル)が作られます。名前は Sheep1とでもしておきましょう。
Inspectorで各データがセット出来るので、以下のように設定します。
Color | 薄い灰色 |
Base Price | 10 |
Extend Price | 5 |
Max Count | 10 |
Wool Cnt | 5 |
気を付けたいのは、Color(色)は最初、透明度を示すアルファ値が0になっていて、まったく透明な状態になっている事です。しっかりと、アルファ値の値も設定(255で良いです)しましょう。
なお、色も全くの白ではなく、ちょっと灰色にしました。一番安い羊なので、ちょっと薄暗く(汚れた感じ?)にしてみたわけです。
とりあえず、羊の初期データが1つできました。では、次のちょっと高い羊のデータを用意します。
今作ったSheep1を選択して、CTRL+D(複製)します。
すると、Sheep2が作られましたね。
Sheep2はちょっと全体的に高くなります。色は何でもいいですが、パステルカラーの方がキレイなので、白に近い薄い色にしておきましょう。
Color | 薄いピンク |
Base Price | 100 |
Extend Price | 50 |
Max Count | 10 |
Wool Cnt | 40 |
これで、SheepDataがとりあえず2つ出来ました。最終的にはもっと増やしていきますが、とりあえずは以上でよいです。
では、SheepオブジェクトはこのSheepDataを受け取って、初期設定が出来るように直していきます。
Sheepスクリプト修正
では、Assets/Scripts/ に入っているSheepスクリプトを修正していきましょう。ダブルクリックしてIDEを開きます。
(見当たらない方は Assets/直下にあるかもしれません、小まめに整理整頓で移動していきましょう)
今時点では、Sheepオブジェクトは以下のようになっているはずです。
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sheep : MonoBehaviour { [SerializeField] private SpriteRenderer sheepRenderer; [SerializeField] private Sprite cutSheepSprite; [SerializeField] private Wool woolPrefab; //最初の羊の画像 private Sprite defaultSprite; //移動速度 private float moveSpeed; //初期化処理 private void Initialize() { sheepRenderer.sprite = defaultSprite; transform.position = new Vector3(5,Random.Range(0.0f,4.0f),0); //初期位置をセット moveSpeed = -Random.Range(1.0f, 2.0f); //移動速度をセット } // Start is called before the first frame update void Start() { defaultSprite = sheepRenderer.sprite; Initialize(); } // Update is called once per frame void Update() { transform.position += new Vector3(moveSpeed,0) * Time.deltaTime; void Update() { transform.position += new Vector3(moveSpeed,0) * Time.deltaTime; if (transform.position.x < -5) { Initialize(); } } private void Shaving() { sheepRenderer.sprite = cutSheepSprite; var wool = Instantiate(woolPrefab, transform.position, transform.rotation); } private void OnMouseOver() { if (Input.GetMouseButton(0) == false) return; Shaving(); } } |
まず、先ほど作ったSheepDataを受け取るための変数sheepData
と
また、羊毛の量用の変数 woolCnt
を変数に追加します。
1 2 3 4 5 |
//羊の初期データ public SheepData sheepData; //羊毛の量 private int woolCnt; |
この時、sheepData
はInspectorや外部からセットされて欲しいのでpublic
に、woolCnt
は外から勝手に変更されては困るのでprivate
にしておきます。
次に、初期化用メソッド(Initialize)で、渡されている(はずの)sheepData
を元に羊の色(sheepRenderer.color)のセットや、羊毛の量(woolCnt)をセットします。
1 2 3 4 5 6 7 8 9 10 |
//初期化処理 private void Initialize() { sheepRenderer.sprite = defaultSprite; transform.position = new Vector3(5,Random.Range(0.0f,4.0f),0); //初期位置をセット moveSpeed = -Random.Range(1.0f, 2.0f); //移動速度をセット sheepRenderer.color = sheepData.color; //色のセット woolCnt = sheepData.woolCnt; //羊毛の量 } |
そして、刈り取りメソッド(Shaving())は以下のように修正します。
(コメントをちょっと過剰に書いているので、不要な方は適宜省略してください)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private void Shaving() { if (woolCnt <= 0) return; //もう刈り取れる羊毛はないので何もしない var shavingWool = (int)(sheepData.woolCnt * Random.Range(0.3f, 0.4f)); //3~40%の羊毛を刈り取る if (woolCnt < shavingWool) shavingWool = woolCnt; //今羊に残っている羊毛より多い羊毛は取れないので、上限 woolCnt -= shavingWool; //今回刈り取る分を保持している羊毛から減らし if (woolCnt <= 0) //0になったようなら、 { sheepRenderer.sprite = cutSheepSprite; //画像をカットされたものに差し替え sheepRenderer.color = Color.white; //毛はもうないので色を白に戻す } var wool = Instantiate(woolPrefab, transform.position, transform.rotation); //TODO Woolオブジェクトに今回刈り取った羊毛と色情報を渡す } |
書いてあるコメントの通りではあるのですが重要なところだけ解説していくと、大体3回クリック(実際には押しっぱなしでも良いのですが)ぐらいでどの羊も全て刈り取れるように、30~40%ずつ刈るようにしています。
(この辺りの数値はレベルデザイン次第でもあるのでいくらでも調整して構いません。まだ先の話ではありますが、お金で羊の購入だけではなく、アイテムで「高級ハサミ」を購入したら、1回で刈り取れる羊毛の割合を増やす。といったゲーム性も持たせられますね。そういう意味ではポイントになりうる箇所です。)
ただ、今持っている羊毛の量よりも多く刈り取ることは出来ないので(それを許容するゲーム性もあるとは思いますが) if(woolCnt < shaveingWool) で、今から刈り取ろうとしている羊毛の量と、保持している羊毛の量を比較して、上限を決めています。
この2行は
1 2 |
var shavingWool = (int)(sheepData.woolCnt * Random.Range(0.3f, 0.4f)); //3~40%の羊毛を刈り取る if (woolCnt < shavingWool) shavingWool = woolCnt; //今羊に残っている羊毛より多い羊毛は取れないので、上限 |
ちょっと工夫(Mathf.Min:引数で渡された値の小さいほうを返却) すると、1行に圧縮できます。
1 |
var shavingWool = (int)Mathf.Min(woolCnt , sheepData.woolCnt * Random.Range(0.3f, 0.4f) ); |
なぜ一緒の意味になるのか。
ちょっと考えてみると面白いかもしれません。
そして、woolCntが0になった場合は、もう刈り取ることは出来ない。 という事を改めてプレイヤーに示す必要があるため、画像をカットされた羊に差し替えるようにし、羊毛はもう無いので色を白(Color.white
)に戻しています。
最後に //TODO という形で、「本当はやりたい事」が書いてあります。
本当はここで生成した羊毛(Wool)オブジェクトに今回刈り取った羊毛の量と色情報を渡す必要があるのですが、まだWool側にその仕組みが存在しないため、未来の自分へのメモとしてこの//TODOコメントというものを書いています。
最終的にSheepスクリプトは以下のようになります。
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sheep : MonoBehaviour { [SerializeField] private SpriteRenderer sheepRenderer; [SerializeField] private Sprite cutSheepSprite; [SerializeField] private Wool woolPrefab; //最初の羊の画像 private Sprite defaultSprite; //移動速度 private float moveSpeed; //羊の初期データ public SheepData sheepData; //羊毛の量 private int woolCnt; //初期化処理 private void Initialize() { sheepRenderer.sprite = defaultSprite; transform.position = new Vector3(5,Random.Range(0.0f,4.0f),0); //初期位置をセット moveSpeed = -Random.Range(1.0f, 2.0f); //移動速度をセット sheepRenderer.color = sheepData.color; //色のセット woolCnt = sheepData.woolCnt; //羊毛の量 } // Start is called before the first frame update void Start() { defaultSprite = sheepRenderer.sprite; Initialize(); } // Update is called once per frame void Update() { transform.position += new Vector3(moveSpeed,0) * Time.deltaTime; if (transform.position.x < -5) { Initialize(); } } private void Shaving() { if (woolCnt <= 0) return; //もう刈り取れる羊毛はない var shavingWool = (int)(sheepData.woolCnt * Random.Range(0.3f, 0.4f)); //3~40%の羊毛を刈り取る if (woolCnt < shavingWool) shavingWool = woolCnt; //今羊に残っている羊毛より多い羊毛は取れないので、上限 woolCnt -= shavingWool; //今回刈り取る分を保持している羊毛から減らし if (woolCnt <= 0) //0になったようなら、 { sheepRenderer.sprite = cutSheepSprite; //画像をカットされたものに差し替え sheepRenderer.color = Color.white; //毛はもうないので色を白に戻す<br> } var wool = Instantiate(woolPrefab, transform.position, transform.rotation); //TODO Woolオブジェクトに今回刈り取った羊毛を渡す } private void OnMouseOver() { if (Input.GetMouseButton(0) == false) return; Shaving(); } } |
では、保存をしてHierarchyのsheepオブジェクトを選択し、InspectorのSheepDataへAssets/SheepDatas の Sheep1かSheep2 をセットしてみて、確認してみましょう。
確認するのは以下の点です。
- 羊にセットしたSheepDataの色が付いているか
- 羊毛が無くなった羊からは羊毛が取れなくなっているか
- 一周した羊はまた毛が復活しているか
問題がなさそうでしたら、またScene上のsheepとprefabにしてあるsheepで差が発生していますので、Overides→Apply All で、変更をprefabの方にも適用しておきましょう。
Sキーを押して羊を生成してみて、エラー等出てないかも確認しておくと良いです。
おさらいと次回予告
今回は羊オブジェクトのパラメータをScriptableObjectで作成しました。
次回は羊の購入処理を作っていきます。
次回の記事↓

コメント