दृश्यों के बीच डेटा को संभालने का उचित तरीका क्या है?


52

मैं अपना पहला 2D गेम यूनिटी में विकसित कर रहा हूं और मुझे एक महत्वपूर्ण प्रश्न लगता है।

मैं दृश्यों के बीच डेटा को कैसे संभालूं?

इसके अलग-अलग उत्तर प्रतीत होते हैं:

  • किसी ने प्लेयरप्रैफ़ का उपयोग करते हुए उल्लेख किया है , जबकि अन्य लोगों ने मुझे बताया कि इसका उपयोग स्क्रीन चमक और अन्य चीजों को संग्रहीत करने के लिए किया जाना चाहिए।

  • किसी ने मुझे बताया कि सबसे अच्छा तरीका यह था कि मैं एक सेवगेम गेम में हर चीज लिखना सुनिश्चित करूं, जिसमें मैंने दृश्यों को बदल दिया, और यह सुनिश्चित करने के लिए कि जब नया दृश्य लोड हो जाए, तो सेवगेम से फिर से जानकारी प्राप्त करें। यह मुझे प्रदर्शन में बेकार लग रहा था। क्या मैं गलत था?

  • अन्य समाधान, जो मैंने अभी तक लागू किया है, वह एक वैश्विक गेम ऑब्जेक्ट है जो दृश्यों के बीच नष्ट नहीं होता है, दृश्यों के बीच सभी डेटा को संभालता है। इसलिए जब खेल शुरू होता है, तो मैं एक स्टार्ट सीन लोड करता हूं जहां यह ऑब्जेक्ट लोड होता है। इसके समाप्त होने के बाद, यह पहला वास्तविक गेम दृश्य लोड करता है, आमतौर पर एक मुख्य मेनू।

यह मेरा कार्यान्वयन है:

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

इस उत्तर में सूचीबद्ध इस स्थिति को संभालने के मूलभूत तरीके हैं। हालांकि, इनमें से अधिकांश विधियां बड़ी परियोजनाओं के लिए अच्छी तरह से पैमाने पर नहीं हैं। यदि आप कुछ अधिक स्केलेबल चाहते हैं और अपने हाथों को गंदे होने से डरते नहीं हैं, तो डिपेंडेंसी इंजेक्शन फ्रेमवर्क के बारे में ली हेस द्वारा उत्तर देखें


1. केवल डेटा रखने के लिए एक स्थिर स्क्रिप्ट

आप केवल डेटा रखने के लिए एक स्थिर स्क्रिप्ट बना सकते हैं। चूंकि यह स्थिर है, आपको इसे गेमऑबजेक्ट में निर्दिष्ट करने की आवश्यकता नहीं है। आप बस अपने डेटा का उपयोग कर सकते हैं जैसे 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);अपनी कक्षा में लाइन जोड़ सकते हैं जहां इसे एक बार निष्पादित किया जा सकता है (इसमें जगह देना Awake()हमारे लिए इस तरह से जाने का तरीका है)

पेशेवरों:

  • सभी MonoBehaviour जॉब्स (उदाहरण के लिए Coroutines) को सुरक्षित रूप से किया जा सकता है।
  • आप संपादक के अंदर फ़ील्ड असाइन कर सकते हैं।

विपक्ष:

  • आपको संभवतः स्क्रिप्ट के आधार पर अपने दृश्य को समायोजित करने की आवश्यकता होगी।
  • आपको शायद यह जांचने की आवश्यकता होगी कि अपडेट या अन्य सामान्य कार्यों / विधियों में क्या करना है, यह निर्धारित करने के लिए कौन सा secene लोड किया गया है। उदाहरण के लिए, यदि आप अपडेट () में UI के साथ कुछ कर रहे हैं, तो आपको यह जांचने की आवश्यकता है कि क्या काम करने के लिए सही दृश्य लोड किया गया है। इसके कारण if-else या स्विच-केस चेक लोड होता है।

3. PlayerPrefs

आप इसे लागू कर सकते हैं यदि आप यह भी चाहते हैं कि खेल बंद होने पर भी आपका डेटा संग्रहीत किया जाए।

पेशेवरों:

  • एकता को प्रबंधित करना आसान है क्योंकि एकता सभी पृष्ठभूमि प्रक्रिया को संभालती है।
  • आप न केवल दृश्यों के बीच बल्कि उदाहरणों (गेम सेशन) के बीच भी डेटा पास कर सकते हैं।

विपक्ष:

  • फ़ाइल सिस्टम का उपयोग करता है।
  • डेटा को आसानी से प्रीफ़्स फ़ाइल से बदला जा सकता है।

4. फ़ाइल में सहेजना

दृश्यों के बीच मूल्यों को संचय करने के लिए यह थोड़ा ओवरकिल है। यदि आपको एन्क्रिप्शन की आवश्यकता नहीं है, तो मैं आपको इस विधि से हतोत्साहित करता हूं।

पेशेवरों:

  • आप PlayerPrefs के विपरीत सहेजे गए डेटा के नियंत्रण में हैं।
  • आप न केवल दृश्यों के बीच बल्कि उदाहरणों (गेम सेशन) के बीच भी डेटा पास कर सकते हैं।
  • आप फ़ाइल (उपयोगकर्ता-जनित सामग्री अवधारणा इस पर निर्भर करता है) को स्थानांतरित कर सकते हैं।

विपक्ष:

  • धीरे।
  • फ़ाइल सिस्टम का उपयोग करता है।
  • बचत करते समय स्ट्रीम रुकावट के कारण पढ़ने / लोडिंग संघर्ष की संभावना।
  • जब तक आप एन्क्रिप्शन लागू नहीं करते (तब तक कोड भी धीमा हो जाएगा, डेटा फ़ाइल से आसानी से बदला जा सकता है।)

5. सिंगलटन पैटर्न

सिंगलटन पैटर्न ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग में एक बहुत ही हॉट टॉपिक है। कुछ यह सुझाव देते हैं, और कुछ नहीं करते हैं। अपने आप पर शोध करें और अपनी परियोजना की स्थितियों के आधार पर उपयुक्त कॉल करें।

पेशेवरों:

  • सेट-अप और उपयोग दोनों के लिए आसान।
  • आप अपने प्रोजेक्ट में हर जगह से डेटा एक्सेस कर सकते हैं।
  • एकल डेटाबेस जैसी स्क्रिप्ट में सभी चर और डेटा उन्हें संभालना आसान बनाते हैं।

विपक्ष:

  • बॉयलरप्लेट कोड के बहुत सारे जिनका एकमात्र काम सिंगलटन उदाहरण को बनाए रखना और सुरक्षित करना है।
  • सिंगलटन पैटर्न के उपयोग के खिलाफ मजबूत तर्क हैं । सतर्क रहें और अपना शोध पहले से कर लें।
  • खराब कार्यान्वयन के कारण डेटा क्लैश की संभावना।
  • एकता को सिंगलटन पैटर्न 1 को संभालने में कठिनाई हो सकती है ।

1 : यूनिफाइड विकी में दी गई सिंगलटन स्क्रिप्ट की OnDestroyपद्धति के सारांश में , आप लेखक को भूत की वस्तुओं का वर्णन करते हुए देख सकते हैं, जो रनटाइम से एडिटर में ब्लीड होती है:

जब एकता बुझती है, तो यह एक यादृच्छिक क्रम में वस्तुओं को नष्ट कर देती है। सिद्धांत रूप में, एक सिंगलटन केवल तब नष्ट हो जाता है जब एप्लिकेशन क्विट करता है। यदि कोई स्क्रिप्ट नष्ट होने के बाद इंस्टेंस को कॉल करती है, तो यह एक छोटी-सी भूत वाली वस्तु बनाएगी, जो एप्लिकेशन को चलाने से रोकने के बाद भी संपादक के दृश्य पर रहेगी। सच में ख़राब! तो, यह सुनिश्चित करने के लिए बनाया गया था कि हम उस छोटी गाड़ी भूत वस्तु को नहीं बना रहे हैं।


8

थोड़ा और अधिक उन्नत विकल्प ज़ेनजेक्ट जैसे ढांचे के साथ निर्भरता इंजेक्शन प्रदर्शन करना है ।

यह आपको आपके आवेदन की संरचना के लिए स्वतंत्र छोड़ देता है, लेकिन आप जो चाहते हैं; उदाहरण के लिए,

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

आप तब प्रकार को IoC (नियंत्रण का उलटा) कंटेनर से बांध सकते हैं। Zenject के साथ यह क्रिया a MonoInstallerया के अंदर की जाती है ScriptableInstaller:

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

इसके बाद सिंगलटन के उदाहरण PlayerProfileको अन्य वर्गों में इंजेक्ट किया जाता है जिन्हें ज़ेनजेक्ट के माध्यम से त्वरित किया जाता है। आदर्श रूप से कंस्ट्रक्टर इंजेक्शन के माध्यम से लेकिन संपत्ति और क्षेत्र इंजेक्शन ज़ेनजेक्ट की Injectविशेषता के साथ एनोटेट करके भी संभव है ।

बाद की विशेषता तकनीक का उपयोग आपके दृश्य की गेम ऑब्जेक्ट्स को स्वचालित रूप से इंजेक्ट करने के लिए किया जाता है क्योंकि एकता आपके लिए इन ऑब्जेक्ट्स को त्वरित करती है:

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

आप चीजों को अच्छे तरीके से कर रहे हैं। यह वह तरीका है जो मैं इसे करता हूं, और स्पष्ट रूप से कई लोग इसे करते हैं क्योंकि यह ऑटोलैडर स्क्रिप्ट (आप किसी भी दृश्य को स्वचालित रूप से लोड करने के लिए सेट कर सकते हैं जब भी आप खेलते हैं) मौजूद है: http://wiki.unity3d.com/index.php/ SceneAutoLoader

पहले दो विकल्पों में से दोनों ऐसी चीजें हैं जो आपके खेल को सत्रों के बीच खेल को बचाने के लिए आवश्यक हो सकती हैं, लेकिन वे इस समस्या के लिए गलत उपकरण हैं।


मैंने अभी आपके द्वारा पोस्ट की गई लिंक को थोड़ा पढ़ा है। ऐसा लगता है कि मैं वैश्विक गेम ऑब्जेक्ट को लोड कर रहा हूं, जहां inicial दृश्य को ऑटोलड करने का एक तरीका है। यह थोड़ा जटिल लगता है इसलिए मुझे यह तय करने के लिए कुछ समय की आवश्यकता होगी कि क्या यह ऐसा कुछ है जो मेरी समस्या को हल करता है। आपकी प्रतिक्रिया के लिए धन्यवाद!
एनरिक मोरेनो टेंट

स्क्रिप्ट मैं उस समस्या को हल करने के लिए जुड़ा हुआ है, जिसमें आप हर बार स्टार्टअप दृश्य पर स्विच करने के लिए याद रखने के बजाय किसी भी दृश्य में खेल सकते हैं। यह अभी भी खेल को शुरुआत से शुरू करता है, हालांकि अंतिम स्तर में सीधे शुरू करने के बजाय; आप किसी भी स्तर तक छोड़ने की अनुमति देने के लिए एक धोखा में डाल सकते हैं, या खेल के स्तर को पारित करने के लिए ऑटोलॉड स्क्रिप्ट को संशोधित कर सकते हैं।
झॉकिंग

हाँ अच्छी तरह से। यह परेशानी स्टार्टिंग सीन पर स्विच करने के लिए याद रखने की उतनी ज्यादा "झुंझलाहट" नहीं थी, जितनी कि दिमाग में विशिष्ट स्तर को लोड करने के लिए हैक करने की। फिर भी धन्यवाद!
एनरिक मोरेनो टेंट

1

एक एकल प्रबंधक वर्ग के माध्यम से दृश्यों के बीच चर को स्टोर करने का एक आदर्श तरीका है। लगातार डेटा संग्रहीत करने के लिए एक क्लास बनाकर, और उस क्लास को सेट करके DoNotDestroyOnLoad(), आप यह सुनिश्चित कर सकते हैं कि यह तुरंत सुलभ हो और दृश्यों के बीच बना रहे।

आपके पास एक और विकल्प PlayerPrefsकक्षा का उपयोग करना है । PlayerPrefsआपको प्ले सेशन के बीच डेटा बचाने की अनुमति देने के लिए डिज़ाइन किया गया है , लेकिन यह अभी भी दृश्यों के बीच डेटा को बचाने के साधन के रूप में काम करेगा ।

एकल वर्ग का उपयोग करना और DoNotDestroyOnLoad()

निम्न स्क्रिप्ट एक निरंतर एकल वर्ग बनाता है। एक सिंगलटन क्लास एक ऐसा वर्ग है जिसे केवल एक ही समय में एक ही उदाहरण चलाने के लिए डिज़ाइन किया गया है। इस तरह की कार्यक्षमता प्रदान करके, हम सुरक्षित रूप से एक स्थिर आत्म-संदर्भ बना सकते हैं, कहीं से भी कक्षा तक पहुँचने के लिए। इसका मतलब यह है कि आप कक्षा के साथ 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" शीर्षक पर, पदानुक्रम दृश्य पर चलता है।

कई दृश्यों की एक स्क्रीन रिकॉर्डिंग लोड की जा रही है, जबकि डेटामनेगर "DoNotDestroyOnLoad" शीर्षक के तहत बनी हुई है।

PlayerPrefsकक्षा का उपयोग करना

एकता के पास एक अंतर्निहित वर्ग है जिसे मूलभूत सतत डेटा कहा जाता हैPlayerPrefsPlayerPrefsफ़ाइल के लिए प्रतिबद्ध कोई भी डेटा गेम सत्रों में बना रहेगा , इसलिए स्वाभाविक रूप से, यह दृश्यों में डेटा को बनाए रखने में सक्षम है।

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फ़ाइल में क्रमबद्ध सरणियों के लिए एक स्क्रिप्ट प्रदान करते हैं, एक फ़ाइल में संग्रहीत की जाती है । वे हमें यूनीफाइड कम्युनिटी विकी की ओर भी इशारा करते हैं , जहां एक उपयोगकर्ता नेPlayerPrefsX वैक्टर और सरणियों जैसे अधिक प्रकार के प्रकारों के लिए समर्थन की अनुमति देने के लिए एक अधिक विस्तारक स्क्रिप्ट अपलोड की है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.