//tips
//Unity3Dとcamera、UI表示の関係性
Unity2Dはカメラの表示範囲にアプリの制作物を納めれば問題ないが、Unity3Dは制作物が大抵のケースでカメラの表示範囲から外れてしまうので、その場合の一般的なプレイヤーとカメラ、そして、プレイヤーと一緒に常に表示されるUI(canvas)の関係性を確認した。
3D空間の中で、プレイヤーを動かす場合は、プレイヤーにカメラの照準を合わせる必要があるので、カメラをプレイヤーの子オブジェクトとし、プレイヤーの動きをカメラで追従する。
その追従画面に対して、常に表示させておきたいテキストなどはcanvasのUIで作成されることになるが、単純にcanvasのrender modeをScreen Space - cameraにするだけではダメで、さらにPlane Distanceによって、カメラの最大奥行の表示からプレイヤーがカメラに写る最適なPlane Distanceへの変更が必要となる。
これは、カメラの表示可能領域も3dで表されているので、その3dの中の一つの2d(プレイヤーが最適に表示される画面枠)を選ばなければいけないということである。
プレイヤーのスクリプトは以下になる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
public float speed = 10.0f;
public Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
float x = Input.GetAxis("Horizontal") * speed;
float z = Input.GetAxis("Vertical") * speed;
rb.AddForce(x, 0, z);
}
}
//追加ステージの作成
ベースとなるSceneの作成ができたら、それを複製することで別のステージを制作していくことができる。
これはFile→Save Scene as を利用し、別名で保存すれば良い。
//ボタンを押したらステージ遷移
まず複数のボタンがあるため配列を使用する。
HingeJoint[] hingeJoints;
hingeJoints = GetComponents<HingeJoint>();
配列の取得のベースは上記の形となる。
この各ボタンに遷移の処理を付加していく必要がある。
なので、今回はstageButtonsという配列の変数を用意し、配列番号によってステージとボタンの遷移を行なっていく。
int clearStageNo = PlayerPrefs.GetInt ("CLEAR", 0);
とは、事前にPlayerPrefs.SetInt(string key, int i);で保存したものをロードするときに使用するint i =PlayerPrefs.GetInt(string key);をベースにしており、読み込もうとしたときにデータがない場合は、デフォルト値である第二引数の0が代わりに保存される。
stageButtons.GetUpperBound(0)でステージの数を取得し、ループさせる。
クリアしたステージがある場合は数字が加算していくので、それにより、入れるステージが増えていくことになる。
interactableとはbool型でボタンに付加して、falseにすると半透明にし、選択できなくする使われ方をする。
最後にボタンを押されたときに遷移するSceneManager.LoadScene ("GameScene" + stageNo);を記述し、インスペクターの中のButton(Script)のOn Click()でスクリプトの貼り付けとメソッドPushStartButtonの設定を行う。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class StageSelectManager : MonoBehaviour {
public GameObject[] stageButtons; //ステージ選択ボタン配列
// Use this for initialization
void Start () {
int clearStageNo = PlayerPrefs.GetInt ("CLEAR", 0); //どのステージまでクリアしているのかをロード(セーブされていなければ「0」)
//ステージボタンを有効化
for (int i = 0; i <= stageButtons.GetUpperBound(0); i++) {
bool buttonEnable;
if (clearStageNo < i) {
buttonEnable = false; //前ステージをクリアしていなければ無効
}else{
buttonEnable = true; //前ステージをクリアしていれば有効
}
stageButtons[i].GetComponent<Button>().interactable = buttonEnable; //ボタンの有効/無効を設定
}
}
// Update is called once per frame
void Update () {
}
//ステージ選択ボタンを押した
public void PushStageSelectButton (int stageNo) {
SceneManager.LoadScene ("GameScene" + stageNo); //ゲームシーンへ
}
}
//PlayerPrefsの理解
セーブとロードで使用するPlayerPrefsをもう少し突っ込んで理解する。
数字をずっと加算し続けるプログラムでセーブとロードの簡単な反応を見る。
UIでテキストを作成したのち、emptyオブジェクトに下記のスクリプトを追加し、Managerとする。インスペクターのscore_object項目にUItextオブジェクトをヒエラルキーからドラッグすることでアタッチすれば準備完了。
フレームが変わるごとにscore_numが加算されていく。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // 追加
public class ScoreManager : MonoBehaviour
{
public GameObject score_object = null; // Textオブジェクト
public int score_num = 0; // スコア変数
// 初期化時の処理
void Start()
{
// スコアのロード
score_num = PlayerPrefs.GetInt("SCORE", 0);
}
// 削除時の処理
void OnDestroy()
{
// スコアを保存
PlayerPrefs.SetInt("SCORE", score_num);
PlayerPrefs.Save();
}
// 更新
void Update()
{
// オブジェクトからTextコンポーネントを取得
Text score_text = score_object.GetComponent<Text>();
// テキストの表示を入れ替える
score_text.text = "Score:" + score_num;
score_num += 1; // とりあえず1加算し続けてみる
}
}
保存場所はローカル環境となるため
Mac:
/Users/[ユーザー名]/Library/Preferences/unity.[company name].[product name].plist
ios:
/Library/Preferences/[bundle identifier].plist」
android:
/data/data/pkg-name/shared_prefs/pkg-name.xml
へデータが保存される。
//array.GetUpperBoundとarray.GetLengthの違い
GetUpperBoundは配列の最大インデックスを返し、GetLengthは配列の要素数を返す。
1次配列の場合は、GetUpperBound = GetLength-1
2次配列の場合は事情が異なり、例えば下記は
private static readonly int[,] USHolidays =
{
{ 1, 1 },
{ 7, 4 },
{ 12, 24 },
{ 12, 25 }
};
配列には8つの要素があるため、Lengthプロパティは8を出力。
一方で、GetUpperBound()関数は、最初の次元の上限が3(縦に0,1,2,3)であるため、3を出力する。
この性質の違いから、GetUpperBound()関数は次元ごとのループ作業に適しており、
for (var i = 0; i <= USHolidays.GetUpperBound(0); i++)
{
Console.WriteLine("{0}, {1}", USHolidays[i, 0], USHolidays[i, 1]);
}
などの形で利用される。
ここで使用されているConsole.WriteLine()の便利技は、””内部で、コンソール表示する形を示し、{}に第二引数以下に続く、数字の順番(第二引数0番から始まる)を書くことで、その順番に書かれた数字そのものを取得できる。
例:
int first = 123;
int second = 234;
System.Console.WriteLine("first:{0} second:{1}", first, second); // 順番
実行結果:
first:123 second:234
となる。