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

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

ただいまの
回答率

87.50%

ハイスコアの保存 unity

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,623

score 19

unity2Dでゲームを作成しています。

全2ステージのゲームです。
ステージごとのスコアを登録し、スコアシーンでスコアをハイスコア順で
上位の10個を表示させてスクロールできるようにし、
ステージ1とステージ2のスコアをわけたいと考えているのですが、
スコアシーンでの表示がうまく行きません。スコアシーンはスコアシーン1とスコアシーン2に分けております。

ステージ1だけの場合はうまく行ったのですが、ステージ1のデータを複製をしてステージ2のスコアデータを作成とした際にできませんでした。

Listで管理をしており
、スコアの登録まではうまく行っていると思うのですが、スコアシーンでの表示がされない状態になっております。
EnhancedScrollerを用いて実装をしております。
こちらのページを参考にしました。

また、Ranktext(ステージ1)とRanktext2(ステージ2)をpfefab化し、CellViewを双方にアタッチしております。一度ゲームを再生した際には、スクロール内にその子要素にあるテキスト自体は表示がされますが、更新がされておらず、同じ数値(前にプレイした際の数値)が表示されています。

どなたかアドバイスをいただけますと幸いです。

ゲーム終了時のスコアの保存(ステージ1とステージ2)
(ゲームの終了の際にスコア保存をして更新をしております。)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;

public class EndSceneManager : MonoBehaviour
{
List<int> highScores = new List<int>();
    //第二ステージの場合
    List<int> highScores2 = new List<int>();


    [SerializeField]
    Text scoreText, clearText;
    string[] keyList = new string[10];

    string[] keyList2 = new string[10];

    int scoreNumber;
    int scoreNumber2;


//スコアの保存
public void Return()
    {
//ステージ1の場合
        if (PlayerPrefs.GetInt("secondLap", 0) == 0)
        { 
            // playerprefsからscoreNumberの分(1~10)だけハイスコアを取ってくる
            for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber"); i++)
        {
            highScores.Add(PlayerPrefs.GetInt(keyList[i]));
            // Debug.Log("high score add from pref cycle");
        }
        // 今回のスコアをハイスコアに追加する
        // if finishFlag == true
        highScores.Add(GameManager.score);
        // ハイスコアをソート
        // highScores.Sort((int x, int y) => { return y - x; });
        highScores.Sort((x, y) => y - x);

        if (highScores.Count > 10)
        {
            highScores.RemoveAt(10);
            // Debug.Log("memorized score is more than 10");
        }
        // スコアの数を0にリセット
        scoreNumber = 0;
        // ハイスコアをplayerprefsに記録
        // ハイスコアの個数分scoreNumberをインクリメント
        for (int i = 0; i < highScores.Count; i++)
        {
            // Debug.Log(highScores[i]);
            PlayerPrefs.SetInt(keyList[i], highScores[i]);
            scoreNumber++;
            // Debug.Log("set prefs high score cycle");
        }
        // ハイスコアの個数をplayerprefsに記録
        PlayerPrefs.SetInt("scoreNumber", scoreNumber);
        SceneManager.LoadScene("MainScene");

        }


//ステージ2の場合
        else if (PlayerPrefs.GetInt("secondLap", 0) == 1) {

            // playerprefsからscoreNumberの分(1~10)だけハイスコアを取ってくる
            for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber2"); i++)
            {
                highScores2.Add(PlayerPrefs.GetInt(keyList2[i]));
                // Debug.Log("high score add from pref cycle");
            }
            // 今回のスコアをハイスコアに追加する
            // if finishFlag == true
            highScores2.Add(GameManager.score);
            // ハイスコアをソート
            // highScores.Sort((int x, int y) => { return y - x; });
            highScores2.Sort((x, y) => y - x);

            if (highScores2.Count > 10)
            {
                highScores2.RemoveAt(10);
                // Debug.Log("memorized score is more than 10");
            }
            // スコアの数を0にリセット
            scoreNumber2 = 0;
            // ハイスコアをplayerprefsに記録
            // ハイスコアの個数分scoreNumberをインクリメント
            for (int i = 0; i < highScores2.Count; i++)
            {
                // Debug.Log(highScores[i]);
                PlayerPrefs.SetInt(keyList2[i], highScores2[i]);
                scoreNumber2++;
                // Debug.Log("set prefs high score cycle");
            }
            // ハイスコアの個数をplayerprefsに記録
            PlayerPrefs.SetInt("scoreNumber2", scoreNumber2);
            SceneManager.LoadScene("MainScene");



        }
    }


スコアの表示(スコアシーンのステージ1のスクリプト)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HighScoreManager : MonoBehaviour
{
    List<GameObject> highScoreTexts = new List<GameObject>();

    void Start()
    {
        // Debug.Log(PlayerPrefs.GetInt("scoreNumber"));

        for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber"); i++)
        {
            // Debug.Log(PlayerPrefs.GetInt((i + 1).ToString()));
            highScoreTexts.Add(Instantiate(
                Resources.Load<GameObject>("Prefabs/RankText"),
                transform.position,
                Quaternion.identity
            ));
            highScoreTexts[i].transform.SetParent(transform);
            highScoreTexts[i].transform.localScale = new Vector3(1, 1, 1);
            highScoreTexts[i].GetComponent<RectTransform>().anchoredPosition = new Vector3(65, 400 - (145 * (i + 1)));
            highScoreTexts[i].transform.Find("Text").GetComponent<Text>().text
            = (i + 1).ToString() + ".  " + PlayerPrefs.GetInt((i + 1).ToString()).ToString();
            // highScoreTexts[i].transform.Find("Text").GetComponent<Text>().text = "aiueo";
        }





    }

    void Update()
    {

    }
}

スコアの表示(スコアシーンのステージ2のスクリプト)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HighScoreManager2 : MonoBehaviour
{

    List<GameObject> highScoreTexts2 = new List<GameObject>();

    void Start()
    {
        // Debug.Log(PlayerPrefs.GetInt("scoreNumber"));

        for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber2"); i++)
        {
            // Debug.Log(PlayerPrefs.GetInt((i + 1).ToString()));
            highScoreTexts2.Add(Instantiate(
                Resources.Load<GameObject>("Prefabs/RankText2"),
                transform.position,
                Quaternion.identity
            ));
            highScoreTexts2[i].transform.SetParent(transform);
            highScoreTexts2[i].transform.localScale = new Vector3(1, 1, 1);
            highScoreTexts2[i].GetComponent<RectTransform>().anchoredPosition = new Vector3(65, 400 - (145 * (i + 1)));
            highScoreTexts2[i].transform.Find("Text2").GetComponent<Text>().text
            = (i + 1).ToString() + ".  " + PlayerPrefs.GetInt((i + 1).ToString()).ToString();
            // highScoreTexts[i].transform.Find("Text").GetComponent<Text>().text = "aiueo";
        }





    }

    void Update()
    {

    }
}


pfefabのRankTextとRankText2にアタッチ

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EnhancedUI.EnhancedScroller;
using UnityEngine.UI;

public class CellView : EnhancedScrollerCellView
{
    public Text m_nameTextUI;

    public void SetData(ScrollerData data)
    {
        m_nameTextUI.text = data.m_name;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EnhancedUI.EnhancedScroller;

public class ScrollerController : MonoBehaviour, IEnhancedScrollerDelegate
{

    public CellView m_cellPrefab;


    private ScrollerData[] m_list;


    private void Start()
    {



    }

    public int GetNumberOfCells(EnhancedScroller scroller)
    {
        return m_list.Length;

    }



    public float GetCellViewSize(EnhancedScroller scroller, int dataIndex)
    {
        return 60f;
    }


    public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex)
    {
        var cellView = scroller.GetCellView(m_cellPrefab) as CellView;

        cellView.SetData(m_list[dataIndex]);

        return cellView;


    }



}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScrollerData
{
    public string m_name;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hikaaaaaaaa

    2020/05/11 14:20

    こちらの理解不足で申し訳ございまん。。

    こちら設定はしていないと思います。。

    キャンセル

  • YASU_jrt

    2020/05/11 15:50

    ちなみに同じような内容の質問をあげられているようですが、
    スコアの保存だけに関しての回答はそちらにしたほうがいいですか?
    https://teratail.com/questions/260537

    キャンセル

  • hikaaaaaaaa

    2020/05/11 15:51

    こちらで大丈夫です。
    ありがとうございます。。

    キャンセル

回答 1

+1

こんにちは。
私はEnhancedScrollerに関しては詳しくないので、全ての問題が解決されるかはわかりませんが、
スコアの保存と取得に関しての修正案を提示致します。

今回スコアの保存に使用している
PlayerPrefs.SetInt()
は第一引数に保存するデータのキーとなる文字列を指定する必要があります。
指定する文字列そのものは何でもいいのですが、別のデータとして保存する場合は違う文字列を指定する必要があります。
PlayerPrefs.SetInt()

例えば、
ステージ1の1番目の得点のキーは、"Stage1_1"
ステージ1の2番目の得点のキーは、"Stage1_2"
ステージ2の1番目の得点のキーは、"Stage2_1"
といった感じにです。

PlayerPrefs.SetInt("Stage1_1", 10);
PlayerPrefs.SetInt("Stage1_2", 8);
PlayerPrefs.SetInt("Stage2_1", 15);

同じキーを使ってPlayerPrefs.SetInt()を使うと上書きされます。

EndSceneManagerクラスのReturn()関数内で
PlayerPrefs.SetInt()を使って得点を保存しているようですが、
キーとして使用しているkeyListお呼びkeyList2は配列の初期化はされていますが、別々の文字列を指定していないため各ステージの得点がすべて同じ保存先に上書きされ正しく保存されていないように見受けられます。

以下のスクリプトのように各ステージの得点毎に別のキーを指定してあげれば正しく保存されると思います。

// ステージ1の場合
for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber"); i++)
{
    // stage1_インデックス番号の形で文字列を生成する
    string key = string.Format("stage1_{0}", i);
    PlayerPrefs.SetInt(key, highScores[i]);
}
// ステージ2の場合
for (int i = 0; i < PlayerPrefs.GetInt("scoreNumber2"); i++)
{
    // stage2_インデックス番号の形で文字列を生成する
    string key = string.Format("stage2_{0}", i);
    PlayerPrefs.SetInt(key, highScores2[i]);
}

得点を取得する場合もHighScoreManager,HighScoreManager2を見る限り
両方ともPlayerPrefs.GetInt((i + 1).ToString())という形で取得していますが、
上記のPlayerPrefs.SetInt()と同じキーを使うことで正しく得点を取得できると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/12 11:41

    ご回答ありがとうございます。

    上記のコードを実装した際に、
    string key = string.Format("stage1_{1}", i);のiの部分で書式設定文字列で引数が設定されていません。
    と表示がされてしまいます。。

    キャンセル

  • 2020/05/12 17:14

    おっと、申し訳ない.
    正しくは以下の通りでした。修正しましたのでご確認を。
    string.Format("stage1_{0}", i);

    string.Format()については以下のリファレンスを参考にしてみてください。
    https://docs.microsoft.com/ja-jp/dotnet/api/system.string.format?view=netcore-3.1

    キャンセル

  • 2020/05/13 14:59

    ご回答ありがとうございます。
    上記の通りに実装した際に
    ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    と出てきてしまいます。
    リストの個数以上の範囲を指定しているとの事ですがコード上そのような設定はしていないように思います。。

    もしお分かりになるのならばアドバイスいただけますと幸いです。

    キャンセル

  • 2020/05/13 19:19

    ありえるとしたら、highScores が scoreNumber 分用意されていない時などでしょうかね。
    エラーが起きる箇所の前にログを仕込んで、実際の数値を確認してみてはいかがでしょうか。

    Debug.LogFormat("scoreNumber = {0}", PlayerPrefs.GetInt("scoreNumber"));
    Debug.LogFormat("highScores count = {0}", highScores.Count);

    上記のようなログを仕込むことで、Unityのコンソールウィンドウに実際のスクリプトが動いているときの数値が表示できます。
    今回の書き方では {0} の部分に各変数の値が表示される書き方になっています。
    これで実際に数値がどのように変動しているかを調べることができます。

    それでも原因がわからない場合は、
    この質問内容に追記で、修正したスクリプトを記述してもらえれば確認してみますよ。

    キャンセル

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

  • ただいまの回答率 87.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る