ポートフォリオ:シーン選択とシナリオ選択のデバッグ機能作成、スタート画面実装【192日目】(2019/02/27)
https://gyazo.com/903cab017b855a416bdbb3293797fa84
Porin.icon今日はプライベートの作業記録だよん!
◆作業記録の目次
1. ポートフォリオ:シーン選択とシナリオ選択のデバッグ機能作成
2. ポートフォリオ:スタート画面実装
◆作業時間のタイムトラッキング結果
2日分
https://gyazo.com/85e85d4870cbd5cd0dd357070b321d39
https://gyazo.com/5246c137070c303ec6be93cffe81710d
https://gyazo.com/6bb5a58ba1ce5e3f1e49abb6c627bd47
https://gyazo.com/bab043feed71170908fa8a5303c81dc8
https://gyazo.com/ea38e8d40023a4d62a667463b859b1d4
1. ポートフォリオ:シーン選択とシナリオ選択のデバッグ機能作成
前回の続きから
▼ デバッグメニューをシーン開始時に表示
継承の仕方について参考
基底クラスを作成
各シーンのスクリプトのどれかに継承させて、シーン開始時に必ず呼び出すもの
SerializeFieldでデバッグメニューを含んだCanvasゲームオブジェクトの Prefabを読み込む
ゲーム開始時に一度だけインスタンスを作成し、DontDestroyに設定する
code:SceneBase.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneBase : MonoBehaviour
{
public enum SCENARIO
{
NONE = -1,
Chapter1_1 = 0,
Chapter1_2,
Chapter1_3,
NUM
}
GameObject debugCanvas;
private bool isInitialized = false;
public static SCENARIO currentScinario{ get; set; }
protected virtual void Awake(){
if(!isInitialized){
GameObject debugMenu = Instantiate(debugCanvas) as GameObject;
DontDestroyOnLoad(debugMenu);
isInitialized = true;
}
}
}
継承
code:SceneInvestigation.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneInvestigation : SceneBase
{
protected override void Awake(){
base.Awake();
}
}
▼ 選択肢をセットアップ
シーン開始と共にドロップダウンコンポーネントの配列を取得
code:cs
List<Dropdown.OptionData>[] m_MessagesArray = new List<Dropdown.OptionData>2; Dropdown[] m_Dropdowns;
private void Awake(){
m_Dropdowns = FindObjectsOfType<Dropdown>();
confirmButton = transform.Find("Scroll View/Viewport/Content/ConfirmButton").GetComponent<Button>();
}
ドロップダウンでシナリオ選択やシーン選択ができるようにしていく
完全に現状に最適化しすぎて応用しにくいコードだけど少しずつ修正してけばいいや
code:cs
private void Start()
{
// ドロップダウン
m_MessagesArray0 = new List<Dropdown.OptionData>(); int scenarioIndex = 0;
foreach(string sceneName in Enum.GetNames(typeof(SceneBase.SCENARIO))){
if(sceneName != "NONE" && sceneName != "NUM"){
scenarioIndex += 1;
}
}
m_MessagesArray1 = new List<Dropdown.OptionData>(); int sceneIndex = 0;
foreach(string sceneName in Enum.GetNames(typeof(SceneBase.SCENE))){
if(sceneName != "NONE" && sceneName != "NUM"){
m_NewDataArraysceneIndex = new Dropdown.OptionData(); sceneIndex += 1;
}
}
for(int index=0; index<m_MessagesArray.Length; ++index){ // ドロップダウンに内容を入れていく
m_Dropdownsindex.ClearOptions(); foreach(Dropdown.OptionData message in m_MessagesArrayindex){ m_Dropdownsindex.options.Add(message); }
}
}
より応用的に使えるように修正
これで選択式のデバッグを追加したいときは、オブジェクトを作成して、スクリプト内のchoiceArrayに追加すればおけになった(列挙型限定)
ここらへんのものを駆使したらいけた
code:cs
public class DebugMenu : MonoBehaviour
{
Dropdown[] m_Dropdowns;
Button confirmButton;
private void Awake(){
m_Dropdowns = FindObjectsOfType<Dropdown>();
Array.Reverse(m_Dropdowns); // 表示順になるように
confirmButton = transform.Find("Scroll View/Viewport/Content/ConfirmButton").GetComponent<Button>();
}
private void Start()
{
List<Dropdown.OptionData>[] m_OptionDataListArray = new List<Dropdown.OptionData>m_Dropdowns.Length; // ドロップダウン
Type[] choiceArray = new Type[] {typeof(SceneBase.SCENE), typeof(SceneBase.SCENARIO)}; // ドロップダウンで選択するもの
foreach(Type choice in choiceArray){
string[] nameArray = choice.GetEnumNames();
Dropdown.OptionData[] m_NewDataArray = new Dropdown.OptionDatanameArray.Length-2; // NONE, NUMを数えない foreach(string name in nameArray){
if(name != "NONE" && name != "NUM"){
}
}
}
for(int index=0; index<m_OptionDataListArray.Length; ++index){ // ドロップダウンに内容を入れていく
m_Dropdownsindex.ClearOptions(); foreach(Dropdown.OptionData message in m_OptionDataListArrayindex){ m_Dropdownsindex.options.Add(message); }
}
▼ 確認ボタン
ドロップダウンの値が変更されたら、確認ボタンのリスナーの更新するように
初期起動時はcaptionTextの値がNullになってしまうので設定
code:cs
// 確認ボタン
foreach(Dropdown m_Dropdown in m_Dropdowns){
UpdateConfirmButton();
});
}
UpdateConfirmButton(); // 初期起動時用
過去のイベントは破棄して更新する
code:cs
private void UpdateConfirmButton(){
confirmButton.onClick.RemoveAllListeners();
confirmButton.onClick.AddListener(() => SceneBase.LoadScenario(m_Dropdowns0.captionText.text, m_Dropdowns1.captionText.text)); confirmButton.onClick.AddListener(() => Debug.Log("Debug Menuシーン:" + m_Dropdowns0.captionText.text + "、シナリオ:" + m_Dropdowns1.captionText.text)); confirmButton.onClick.AddListener(() => transform.Find("Scroll View/").gameObject.SetActive(false));
}
▼ 表示非表示
メニューの表示非表示はScroll Viewのアクティブ非アクティブで表現
表示
表示用ボタンを透過で配置する
https://gyazo.com/638ff38fe65e6fbdfb393fbe205a56c1
非表示
ゲーム開始時と閉じるボタンを押した時に非表示
code:cs
// ゲーム開始時は操作不可に
transform.Find("Scroll View/").gameObject.SetActive(false);
▼ 完成
https://gyazo.com/aa54bdf43cc04eb09af11ddfaaaaf396
https://gyazo.com/ea38e8d40023a4d62a667463b859b1d4
2. ポートフォリオ:スタート画面実装
◆ TODO整理
https://gyazo.com/729969c1d8cabece406a32687a0bb8b1
◆ 準備
▼ シナリオ追加
続きからオプションをやりやすくするためにシナリオを小分けにしたため
基本なにか状態が変わったらシナリオも変わるように
code:SceneBase.cs
public enum SCENARIO
{
NONE = -1,
Chapter1_1 = 0,
Chapter1_2,
Chapter1_3,
Chapter1_4,
Chapter1_5,
NUM
}
▼ 現在のシーンを保持
シーン開始時にSceneManager.sceneLoadedにデリゲートを追加
code:SceneBase.cs
protected virtual void Awake(){
if(!isInitialized){
GameObject debugMenu = Instantiate(debugCanvas) as GameObject;
DontDestroyOnLoad(debugMenu);
isInitialized = true;
SceneManager.sceneLoaded += OnSceneLoaded;
}
}
code:SceneBase.cs
public static SCENE currentScene {get; private set;}
private void OnSceneLoaded( Scene scene, LoadSceneMode mode )
{
currentScene = (SCENE)Enum.Parse(typeof(SCENE), scene.name);
}
▼ シナリオ設定用メソッド作成
code:SceneBase.cs
public static void ChangeScenario(SCENARIO scenario){
currentScinario = scenario;
}
◆ スタートシーン実装
▼ シーンに追加
デバッグの選択肢にもちゃんと追加されてうれしい
code:cs
public enum SCENE {
NONE = -1,
スタート = 0,
探索,
PORINのいる場所,
NUM
}
▼ オブジェクトを配置
一応全部複数解像度に耐えうるようにしてる...はず...
ヒエラルキーウィンドウ
https://gyazo.com/57a31d4c31b79cb692e28ae7b25a2ccd
基本配置
https://gyazo.com/1c61261336682e095a402b9b94892826
確認ダイアログ表示時
https://gyazo.com/7268111d05f5c35f4de8b59ba2ce6a13
▼ はじめから
ゲームデータがないときは「つづきから」を表示しない
「はじめから」(ResetButton)を押すと確認ダイアログが表示される
ただしゲームデータがないときはそのままゲームをスタート
確認ダイアログで「はい」(YesButton)を選択するとゲームデータをリセットしてはじめから再生するように
code:SceneStart.cs
protected override void Awake(){
base.Awake();
// ゲームデータがないときは「つづきから」を表示しない
if(SceneBase.currentScinario == SCENARIO.NONE){
GameObject.Find("ContinueButton").SetActive(false);
}
// ボタンにイベントを設定
transform.Find("Canvas/ResetButton").GetComponent<Button>().onClick.AddListener(ShowConfirmDialog);
transform.Find("Canvas/ConfirmDialog/YesButton").GetComponent<Button>().onClick.AddListener(StartGame);
}
private void ShowConfirmDialog(){
// ゲームデータがないときはダイアログを表示せずにゲームをスタートする
if(SceneBase.currentScinario == SCENARIO.NONE){
StartGame();
} else
{
transform.Find("Canvas/ConfirmDialog").gameObject.SetActive(true);
}
}
private void StartGame(){
SceneBase.LoadScenario(SCENE.探索, SCENARIO.Chapter1_1);
}
◆ プレイヤーデータ作成
▼ 参考
▼ 実装
currentSceneとcurrentScinarioにはセッターにてPlayerPrefsを更新するようにする
解放済みポートフォリオデータは未実装
code:SceneBase.cs
// Playerデータキー
private static readonly string m_CurrentScene = "Scene";
private static readonly string m_CurrentScinario = "Scinario";
// private static readonly string m_OpendPortfolio = "Portfolio";
private static SCENE _currentScene;
public static SCENE currentScene {
get { return _currentScene; }
private set{
_currentScene = value;
PlayerPrefs.SetString(m_CurrentScene, Enum.GetName(typeof(SCENE), value));
}
}
private static SCENARIO _currentScinario;
public static SCENARIO currentScinario {
get { return _currentScinario; }
private set{
_currentScinario = value;
PlayerPrefs.SetString(m_CurrentScinario, Enum.GetName(typeof(SCENARIO), value));
}
}
シーン開始時にPlayerPrefsをロードしてパラメータを設定
code:SceneBase.cs
protected virtual void Awake(){
if(!isInitialized){
GameObject debugMenu = Instantiate(debugCanvas) as GameObject;
DontDestroyOnLoad(debugMenu);
isInitialized = true;
SceneManager.sceneLoaded += OnSceneLoaded;
LoadPlayerData();
}
}
private void LoadPlayerData(){
currentScene = (SCENE)Enum.Parse(typeof(SCENE), PlayerPrefs.GetString(m_CurrentScene, "スタート"));
currentScinario = (SCENARIO)Enum.Parse(typeof(SCENARIO), PlayerPrefs.GetString(m_CurrentScinario, "NONE"));
}
デバッグメニューでシナリオNONEを選択することでシナリオをリセットできるようにした
初期状態の動作確認をするため
こんな感じに
https://gyazo.com/6fe7df7207fd0b46a0ef8e21a2b538d9
◆ つづきから
つづきからボタンにリスナーを追加
プレイヤーデータのロードはスタート画面のみにする
code:SceneStart.cs
protected override void Awake(){
base.Awake();
SceneBase.LoadPlayerData();
// ゲームデータがないときは「つづきから」を表示しない
if(SceneBase.currentScinario == SCENARIO.NONE){
GameObject.Find("ContinueButton").SetActive(false);
}
// ボタンにイベントを設定
transform.Find("Canvas/ResetButton").GetComponent<Button>().onClick.AddListener(ShowConfirmDialog);
transform.Find("Canvas/ContinueButton").GetComponent<Button>().onClick.AddListener(ContinueGame);
transform.Find("Canvas/ConfirmDialog/YesButton").GetComponent<Button>().onClick.AddListener(StartGame);
}
private void ContinueGame(){
SceneBase.LoadScenario(SceneBase.currentScene, SceneBase.currentScinario);
}
シーン切り替え時行うプレイヤーのシーンデータ切り替えはスタートシーンの場合は行わない
ゲームスタート時にプレイヤーデータが上書きされ、スタートシーンがプレイヤーのシーンデータになってしまうため
code:SceneBase.cs
private void OnSceneLoaded( Scene scene, LoadSceneMode mode )
{
if(SceneManager.GetActiveScene().name != "スタート"){ // スタート時にプレイヤーデータを更新するのを防止
currentScene = (SCENE)Enum.Parse(typeof(SCENE), scene.name);
}
}
(了)
https://gyazo.com/ea38e8d40023a4d62a667463b859b1d4
感想や指摘などあったらどしどし連絡ください!!
もし万が一、気が向いたりして何かコメントをもらえたら超絶喜びます!!Porin.icon