วิธีที่เหมาะสมในการจัดการข้อมูลระหว่างฉากคืออะไร?


52

ฉันกำลังพัฒนาเกม 2D เกมแรกของฉันใน Unity และฉันเจอสิ่งที่ดูเหมือนคำถามสำคัญ

ฉันจะจัดการข้อมูลระหว่างฉากได้อย่างไร

ดูเหมือนจะมีคำตอบที่แตกต่างกันสำหรับสิ่งนี้:

  • มีคนพูดถึงการใช้PlayerPrefsในขณะที่คนอื่นบอกฉันว่าควรใช้เก็บสิ่งอื่น ๆ เช่นความสว่างของหน้าจอเป็นต้น

  • มีคนบอกฉันว่าวิธีที่ดีที่สุดคือให้แน่ใจว่าเขียนทุกอย่างเป็นเกมเซฟทุกครั้งที่ฉันเปลี่ยนฉากและเพื่อให้แน่ใจว่าเมื่อฉากใหม่โหลดขึ้นมารับข้อมูลจาก savegame อีกครั้ง เรื่องนี้ดูเหมือนว่าฉันจะสิ้นเปลืองในการแสดง ฉันผิดหรือเปล่า?

  • โซลูชันอื่นซึ่งเป็นสิ่งที่ฉันนำมาใช้จนถึงขณะนี้คือการมีวัตถุเกมระดับโลกที่ไม่ได้ถูกทำลายระหว่างฉากจัดการข้อมูลทั้งหมดระหว่างฉาก ดังนั้นเมื่อเกมเริ่มขึ้นฉันโหลดฉากเริ่มต้นที่มีการโหลดวัตถุนี้ หลังจากจบเกมจะโหลดฉากเกมจริงครั้งแรกโดยปกติจะเป็นเมนูหลัก

นี่คือการดำเนินการของฉัน:

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

public class GameController : MonoBehaviour {

    // Make global
    public static GameController Instance {
        get;
        set;
    }

    void Awake () {
        DontDestroyOnLoad (transform.gameObject);
        Instance = this;
    }

    void Start() {
        //Load first game scene (probably main menu)
        Application.LoadLevel(2);
    }

    // Data persisted between scenes
    public int exp = 0;
    public int armor = 0;
    public int weapon = 0;
    //...
}

วัตถุนี้สามารถจัดการกับชั้นเรียนอื่น ๆ ของฉันเช่นนี้:

private GameController gameController = GameController.Instance;

ขณะที่สิ่งนี้ได้ผลมาแล้วมันทำให้ฉันมีปัญหาใหญ่หนึ่งอย่าง: ถ้าฉันต้องการโหลดฉากโดยตรงสมมติว่าในระดับสุดท้ายของเกมฉันไม่สามารถโหลดได้โดยตรงเนื่องจากฉากนั้นไม่มีสิ่งนี้วัตถุเกมทั่วโลก

ฉันจัดการปัญหานี้ในทางที่ผิดหรือไม่? มีวิธีปฏิบัติที่ดีกว่าสำหรับความท้าทายแบบนี้หรือไม่? ฉันชอบที่จะได้ยินความคิดเห็นความคิดและข้อเสนอแนะของคุณเกี่ยวกับปัญหานี้

ขอบคุณ

คำตอบ:


64

รายการในคำตอบนี้เป็นวิธีพื้นฐานในการจัดการสถานการณ์นี้ แม้ว่าวิธีการเหล่านี้ส่วนใหญ่ไม่ได้ปรับขนาดให้ดีสำหรับโครงการขนาดใหญ่ หากคุณต้องการสิ่งที่ปรับขนาดได้มากกว่าและไม่กลัวที่จะทำให้มือสกปรกลองดูคำตอบจาก Lea Hayesเกี่ยวกับกรอบการพึ่งพาการพึ่งพา


1. สคริปต์แบบคงที่สำหรับเก็บข้อมูลเท่านั้น

คุณสามารถสร้างสคริปต์คงที่เพื่อเก็บข้อมูลเท่านั้น เนื่องจากเป็นแบบคงที่คุณไม่จำเป็นต้องกำหนดให้กับ GameObject คุณสามารถเข้าถึงข้อมูลของคุณเช่นScriptName.Variable = data;ฯลฯ

ข้อดี:

  • ไม่ต้องใช้อินสแตนซ์หรือซิงเกิลตัน
  • คุณสามารถเข้าถึงข้อมูลได้จากทุกที่ในโครงการของคุณ
  • ไม่มีรหัสพิเศษเพื่อส่งผ่านค่าระหว่างฉาก
  • ตัวแปรและข้อมูลทั้งหมดในสคริปต์เหมือนฐานข้อมูลเดียวทำให้จัดการได้ง่าย

จุดด้อย:

  • คุณจะไม่สามารถใช้ Coroutine ภายในสคริปต์คงที่
  • คุณอาจจะต้องจบลงด้วยตัวแปรหลายบรรทัดในคลาสเดียวถ้าคุณจัดการไม่ดี
  • คุณไม่สามารถกำหนดฟิลด์ / ตัวแปรภายในเครื่องมือแก้ไขได้

ตัวอย่าง:

public static class PlayerStats
{
    private static int kills, deaths, assists, points;

    public static int Kills 
    {
        get 
        {
            return kills;
        }
        set 
        {
            kills = value;
        }
    }

    public static int Deaths 
    {
        get 
        {
            return deaths;
        }
        set 
        {
            deaths = value;
        }
    }

    public static int Assists 
    {
        get 
        {
            return assists;
        }
        set 
        {
            assists = value;
        }
    }

    public static int Points 
    {
        get 
        {
            return points;
        }
        set 
        {
            points = value;
        }
    }
}

2. DontDestroyOnLoad

หากคุณต้องการสคริปต์ของคุณจะได้รับมอบหมายให้ GameObject หรือเป็นผลมาจาก MonoBehavior แล้วคุณสามารถเพิ่มDontDestroyOnLoad(gameObject);สายการเรียนของคุณที่จะสามารถดำเนินการครั้งเดียว(วางไว้ในAwake()คือ usally วิธีที่จะไปสำหรับเรื่องนี้)

ข้อดี:

  • งาน MonoBehaviour ทั้งหมด (เช่น Coroutines) สามารถทำได้อย่างปลอดภัย
  • คุณสามารถกำหนดเขตข้อมูลภายในเครื่องมือแก้ไข

จุดด้อย:

  • คุณอาจจะต้องปรับฉากของคุณขึ้นอยู่กับสคริปต์
  • คุณอาจต้องตรวจสอบว่าโหลด secene ใดเพื่อตรวจสอบว่าต้องทำอะไรใน Update หรือฟังก์ชั่น / วิธีการทั่วไปอื่น ๆ ตัวอย่างเช่นหากคุณกำลังทำอะไรบางอย่างกับ UI ใน Update () คุณจะต้องตรวจสอบว่ามีการโหลดซีนที่ถูกต้องเพื่อทำงานหรือไม่ สิ่งนี้ทำให้เกิดการโหลด if-else หรือการตรวจสอบกรณีสวิตช์

3. PlayerPrefs

คุณสามารถใช้สิ่งนี้หากคุณต้องการจัดเก็บข้อมูลของคุณแม้ว่าเกมจะปิด

ข้อดี:

  • จัดการได้ง่ายเนื่องจาก Unity จัดการกระบวนการพื้นหลังทั้งหมด
  • คุณสามารถส่งผ่านข้อมูลไม่เพียง แต่ระหว่างฉาก แต่ระหว่างอินสแตนซ์ (เซสชันเกม)

จุดด้อย:

  • ใช้ระบบไฟล์
  • ข้อมูลสามารถเปลี่ยนแปลงได้ง่ายจากไฟล์ prefs

4. การบันทึกเป็นไฟล์

นี่เป็นค่าใช้จ่ายที่มากเกินไปสำหรับการจัดเก็บค่าระหว่างฉาก หากคุณไม่ต้องการการเข้ารหัสฉันไม่แนะนำให้คุณใช้วิธีนี้

ข้อดี:

  • คุณสามารถควบคุมข้อมูลที่บันทึกไว้ซึ่งต่างจาก PlayerPrefs
  • คุณสามารถส่งผ่านข้อมูลไม่เพียง แต่ระหว่างฉาก แต่ระหว่างอินสแตนซ์ (เซสชันเกม)
  • คุณสามารถถ่ายโอนไฟล์ (แนวคิดเนื้อหาที่ผู้ใช้สร้างขึ้นอยู่กับสิ่งนี้)

จุดด้อย:

  • ช้า.
  • ใช้ระบบไฟล์
  • ความเป็นไปได้ของการอ่าน / การโหลดข้อขัดแย้งที่เกิดจากการขัดจังหวะกระแสขณะบันทึก
  • ข้อมูลสามารถเปลี่ยนแปลงได้ง่ายจากไฟล์เว้นแต่ว่าคุณจะใช้การเข้ารหัส (ซึ่งจะทำให้รหัสช้าลง)

5. รูปแบบซิงเกิล

รูปแบบซิงเกิลเป็นหัวข้อร้อนแรงในการเขียนโปรแกรมเชิงวัตถุ บางคนแนะนำและบางคนก็ไม่ ค้นคว้าด้วยตนเองและโทรออกตามความเหมาะสมขึ้นอยู่กับเงื่อนไขของโครงการ

ข้อดี:

  • ง่ายต่อการติดตั้งและใช้งาน
  • คุณสามารถเข้าถึงข้อมูลได้จากทุกที่ในโครงการของคุณ
  • ตัวแปรและข้อมูลทั้งหมดในสคริปต์เหมือนฐานข้อมูลเดียวทำให้จัดการได้ง่าย

จุดด้อย:

  • รหัสสำเร็จรูปจำนวนมากที่มีหน้าที่เพียงอย่างเดียวคือการรักษาและรักษาความปลอดภัยอินสแตนซ์ซิงเกิล
  • มีข้อโต้แย้งที่แข็งแกร่งกับการใช้รูปแบบเดี่ยว ระมัดระวังและทำวิจัยของคุณล่วงหน้า
  • ความเป็นไปได้ของการขัดแย้งของข้อมูลเนื่องจากการใช้งานไม่ดี
  • อาจมีความเป็นเอกภาพในการจัดการรูปแบบเดี่ยวยาก1

1 : ในบทสรุปของOnDestroyวิธีการของSingleton Script ที่มีให้ใน Unify Wikiคุณสามารถเห็นผู้เขียนอธิบายวัตถุผีที่ตกเข้าไปในโปรแกรมแก้ไขจากรันไทม์:

เมื่อ Unity จบการทำงานมันจะทำลายวัตถุในลำดับแบบสุ่ม โดยหลักการแล้วซิงเกิลตันจะถูกทำลายก็ต่อเมื่อแอปพลิเคชันหยุดทำงาน หากสคริปต์ใด ๆ เรียกอินสแตนซ์หลังจากที่ถูกทำลายมันจะสร้างออบเจ็กต์ผีที่จะอยู่ในฉากตัวแก้ไขแม้หลังจากหยุดเล่นแอปพลิเคชัน เลวจริงๆ! ดังนั้นสิ่งนี้จึงถูกสร้างขึ้นเพื่อให้แน่ใจว่าเราไม่ได้สร้างวัตถุผีที่น่ารำคาญ


8

ตัวเลือกที่เล็กน้อยที่สูงขึ้นคือการดำเนินการฉีดอยู่กับกรอบเหมือนZenject

สิ่งนี้ทำให้คุณมีอิสระในการจัดโครงสร้างแอปพลิเคชันของคุณตามที่คุณต้องการ เช่น

public class PlayerProfile
{
    public string Nick { get; set; }
    public int WinCount { get; set; }
}

จากนั้นคุณสามารถผูกชนิดกับคอนเทนเนอร์ IoC (การผกผันของการควบคุม) ด้วย Zenject การกระทำนี้จะดำเนินการภายในMonoInstallerหรือScriptableInstaller:

public class GameInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        this.Container.Bind<PlayerProfile>()
            .ToSelf()
            .AsSingle();
    }
}

อินสแตนซ์เดี่ยวของPlayerProfileถูกฉีดเข้าไปในคลาสอื่น ๆ ที่สร้างอินสแตนซ์ผ่าน Zenject โดยผ่านการสร้างคอนสตรัคชัน แต่คุณสมบัติและการฉีดฟิลด์สามารถทำได้โดยใส่คำอธิบายประกอบด้วยInjectคุณสมบัติของ Zenject

เทคนิคหลังมีการใช้เทคนิคการฉีดวัตถุเกมในฉากของคุณโดยอัตโนมัติเนื่องจากความสามัคคียกตัวอย่างวัตถุเหล่านี้ให้คุณ:

public class WinDetector : MonoBehaviour
{
    [Inject]
    private PlayerProfile playerProfile = null;


    private void OnCollisionEnter(Collision collision)
    {
        this.playerProfile.WinCount += 1;
        // other stuff...
    }
}

ไม่ว่าด้วยเหตุผลใดก็ตามคุณอาจต้องการผูกการใช้งานโดยส่วนต่อประสานแทนที่จะใช้ตามประเภทการใช้งาน (ข้อจำกัดความรับผิดชอบสิ่งต่อไปนี้ไม่ควรเป็นตัวอย่างที่น่าทึ่งฉันสงสัยว่าคุณต้องการวิธีการบันทึก / โหลดในตำแหน่งนี้ ... แต่นี่แสดงตัวอย่างว่าการใช้งานอาจแตกต่างกันอย่างไร

public interface IPlayerProfile
{
    string Nick { get; set; }
    int WinCount { get; set; }

    void Save();
    void Load();
}

[JsonObject]
public class PlayerProfile_Json : IPlayerProfile
{
    [JsonProperty]
    public string Nick { get; set; }
    [JsonProperty]
    public int WinCount { get; set; }


    public void Save()
    {
        ...
    }

    public void Load()
    {
        ...
    }
}

[ProtoContract]
public class PlayerProfile_Protobuf : IPlayerProfile
{
    [ProtoMember(1)]
    public string Nick { get; set; }
    [ProtoMember(2)]
    public int WinCount { get; set; }


    public void Save()
    {
        ...
    }

    public void Load()
    {
        ...
    }
}

ซึ่งจากนั้นสามารถผูกกับคอนเทนเนอร์ IoC ในลักษณะคล้ายกันก่อนหน้านี้:

public class GameInstaller : MonoInstaller
{
    // The following field can be adjusted using the inspector of the
    // installer component (in this case) or asset (in the case of using
    // a ScriptableInstaller).
    [SerializeField]
    private PlayerProfileFormat playerProfileFormat = PlayerProfileFormat.Json;


    public override void InstallBindings()
    {
        switch (playerProfileFormat) {
            case PlayerProfileFormat.Json:
                this.Container.Bind<IPlayerProfile>()
                    .To<PlayerProfile_Json>()
                    .AsSingle();
                break;

            case PlayerProfileFormat.Protobuf:
                this.Container.Bind<IPlayerProfile>()
                    .To<PlayerProfile_Protobuf>()
                    .AsSingle();
                break;

            default:
                throw new InvalidOperationException("Unexpected player profile format.");
        }
    }


    public enum PlayerProfileFormat
    {
        Json,
        Protobuf,
    }
}

3

คุณกำลังทำสิ่งต่าง ๆ ในวิธีที่ดี มันเป็นวิธีที่ฉันทำและเห็นได้ชัดว่าผู้คนทำกันอย่างไรเพราะสคริปต์ออโต้โหลดเดอร์นี้ (คุณสามารถตั้งฉากให้โหลดอัตโนมัติก่อนเมื่อคุณกด Play) มีอยู่: http://wiki.unity3d.com/index.php/ SceneAutoLoader

ตัวเลือกทั้งสองตัวแรกเป็นสิ่งที่เกมของคุณอาจจำเป็นต้องบันทึกเกมระหว่างเซสชัน แต่สิ่งเหล่านี้เป็นเครื่องมือที่ผิดสำหรับปัญหานี้


ฉันอ่านลิงค์ที่คุณโพสต์ไว้เล็กน้อย ดูเหมือนว่ามีวิธีที่จะโหลดฉากแบบเป็นทางการที่ฉันโหลดเกมวัตถุทั่วโลก มันดูซับซ้อนเล็กน้อยดังนั้นฉันจะต้องใช้เวลาตัดสินใจว่ามันเป็นสิ่งที่แก้ปัญหาของฉัน ขอบคุณสำหรับความคิดเห็นของคุณ!
Enrique Moreno Tent

สคริปต์ที่ฉันเชื่อมโยงกับการเรียงลำดับของการแก้ปัญหานั้นในที่ที่คุณสามารถเล่นในฉากใด ๆ แทนที่จะต้องจำไว้ว่าต้องเปลี่ยนเป็นฉากเริ่มต้นทุกครั้ง มันยังคงเริ่มเกมตั้งแต่ต้นแม้ว่าจะเริ่มโดยตรงในระดับสุดท้าย คุณสามารถโกงเพื่ออนุญาตให้คุณข้ามไปที่ระดับใดก็ได้หรือเพียงแค่ปรับเปลี่ยนสคริปต์ autoload เพื่อส่งผ่านระดับไปยังเกม
jhocking

ใช่แล้ว ปัญหาก็คือ "ความน่ารำคาญ" ที่ต้องจำไว้ไม่ให้เปลี่ยนไปสู่ฉากเริ่มต้นเท่าที่ต้องแฮ็กไปรอบ ๆ เพื่อโหลดในระดับที่เฉพาะเจาะจงในใจ ขอขอบคุณ!
Enrique Moreno Tent

1

วิธีที่เหมาะในการเก็บตัวแปรระหว่างฉากคือผ่านคลาสผู้จัดการเดี่ยว ด้วยการสร้างคลาสเพื่อเก็บข้อมูลถาวรและการตั้งค่าคลาสDoNotDestroyOnLoad()นั้นเป็นคุณสามารถมั่นใจได้ว่าสามารถเข้าถึงได้ทันทีและยังคงอยู่ระหว่างฉาก

ตัวเลือกอื่นที่คุณมีคือใช้PlayerPrefsคลาส PlayerPrefsถูกออกแบบมาเพื่อช่วยให้คุณสามารถบันทึกข้อมูลระหว่างการประชุมเล่นแต่มันจะยังคงเป็นวิธีการบันทึกข้อมูลระหว่างฉาก

ใช้คลาสเดี่ยวและ DoNotDestroyOnLoad()

สคริปต์ต่อไปนี้สร้างคลาส singleton แบบถาวร คลาส singleton เป็นคลาสที่ออกแบบมาเพื่อรันเพียงอินสแตนซ์เดียวในเวลาเดียวกัน โดยการให้ฟังก์ชั่นดังกล่าวเราสามารถสร้างการอ้างอิงตนเองแบบคงที่เพื่อเข้าถึงชั้นเรียนได้จากทุกที่ ซึ่งหมายความว่าคุณสามารถเข้าถึงชั้นเรียนได้โดยตรงDataManager.instanceรวมถึงตัวแปรสาธารณะใด ๆ ภายในชั้นเรียน

using UnityEngine;

/// <summary>Manages data for persistance between levels.</summary>
public class DataManager : MonoBehaviour 
{
    /// <summary>Static reference to the instance of our DataManager</summary>
    public static DataManager instance;

    /// <summary>The player's current score.</summary>
    public int score;
    /// <summary>The player's remaining health.</summary>
    public int health;
    /// <summary>The player's remaining lives.</summary>
    public int lives;

    /// <summary>Awake is called when the script instance is being loaded.</summary>
    void Awake()
    {
        // If the instance reference has not been set, yet, 
        if (instance == null)
        {
            // Set this instance as the instance reference.
            instance = this;
        }
        else if(instance != this)
        {
            // If the instance reference has already been set, and this is not the
            // the instance reference, destroy this game object.
            Destroy(gameObject);
        }

        // Do not destroy this object, when we load a new scene.
        DontDestroyOnLoad(gameObject);
    }
}

คุณสามารถดูการใช้งานซิงเกิลตันด้านล่าง โปรดทราบว่าทันทีที่ฉันเรียกใช้ฉากเริ่มต้นวัตถุ DataManager จะย้ายจากส่วนหัวของฉากไปยังส่วนหัว "DontDestroyOnLoad" บนมุมมองลำดับชั้น

การบันทึกหน้าจอของหลาย ๆ ฉากที่กำลังโหลดในขณะที่ DataManager ยังคงอยู่ภายใต้หัวข้อ "DoNotDestroyOnLoad"

การใช้PlayerPrefsคลาส

PlayerPrefsความสามัคคีได้สร้างขึ้นในระดับการจัดการข้อมูลแบบถาวรพื้นฐานที่เรียกว่า ข้อมูลใด ๆ ที่มีความมุ่งมั่นต่อPlayerPrefsไฟล์จะยังคงอยู่ตลอดช่วงเกมดังนั้นตามปกติแล้วจะสามารถเก็บข้อมูลไว้ในฉากต่างๆได้

PlayerPrefsไฟล์สามารถเก็บตัวแปรประเภทstring, และint floatเมื่อเราใส่ค่าลงในPlayerPrefsไฟล์เราจะให้stringคีย์เพิ่มเติม เราใช้รหัสเดียวกันเพื่อเรียกคืนค่าของเราจากPlayerPrefไฟล์ในภายหลัง

using UnityEngine;

/// <summary>Manages data for persistance between play sessions.</summary>
public class SaveManager : MonoBehaviour 
{
    /// <summary>The player's name.</summary>
    public string playerName = "";
    /// <summary>The player's score.</summary>
    public int playerScore = 0;
    /// <summary>The player's health value.</summary>
    public float playerHealth = 0f;

    /// <summary>Static record of the key for saving and loading playerName.</summary>
    private static string playerNameKey = "PLAYER_NAME";
    /// <summary>Static record of the key for saving and loading playerScore.</summary>
    private static string playerScoreKey = "PLAYER_SCORE";
    /// <summary>Static record of the key for saving and loading playerHealth.</summary>
    private static string playerHealthKey = "PLAYER_HEALTH";

    /// <summary>Saves playerName, playerScore and 
    /// playerHealth to the PlayerPrefs file.</summary>
    public void Save()
    {
        // Set the values to the PlayerPrefs file using their corresponding keys.
        PlayerPrefs.SetString(playerNameKey, playerName);
        PlayerPrefs.SetInt(playerScoreKey, playerScore);
        PlayerPrefs.SetFloat(playerHealthKey, playerHealth);

        // Manually save the PlayerPrefs file to disk, in case we experience a crash
        PlayerPrefs.Save();
    }

    /// <summary>Saves playerName, playerScore and playerHealth 
    // from the PlayerPrefs file.</summary>
    public void Load()
    {
        // If the PlayerPrefs file currently has a value registered to the playerNameKey, 
        if (PlayerPrefs.HasKey(playerNameKey))
        {
            // load playerName from the PlayerPrefs file.
            playerName = PlayerPrefs.GetString(playerNameKey);
        }

        // If the PlayerPrefs file currently has a value registered to the playerScoreKey, 
        if (PlayerPrefs.HasKey(playerScoreKey))
        {
            // load playerScore from the PlayerPrefs file.
            playerScore = PlayerPrefs.GetInt(playerScoreKey);
        }

        // If the PlayerPrefs file currently has a value registered to the playerHealthKey,
        if (PlayerPrefs.HasKey(playerHealthKey))
        {
            // load playerHealth from the PlayerPrefs file.
            playerHealth = PlayerPrefs.GetFloat(playerHealthKey);
        }
    }

    /// <summary>Deletes all values from the PlayerPrefs file.</summary>
    public void Delete()
    {
        // Delete all values from the PlayerPrefs file.
        PlayerPrefs.DeleteAll();
    }
}

โปรดทราบว่าฉันใช้ความระมัดระวังเพิ่มเติมเมื่อจัดการPlayerPrefsไฟล์:

  • private static stringฉันได้บันทึกไว้แต่ละคีย์เป็น สิ่งนี้ทำให้ฉันรับประกันได้ว่าฉันใช้คีย์ที่ถูกต้องอยู่เสมอและหมายความว่าหากฉันต้องเปลี่ยนคีย์ด้วยเหตุผลใดก็ตามฉันไม่จำเป็นต้องให้แน่ใจว่าฉันเปลี่ยนการอ้างอิงทั้งหมดไป
  • ฉันบันทึกPlayerPrefsไฟล์ลงในดิสก์หลังจากเขียนลงไป สิ่งนี้อาจจะไม่สร้างความแตกต่างถ้าคุณไม่ใช้การคงอยู่ของข้อมูลในช่วงการเล่น PlayerPrefs จะบันทึกลงดิสก์ในระหว่างการปิดแอปพลิเคชั่นปกติ แต่อาจไม่สามารถโทรได้หากเกมของคุณขัดข้อง
  • ฉันตรวจสอบจริง ๆว่าแต่ละคีย์มีอยู่ในPlayerPrefsก่อนที่ฉันจะพยายามดึงค่าที่เกี่ยวข้อง นี่อาจดูเหมือนการตรวจสอบซ้ำ ๆ แบบไม่มีจุดหมาย แต่ก็เป็นวิธีปฏิบัติที่ดีที่ควรมี
  • ฉันมีDeleteวิธีที่จะเช็ดPlayerPrefsไฟล์ทันที หากคุณไม่ต้องการรวมการคงอยู่ของข้อมูลไว้ในเซสชันการเล่นคุณอาจลองเรียกใช้วิธีAwakeนี้ ด้วยการล้างPlayerPrefsไฟล์ที่เริ่มต้นของแต่ละเกมที่คุณมั่นใจได้ว่าข้อมูลใด ๆ ที่ไม่ยังคงมีอยู่จากช่วงก่อนหน้านี้ไม่ได้รับการจัดการผิดเป็นข้อมูลจากปัจจุบันเซสชั่น

คุณสามารถเห็นPlayerPrefsการทำงานด้านล่าง โปรดทราบว่าเมื่อฉันคลิก "บันทึกข้อมูล" ฉันกำลังเรียกSaveวิธีการนั้นโดยตรงและเมื่อฉันคลิก "โหลดข้อมูล" ฉันกำลังเรียกLoadวิธีนั้นโดยตรง การติดตั้งใช้งานของคุณเองนั้นอาจแตกต่างกันไป แต่ก็แสดงให้เห็นถึงพื้นฐาน

การบันทึกหน้าจอของข้อมูลที่ยังคงถูกส่งผ่านจะถูกเขียนทับจากผู้ตรวจสอบผ่านฟังก์ชั่นบันทึก () และโหลด ()


ในฐานะที่เป็นบันทึกสุดท้ายฉันควรชี้ให้เห็นว่าคุณสามารถขยายตามพื้นฐานPlayerPrefsเพื่อจัดเก็บประเภทที่มีประโยชน์มากขึ้น JPTheK9 ให้คำตอบที่ดีสำหรับคำถามที่คล้ายกันซึ่งพวกเขามีสคริปต์สำหรับการจัดลำดับอาร์เรย์ในรูปแบบสตริงเพื่อจัดเก็บในPlayerPrefsไฟล์ พวกเขายังชี้ให้เราไปUnify ชุมชนวิกิพีเดีย , ที่ผู้ใช้มีการอัปโหลดขยายตัวมากขึ้นPlayerPrefsXสคริปต์ที่จะช่วยให้การสนับสนุนสำหรับความหลากหลายมากขึ้นของประเภทเช่นเวกเตอร์และอาร์เรย์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.