ゲームの進行を管理する、ゲームの進行状況をセーブ/ロードすると同じゲーム進行をデリゲートを使ってやってみます。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.IO;
public class GameScript : MonoBehaviour
{
[SerializeField] GameObject[] colliders;
[SerializeField] Text text;
[SerializeField] Transform target;
public static bool onTriggerEnter;
int chapter;
int state;
float sec;
Transform playerHead;
AudioSource audioSource;
string filename;
delegate void Method(); // デリゲートを定義
Method method;
// Start is called before the first frame update
void Start()
{
filename = Application.dataPath + "/testsavedata.xml";
if (File.Exists(filename))
{
var data = XmlUtil.Deserialize<SaveData>(filename);
chapter = data.chapter;
}
else {
chapter = 1;
Save(); // 保存
}
state = 1;
text.text = "";
playerHead = Camera.main.transform;
target.gameObject.SetActive(false);
audioSource = GetComponent<AudioSource>();
// コライダーを非アクティブ
foreach (GameObject col in colliders)
{
col.SetActive(false);
}
// 初期状態
switch (chapter)
{
case 1:
colliders[0].SetActive(true);
method = C1s1;
break;
case 2:
target.gameObject.SetActive(true);
method = C2s1;
break;
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// シーンをリロード
SceneManager.LoadScene("New Scene");
}
method();
}
void Save()
{
SaveData data = new SaveData();
data.chapter = chapter;
XmlUtil.Seialize(filename, data);
}
void C1s1()
{
if (onTriggerEnter)
{
onTriggerEnter = false;
audioSource.Play();
colliders[0].SetActive(false); // 赤いのコライダーを非アクティブ
state = 2;
method = C1s2; // メソッドを入れ替える
}
}
void C1s2()
{
sec += Time.deltaTime;
text.text = sec + "";
if (sec >= 3f)
{
sec = 0f;
text.text = "";
target.gameObject.SetActive(true);
chapter = 2; // 次のチャプター
state = 1;
method = C2s1;
Save(); // セーブ
}
}
void C2s1()
{
RaycastHit hit;
Vector3 dir = target.position - playerHead.position;
if (Physics.Raycast(playerHead.position, dir, out hit, 20f))
{
if (hit.collider.tag == "Target")
{
float dot = Vector3.Dot(playerHead.forward, Vector3.Normalize(dir));
// プレイヤーがターゲットの方を見たら
if (dot > 0.9f)
{
target.gameObject.SetActive(false);
colliders[1].SetActive(true); // 緑のコライダーをアクティブ
state = 2;
method = C2s2;
}
}
}
}
void C2s2()
{
if (onTriggerEnter)
{
onTriggerEnter = false;
audioSource.Play();
colliders[1].SetActive(false); // 緑のコライダーを非アクティブ
state = 3;
text.text = "ゲーム終了";
method = C2s3;
}
}
void C2s3()
{
sec += Time.deltaTime;
if (sec >= 2f)
{
chapter = 1;
state = 1;
Save();
SceneManager.LoadScene("New Scene");
}
}
}
今まではUpdate()でゲームの状態によってswitch文で処理を切り替えていましたが、各状態で行いたい処理と次の状態に遷移する条件、遷移するときの処理をまとめて1つのメソッドにして、それを格納するデリゲートの中身を入れ替えることで、処理を切り替えるようにしました。
なので、Update()がかなり短くなりました。
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// シーンをリロード
SceneManager.LoadScene("New Scene");
}
method();
}
各メソッドの遷移するときの処理の中で次の状態のメソッドをデリゲートに入れています。
void C1s1()
{
if (onTriggerEnter)
{
onTriggerEnter = false;
audioSource.Play();
colliders[0].SetActive(false); // 赤いのコライダーを非アクティブ
state = 2;
method = C1s2; // メソッドを入れ替える
}
}
デリゲートの中身をswitch文等を使って入れ替えてもいいかもしれません。
method = GetMethod();
// ---
Method GetMethod()
{
switch (chapter)
{
case 1:
switch (state)
{
case 1:
return C1s1;
case 2:
return C1s2;
}
break;
case 2:
switch (state)
{
case 1:
return C2s1;
case 2:
return C2s2;
case 3:
return C2s3;
}
break;
}
return C2s3;
}