title: Objectに当たったらImageを表示させよう!宝探しゲーム??
tags: C# Unity
author: irishbeer
#はじめに
受講生に送ろうと思ったんですけど、これを説明するのは大変だと思って、記事にしました!3Dの宝探しゲームとかで、使えそうな機能があると思うので、ぜひ使ってみてください!!
#目次
1. 完成予想図
2. 変数共有(getterとsetter)
3. enabledとは
4. 素材の準備
5. いざ、開発!!
6. コード全容
#完成予想図
宝物(今回は、cubeを色つけ)を取ったら、imageを表示させました〜!!
#変数共有(getterとsetter)
変数の共有といえば、調べたらいっぱい出てきそうですが、今回はgetterとsetterを扱います!簡単にいうと、値を取得(get)して、値を代入(set)することです!!しばしば、setはprivateをつけて使用されることが多いです!理由としては、別のインスタンス(複製された別のオブジェクト)から値を代入できぬようにしています!
まあ、こうゆうのは後から覚えた方が理解の助けになる気がします笑詳しく知りたい方は、こちらどうぞ!!
後で、出てくると思いますが、先に説明しちゃいます!
//変数宣言
//他からアクセスするために、publicをつける。これがプロパティ
public GameObject Painting1instantiated
{
//取得したオブジェクトを参照
get { return painting1instantiated; }
//他のスクリプトから得た値(ここでは、オブジェクト)を代入
private set { painting1instantiated = value; }
}
#enabledとは
しばしばSetActiveと対比され、何かを表示/非表示にしたい時、enabledかSetActiveかで迷う時があります。結論からいうと、SetActive(false)は親も子もgameObjectが無効になるのに対し、enabledはgameObjectにアタッチされているコンポネントが無効になる。
僕は、Image(UI)を非表示にしたかったので、SetActiveではなく、enabledを使いました。
形としては、こんな感じです!
painting1Point.enabled = false;
painting1Point.enabled = true;
#素材の準備
適当な画像を四枚用意し、Unityにインポート。(僕はいらすとやから宝物っぽいものを取ってきました)
#オブジェクトの準備
playerと宝物の高さの調整をしやすいように、plane(地面)を置きます。
#いざ、開発!!
長い長い説明と準備はとりあえず終わり!ここから、じゃんじゃん作っていきましょう!
##1. playerの移動実装
ここは、説明や解説は省略させていただきます。
ⅰ. Herarchyからcubeを選択して、[Rename]で、playerと変更。
ⅱ. projectからmaterialを作り、今回は紫色にして、playerにドラッグ&ドロップ
ⅲ. スクリプトを作って、名前をplayerScript下記のコードをコピペしてください。
//変数宣言
float speed = 5.0f;
//~~省略~~
void Update()
{
if (Input.GetKey("up") == true)
{
this.transform.position += new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("down") == true)
{
this.transform.position -= new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("right") == true)
{
this.transform.position -= new Vector3(speed * Time.deltaTime, 0, 0);
}
if (Input.GetKey("left") == true)
{
this.transform.position += new Vector3(speed * Time.deltaTime, 0, 0);
}
}
##2. 宝物をランダムで生成しよう!!
###2-1. 準備
ⅰ. このゲームを管理する空のGameObjectを作り、GameManagerとしておく。
ⅱ. cubeとして、生成するオブジェクト(宝物)を作り、prefab化しておく。これは全部で四つ作り、それぞれ名前と色を変えておく。僕は宝物のAssetを準備するのがめんどくさかったので、cubeを色つけしました。笑
ⅲ. ここまで
ⅳ. 最後に生成される場所を作りましょう。これは、hierarchyから空のオブジェクトを3つ用意して、それぞれをp1、p2、p3と名前をつけておく。
###2-2. gameManageのコードを書いていこう!!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gameManageScript : MonoBehaviour
{
//後ほど生成する時に、何を生成すべきかわからないため、publicをつけておく。
public GameObject painting1;
public GameObject painting2;
public GameObject vase;
public GameObject gem;
//ⅰで解説
public Transform p1;
public Transform p2;
public Transform p3;
//ⅲで解説
GameObject painting1instantiated;
GameObject painting2instantiated;
GameObject vaseinstantiated;
GameObject geminstantiated;
//これは、上の"変数共有(getterとsetter)"の通り。
public GameObject Painting1instantiated
{
get { return painting1instantiated; }
private set { painting1instantiated = value; }
}
public GameObject Painting2instantiated
{
get { return painting2instantiated; }
private set { painting2instantiated = value; }
}
public GameObject Vaseinstantiated
{
get { return vaseinstantiated; }
private set { vaseinstantiated = value; }
}
public GameObject Geminstantiated
{
get { return geminstantiated; }
private set { geminstantiated = value; }
}
void Start()
{
//配列。宣言した宝物(gameObject)を一つの箱に格納。
GameObject[] treasures =
{
painting1,
painting2,
vase,
gem
};
//上と同じ
Transform[] places =
{
p1,
p2,
p3
};
//生成される場所をfor文でLoopさせている。
for (int i = 0; i < 3; i++)
{
//Random.Rangeでランダムで箱から取り出し、それが"treasures[0]だったら"という文
if (treasures[Random.Range(0, 4)] == treasures[0])
{
//ⅱで解説
painting1instantiated = Instantiate(treasures[0], places[i]) as GameObject;
}else if (treasures[Random.Range(1, 4)] == treasures[1])
{
painting2instantiated = Instantiate(treasures[1], places[i]) as GameObject;
}else if (treasures[Random.Range(2, 4)] == treasures[2])
{
vaseinstantiated = Instantiate(treasures[2], places[i]) as GameObject;
}else if (treasures[Random.Range(3, 4)] == treasures[3])
{
geminstantiated = Instantiate(treasures[3], places[i]) as GameObject;
}
}
}
}
ⅰ. Transformは座標を取得するための型。後ほど出てくる、[Instantiate]のどこにの部分で、GameObjectで変数宣言してしまうと、型が違うと出てしまうので、Transformで変数宣言。もっと詳しく知りたい方は公式ドキュメントを!!
ⅱ. これから、Playerが宝物にぶつかった時、その宝物を消したい(獲得したい)が、宝物自体を消してしまうと、[Null reference]というスクリプトで命令しているけど、Unity上でその物体がないよというエラーが出てしまう。なので、生成されたオブジェクトを消したいので、[~ as GameObject]という書き方になっている。
ⅲ. また、その生成されたオブジェクトをplayerScriptで、当たったら消す(獲得したい)ので、ローカル変数宣言ではなく、グローバル変数宣言をして、変数共有ができるようにしている。ローカル変数は、メソッド内で定義された変数で、そのメソッド内でしか使うことができない。
例
void Start(){
//この形がローカル変数
GameObject painting1instantiated = Instantiate(treasures[0], places[i]) as GameObject;
}
ⅳ. ここまで
[gameManageScript]を、空のオブジェクトである[GameManager]に紐付け。prefabであるpainting1~gemと、空のオブジェクトであるp1~p3をドラッグ&ドロップ!!
ⅴ. 途中経過を実装
注意
・prefabであるpainting1~gemの座標(インスペクターのtransformのpostion)を0にしよう!!
・空のオブジェクトであるp1~p3を分散させよう!!y軸の座標はPlayerと同じにしよう!!
##3. 宝物に当たったらimageを表示させよう!!
###3-1. 準備
ⅰ. prefabにtag付けをしていこう!!
新しいtagの作り方は、ここでは省略させていただきます。painting1~gemのprefabに、そのままの名前でtag付け
ⅱ. Canvas内に、Imageを作る
Canvas内に、UIから[Image]を作成。ちょうど良い位置に持ってくる!
ⅲ. 上の[素材の準備]の部分で、インポートした画像を2D sprite化し、その[sprite]を[image]のimageコンポネントに入れる!
ⅳ. GameViewを上からの角度で見れるように、カメラの位置をずらす。
###3-2. playerScriptのコードを書いていこう!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class playerScript : MonoBehaviour
{
float speed = 10.0f;
//後ほど当たり判定で使う。何にあったたかを、Unity上でもわかるように、publicをつける。
public GameObject painting1;
public GameObject painting2;
public GameObject vase;
public GameObject gem;
//先ほど、3-1の準備のⅱで、用意したImage
Image painting1Point;
Image painting2Point;
Image vasePoint;
Image gemPoint;
//変数共有(getterとsetter)で必要。スクリプトをpublicで変数宣言して、スクリプト同士を紐付ける
public gameManageScript gamemanagescript;
void Start()
{
//ここでは、"painting1Point"が何の要素を含んで、Unity上の何なのかを代入している。
painting1Point = GameObject.Find("painting1Point").GetComponent<Image>();
painting2Point = GameObject.Find("painting2Point").GetComponent<Image>();
vasePoint = GameObject.Find("vasePoint").GetComponent<Image>();
gemPoint = GameObject.Find("gemPoint").GetComponent<Image>();
//上の"enabled"の説明通り。初めは、非表示にして、宝物を獲得した後に、表示するよう、設定したいため、falseにしている。
painting1Point.enabled = false;
painting2Point.enabled = false;
vasePoint.enabled = false;
gemPoint.enabled = false;
}
void Update()
{
if (Input.GetKey("up") == true)
{
this.transform.position += new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("down") == true)
{
this.transform.position -= new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("right") == true)
{
this.transform.position -= new Vector3(speed * Time.deltaTime, 0, 0);
}
if (Input.GetKey("left") == true)
{
this.transform.position += new Vector3(speed * Time.deltaTime, 0, 0);
}
}
void OnTriggerEnter(Collider col)
{
//2-2のⅲの説明のように、ローカル変数として使うので、わざわざグローバル変数にする必要はない。なのでメソッド内で宣言
//gamemanagescriptにある、Painting1instantiatedを取得して、destroypainting1に代入している
GameObject destroypainting1 = gamemanagescript.Painting1instantiated;
GameObject destroypainting2 = gamemanagescript.Painting2instantiated;
GameObject destroyvase = gamemanagescript.Vaseinstantiated;
GameObject destroygem = gamemanagescript.Geminstantiated;
if (col.gameObject.tag == "painting1")
{
//"painting1"というタグのついたオブジェクトに当たったら、"painting1Point"を表示させるという意味
painting1Point.enabled = true;
//上のローカルで宣言した変数を、ここで活用
//"painting1"というタグのついたオブジェクトに当たったら、destroypainting1を消す。つまり、"gameManageScript"の"painting1instantiated"を消すという意味
Destroy(destroypainting1);
}
if (col.gameObject.tag == "painting2")
{
painting2Point.enabled = true;
Destroy(destroypainting2);
}
if (col.gameObject.tag == "vase")
{
vasePoint.enabled = true;
Destroy(destroyvase);
}
if (col.gameObject.tag == "gem")
{
gemPoint.enabled = true;
Destroy(destroygem);
}
}
}
ⅱ. 最後の確認
・Playerに、[box collider]と[Rigidbody]が入ってるか
・宝物(prefab)には、[box collider]のみついているか
・宝物(prefab)にtag付けされているか
#コード全容
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gameManageScript : MonoBehaviour
{
public GameObject painting1;
public GameObject painting2;
public GameObject vase;
public GameObject gem;
public Transform p1;
public Transform p2;
public Transform p3;
GameObject painting1instantiated;
GameObject painting2instantiated;
GameObject vaseinstantiated;
GameObject geminstantiated;
public GameObject Painting1instantiated
{
get { return painting1instantiated; }
private set { painting1instantiated = value; }
}
public GameObject Painting2instantiated
{
get { return painting2instantiated; }
private set { painting2instantiated = value; }
}
public GameObject Vaseinstantiated
{
get { return vaseinstantiated; }
private set { vaseinstantiated = value; }
}
public GameObject Geminstantiated
{
get { return geminstantiated; }
private set { geminstantiated = value; }
}
void Start()
{
GameObject[] treasures =
{
painting1,
painting2,
vase,
gem
};
Transform[] places =
{
p1,
p2,
p3
};
for (int i = 0; i < 3; i++)
{
if (treasures[Random.Range(0, 4)] == treasures[0])
{
painting1instantiated = Instantiate(treasures[0], places[i]) as GameObject;
}
if (treasures[Random.Range(1, 4)] == treasures[1])
{
painting2instantiated = Instantiate(treasures[1], places[i]) as GameObject;
}
if (treasures[Random.Range(2, 4)] == treasures[2])
{
vaseinstantiated = Instantiate(treasures[2], places[i]) as GameObject;
}
if (treasures[Random.Range(3, 4)] == treasures[3])
{
geminstantiated = Instantiate(treasures[3], places[i]) as GameObject;
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class playerScript : MonoBehaviour
{
float speed = 10.0f;
public GameObject painting1;
public GameObject painting2;
public GameObject vase;
public GameObject gem;
Image painting1Point;
Image painting2Point;
Image vasePoint;
Image gemPoint;
public gameManageScript gamemanagescript;
void Start()
{
painting1Point = GameObject.Find("painting1Point").GetComponent<Image>();
painting2Point = GameObject.Find("painting2Point").GetComponent<Image>();
vasePoint = GameObject.Find("vasePoint").GetComponent<Image>();
gemPoint = GameObject.Find("gemPoint").GetComponent<Image>();
painting1Point.enabled = false;
painting2Point.enabled = false;
vasePoint.enabled = false;
gemPoint.enabled = false;
}
void Update()
{
if (Input.GetKey("up") == true)
{
this.transform.position += new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("down") == true)
{
this.transform.position -= new Vector3(0, 0, speed * Time.deltaTime);
}
if (Input.GetKey("right") == true)
{
this.transform.position -= new Vector3(speed * Time.deltaTime, 0, 0);
}
if (Input.GetKey("left") == true)
{
this.transform.position += new Vector3(speed * Time.deltaTime, 0, 0);
}
}
void OnTriggerEnter(Collider col)
{
GameObject destroypainting1 = gamemanagescript.Painting1instantiated;
GameObject destroypainting2 = gamemanagescript.Painting2instantiated;
GameObject destroyvase = gamemanagescript.Vaseinstantiated;
GameObject destroygem = gamemanagescript.Geminstantiated;
if (col.gameObject.tag == "painting1")
{
painting1Point.enabled = true;
Destroy(destroypainting1);
}
if (col.gameObject.tag == "painting2")
{
painting2Point.enabled = true;
Destroy(destroypainting2);
}
if (col.gameObject.tag == "vase")
{
vasePoint.enabled = true;
Destroy(destroyvase);
}
if (col.gameObject.tag == "gem")
{
gemPoint.enabled = true;
Destroy(destroygem);
}
}
}
#終わりに
ところどころ、修正すべきところがあるので、そこを後々直していこうと思います!
最後まで、見てくれてありがとうございました!
〜〜〜〜〜