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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

0回答

698閲覧

キャラクターの操作入力を記録したい

kuronokei

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/04/22 09:59

編集2021/04/23 09:19

前提・実現したいこと

Unityの2Dスクロールゲームで、キャラクターの操作を記録して、その後でそれ同じ動きをするキャラクターを追加したいです。
お互い干渉できるようにしたいので、「時間と場所」を記録させるのではなく、「時間と操作入力」を記録させたいです。

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

ゲームを始めて動きを記録し、その動きを開始させようとするとエラーが出ます。

Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

該当のソースコード

using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.IO; public class Recorder : MonoBehaviour { // 操作キャラクター [SerializeField] private GhostChara ghostChara; // AnimatorController private Animator animator; // 現在記憶しているかどうか private bool isRecord; // 保存するデータの最大数 [SerializeField] private int maxDataNum = 2000; // 記録間隔 [SerializeField] private float recordDuration = 0.005f; // Jumpキー //private string animKey = "Jump"; // 経過時間 private float elapsedTime = 0f; // ゴーストデータ private GhostData ghostData; // 再生中かどうか private bool isPlayBack; // ゴースト用キャラ [SerializeField] private GameObject ghost; [SerializeField] // 保存先フォルダ private string saveDataFolder = "/Projects/Ghost"; // 保存ファイル名 private string saveFileName = "/ghostdata.dat"; void Start() { ghostChara.rbody = ghostChara.GetComponent<Rigidbody2D>(); } // ゴーストデータクラス [Serializable] private class GhostData { // カーソルキーの入力を取得 public List<float> HorizontalLists = new List<float>(); // Update is called once per frame void Update() { var moveHorizontal = Input.GetAxis("Horizontal"); if (isRecord) { elapsedTime += Time.deltaTime; if (elapsedTime >= recordDuration) { if (Input.GetAxis("Horizontal") == 1 || Input.GetAxis("Horizontal") == -1) { ghostData.HorizontalLists.Add(moveHorizontal); Debug.Log("左右記録"); } elapsedTime = 0f; } } } // キャラクターデータの保存 public void StartRecord() { // 保存する時はゴーストの再生を停止 StopAllCoroutines(); StopGhost(); isRecord = true; elapsedTime = 0f; ghostData = new GhostData(); Debug.Log("StartRecord"); } // キャラクターデータの保存の停止 public void StopRecord() { isRecord = false; Debug.Log("StopRecord"); } // ゴーストの再生ボタンを押した時の処理 public void StartGhost() { Debug.Log("StartGhost"); if (ghostData == null) { Debug.Log("ゴーストデータがありません"); } else { isRecord = false; isPlayBack = true; ghost.SetActive(true); StartCoroutine(PlayBack()); } } // ゴーストの停止 public void StopGhost() { Debug.Log("StopGhost"); StopAllCoroutines(); isPlayBack = false; ghost.SetActive(false); } // ゴーストの再生 IEnumerator PlayBack() { var i = 0; while (isPlayBack) { yield return new WaitForSeconds(recordDuration); if (ghostData.HorizontalLists[i] != null) { ghostChara.rbody.velocity = new Vector2(ghostChara.speed * ghostChara.axisH, ghostChara.rbody.velocity.y); Debug.Log("左右移動中"); } i++; } public void Save() { if (ghostData != null) { // GhostDataクラスをJSONデータに書き換え var data = JsonUtility.ToJson(ghostData); // ゲームフォルダにファイルを作成 File.WriteAllText(Application.dataPath + saveDataFolder + saveFileName, data); Debug.Log("ゴーストデータをセーブしました"); } } public void Load() { if (File.Exists(Application.dataPath + saveDataFolder + saveFileName)) { string readAllText = File.ReadAllText(Application.dataPath + saveDataFolder + saveFileName); // ghostDataに読み込んだデータを書き込む if (ghostData == null) { ghostData = new GhostData(); } JsonUtility.FromJsonOverwrite(readAllText, ghostData); Debug.Log("ゴーストデータをロードしました。"); } } void OnApplicationQuit() { Debug.Log("アプリケーション終了"); Save(); } }

試したこと

https://gametukurikata.com/program/ghost
こちらのホームページを参考にして、「時間と操作入力」を記録できるように変更しようとしました。

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

マ〇オみたいなシステムで、左右移動とジャンプのみのシンプルな操作です。

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

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

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

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

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

ayousanz

2021/04/22 10:29

単純に入力されたキーと時刻を保存すればいいのではないのでしょうか?何か制限があるのでしたらほかの方法を考えないといけないと思いますが
kuronokei

2021/04/23 09:14

コメントありがとうございます、 その入力されたキーと時刻の保存が上手くいかず、質問させていただきました。 コードを追加したので、もしよろしければ確認お願いします。
ayousanz

2021/04/23 14:50

エラーの個所はどの行ですか?
退会済みユーザー

退会済みユーザー

2021/04/26 08:03

個人的に自分ならどんな感じで書くだろうか?と考えてみて書いてみた。再生のみ、Json変換やらセーブ&ロードはなし。 FixedUpdateを1フレームとして考えDictionaryを使用した簡易ゴーストの作成。 Cubeを作ってコピペしたコードをアタッチしてみてください。参考になれば。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { // フレーム数に対する入力を記録する用 Dictionary<int, InputData> ghostData = new Dictionary<int, InputData>(); // フレーム数 int frameCount = 0; bool replay = false; float horizontal = 0; // 入力はUpdateにて private void Update() { // ghost再生に対応した処理は書いていないので入力は受け付けない if (replay) return; horizontal = Input.GetAxis("Horizontal"); // Rキーで再生 if (Input.GetKeyDown(KeyCode.R)) StartCoroutine(Replay()); } // ghost処理で誤差が発生するためFixedUpdateでの処理とします private void FixedUpdate() { // Updateに同じく if (replay) return; frameCount++; MoveAction(this.gameObject, horizontal); if (horizontal != 0) { // データを追加する ghostData.Add(frameCount, new InputData() { horizontal = this.horizontal }); } } // 移動処理 void MoveAction(GameObject obj, float horizontal) { var position = new Vector3(horizontal, 0, 0); obj.transform.position += position * Time.fixedDeltaTime; } // コルーチンを仕様してゴーストを再生 IEnumerator Replay() { replay = true; var obj = GameObject.CreatePrimitive(PrimitiveType.Cube); int count = 0; foreach(var action in ghostData) { // キーのフレームまでループ while(action.Key - 1 > count) { yield return new WaitForFixedUpdate(); count++; } // キーにある行動を行う MoveAction(obj, action.Value.horizontal); } replay = false; ghostData.Clear(); frameCount = 0; } } // 入力データを記録する用 public struct InputData { public float horizontal; } ```
kuronokei

2021/04/27 03:38

なるほど、できました! そういうやり方があるのですね、助かります。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問