teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

519閲覧

unityでbaba is youのようなゲームを作っています。ひとつ前の状況に戻れる設計にするにはどうすればいいですか?

summerxxx

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2023/12/13 09:20

編集2023/12/14 01:06

0

0

実現したいこと

unityでbaba is youのようなゲームを作っています。
何回でもひとつ前の状況に戻れる実装を行いたいです。

前提

自分が現在どのような状況か説明します。
cameraやlevelmanager以外のオブジェクトに動きがあった場合はその位置をlistで記録する。
戻りたい時は、listの要素数から1マイナスして、記録された場所に該当するオブジェクトを生成することで、ひとつ前の状況を再現している。

発生している問題・エラーメッセージ

はじめに3回オブジェクトを動かし3回戻るボタンを押せば、ちゃんと最初の状況に戻るのですが、そのあと2回オブジェクトを動かして、戻るボタンを押すとオブジェクトがすべて消えてしまいます(cameraやlevelmanager以外)。listの0番目(最初の状況)まで戻れば、オブジェクトは生成されます。

エラーメッセージ

該当のソースコード

public class LevelManager : MonoBehaviour { private List<GameState> gameStates = new List<GameState>(); private int currentStateIndex = -1; [SerializeField] private GameObject uni; [SerializeField] private GameObject uni_Text; [SerializeField] private GameObject is_Text; [SerializeField] private GameObject you_Text; [SerializeField] private GameObject win_Text; // Start is called before the first frame update void Start() { SaveGameState(); } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.U)) { Undo(); Debug.Log(currentStateIndex); } } public void SaveGameState() { GameState state = new GameState(); GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>(); foreach (GameObject obj in allObjects) { if (obj.name == "UNI") { state.uni.Add(obj.transform.position); } else if (obj.name == "UNI_Text") { state.uni_Text.Add(obj.transform.position); } else if (obj.name == "IS_Text") { state.is_Text.Add(obj.transform.position); } else if (obj.name == "YOU_Text") { state.you_Text.Add(obj.transform.position); } else if (obj.name == "WIN_Text") { state.win_Text.Add(obj.transform.position); } } gameStates.Add(state); currentStateIndex = gameStates.Count - 1; } void Undo() { if (currentStateIndex > 0) { GameObject[] objects = GameObject.FindGameObjectsWithTag("Object"); foreach (GameObject obj in objects) { Destroy(obj); } GameObject[] texts = GameObject.FindGameObjectsWithTag("Text"); foreach (GameObject obj in texts) { Destroy(obj); } gameStates.RemoveAt(currentStateIndex); currentStateIndex--; RestoreGameState(); } } void RestoreGameState() { GameState state = gameStates[currentStateIndex]; foreach (var obj in state.uni) { Instantiate(uni, obj, Quaternion.identity); uni.tag = "Object"; } foreach (var obj in state.uni_Text) { Instantiate(uni_Text, obj, Quaternion.identity); uni_Text.tag = "Text"; } foreach (var obj in state.is_Text) { Instantiate(is_Text, obj, Quaternion.identity); is_Text.tag = "Text"; } foreach (var obj in state.you_Text) { Instantiate(you_Text, obj, Quaternion.identity); you_Text.tag = "Text"; } foreach (var obj in state.win_Text) { Instantiate(win_Text, obj, Quaternion.identity); win_Text.tag = "Text"; } } private class GameState { public List<Vector3> uni = new List<Vector3>(); public List<Vector3> uni_Text = new List<Vector3>(); public List<Vector3> is_Text = new List<Vector3>(); public List<Vector3> you_Text = new List<Vector3>(); public List<Vector3> win_Text = new List<Vector3>(); } 以下はオブジェクトを動かすスクリプト。 public class PlayerController : MonoBehaviour { public LevelManager levelManager; [SerializeField] private GameObject player; private bool play; private bool push; // Start is called before the first frame update void Start() { levelManager = GameObject.Find("LevelManager").GetComponent<LevelManager>(); } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.A)) { transform.position += new Vector3(-1, 0, 0); levelManager.SaveGameState(); } if (Input.GetKeyDown(KeyCode.D)) { transform.position += new Vector3(1, 0, 0); levelManager.SaveGameState(); } if (Input.GetKeyDown(KeyCode.W)) { transform.position += new Vector3(0, 1, 0); levelManager.SaveGameState(); } if (Input.GetKeyDown(KeyCode.S)) { transform.position += new Vector3(0, -1, 0); levelManager.SaveGameState(); } } }

試したこと

ひとつ前の状況に戻るときはgameStates.Removeでlistの中にある現在の状況を削除するようにしたのですが、解決できませんでした。

補足情報(FW/ツールのバージョンなど)

最初の状態
イメージ説明
問題の状態
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Sobasenbei

2023/12/13 17:25

エラーなどは出てないでしょうか?出てないとしたらrestoregamestateは最後まで処理されてますか? オブジェクトは出現しているが隠れてるだけなどはないでしょうか?
summerxxx

2023/12/14 01:07

エラーは出てないです。 確かに、DeBug.Logと使って調べたら、途中からrestoregamestateでオブジェクトが生成されなくなっていました。 オブジェクトは完全に消えてると思います。補足情報に画像を追加したのでよろしければ確認お願いいたします。
guest

回答1

0

自己解決

解決しました。ありがとうございます。
問題だった点はひとつ前の状況に戻す際に行われるオブジェクトの生成において、生成されたオブジェクトの名前の後ろに(Clone)がつくことを考慮せずに、名前からオブジェクトを取得してその位置情報をリストに加えようとしていたことでした。
ゲームを進めるたびに特定の名前がつくオブジェクトの位置情報をリストに加えていました。
しかし、一度ひとつ前の状況に戻る操作をしてしまうと、オブジェクトは作り直されるのでその特定の名前の後ろに(Clone)がついてしまいます。位置情報を加えるオブジェクトの条件に(Clone)は付いてなかったので、作り直されたオブジェクトの位置情報は追加されませんでした。

投稿2023/12/14 01:47

summerxxx

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問