How To Reference Savable Integers

Announcements, support questions, and discussion for the Dialogue System.
DrewThomasArt
Posts: 60
Joined: Thu Mar 24, 2022 12:07 am

How To Reference Savable Integers

Post by DrewThomasArt »

I'm following this tutorial:
https://pixelcrushers.com/phpbb/viewtop ... f=9&t=4763

My question is, how does it know what ints to save, like currentHealth and coins? It won't let me call anything from within the script. When I try to use GetComponent or .Find() it says they don't exist or it must be in reference to an object, even though the Saver script is on my player.

I don't think the Saver scripts are allowed to call other components, so how exactly will it know what to save?
(we can ignore the record data() code, forgot to fix that before the screenshot)
Screenshot (8).png
Screenshot (8).png (341.74 KiB) Viewed 830 times
Or is there another way to save ints like currentHealth and coins. Thanks for any help
User avatar
Tony Li
Posts: 21962
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Reference Savable Integers

Post by Tony Li »

Hi,

In general, you'll only want to put serializable variables in your SaveData class. Try something like this:

Code: Select all

// Assumes this script is on a GameObject that also has PlayerHealth & CoinCollecter scripts.
public class PlayerStats : Saver
{

    [Serializable]
    public class SaveData
    {
        public int currentHealth;
        public int coins;
    }    
    
    public override string RecordData()
    {
        var data = new SaveData();
        data.currentHealth = GetComponent<PlayerHealth>().currentHealth;
        data.coins = GetComponent<CoinCollector>().coins;
        return SaveSystem.Serialize(data);
    }
    
    public override ApplyData(string s)
    {
        if (string.IsNullOrEmpty(s)) return;
        var data = SaveSystem.Deserialize<SaveData>(s);
        if (data == null) return;
        GetComponent<PlayerHealth>().currentHealth = data.currentHealth;
        GetComponent<CoinCollector>().coins = data.coins;
        // NOTE: You might want to update visual representation of health & coins here
    }
}
DrewThomasArt
Posts: 60
Joined: Thu Mar 24, 2022 12:07 am

Re: How To Reference Savable Integers

Post by DrewThomasArt »

Tony Li wrote: Tue Nov 01, 2022 10:06 pm Hi,

In general, you'll only want to put serializable variables in your SaveData class. Try something like this:

Code: Select all

// Assumes this script is on a GameObject that also has PlayerHealth & CoinCollecter scripts.
public class PlayerStats : Saver
{

    [Serializable]
    public class SaveData
    {
        public int currentHealth;
        public int coins;
    }    
    
    public override string RecordData()
    {
        var data = new SaveData();
        data.currentHealth = GetComponent<PlayerHealth>().currentHealth;
        data.coins = GetComponent<CoinCollector>().coins;
        return SaveSystem.Serialize(data);
    }
    
    public override ApplyData(string s)
    {
        if (string.IsNullOrEmpty(s)) return;
        var data = SaveSystem.Deserialize<SaveData>(s);
        if (data == null) return;
        GetComponent<PlayerHealth>().currentHealth = data.currentHealth;
        GetComponent<CoinCollector>().coins = data.coins;
        // NOTE: You might want to update visual representation of health & coins here
    }
}
Thank you for writing that, that fixed all of the errors.
It seems now that when I record my health, it's being applied as 0 and instantly killing my character upon load.
To test this, I told the health to be 1000hp on load but the healthbar to use the data.currentHealth. The Healthbar shows 0 HP while my character has 1000hp
Results.png
Results.png (883.11 KiB) Viewed 825 times
ExampleCode.png
ExampleCode.png (362.05 KiB) Viewed 825 times
Even though I'm recording the data at 1000hp, as shown in this screenshot
SavingAtFullHP.png
SavingAtFullHP.png (795.25 KiB) Viewed 825 times
Is it possibly because I'm not recording the data correctly? I haven't done anything except what's in the script. However, there is no option to call the "RecordData" method from this script when I try to call it as an event in the conversation manager
NoRecordDataOption.png
NoRecordDataOption.png (437.6 KiB) Viewed 825 times
It resets the coins to 0 as well
User avatar
Tony Li
Posts: 21962
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Reference Savable Integers

Post by Tony Li »

Hi,

Are there any errors or warnings in the Console window?

There's no need to call RecordData() yourself. Since it's a Saver script, it just needs to be on the same GameObject as your PlayerHealth + CoinCollector scripts. The Save System will know to call RecordData() and ApplyData() at the correct times. You should also assign a unique Key value such as "playerStats".

As a test, after the "if (data == null) return" line in ApplyData(), add this line:

Code: Select all

if (data == null) return;
Debug.Log($"Restoring currentHealth={data.currentHealth}, coins={data.coins}"); //<-- ADD THIS
Also temporarily tick the Debug checkboxes on the SaveSystem and PlayerPrefsSavedGameDataStorer components. When you save the game, the Console will show the save data in JSON format. It will be a little hard to read, but look for something like:

Code: Select all

{key:"playerStats"}, data:{ currentHealth:1000, coins=99 }}
That will tell you what values it has saved.

When you load the saved game, the Debug.Log() line above will show something like:

Code: Select all

Restoring currentHealth=123, coins=456
DrewThomasArt
Posts: 60
Joined: Thu Mar 24, 2022 12:07 am

Re: How To Reference Savable Integers

Post by DrewThomasArt »

Thank you, I can see the values now, that has fixed the issue as well as makes the player spawn in the correct place for whatever reason. It also made me realize to put the starting currentHealth not to 0 in the inspector as well. Apparently that was registering before the script was. Either way, everything is working absolutely perfectly now thanks to you
User avatar
Tony Li
Posts: 21962
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Reference Savable Integers

Post by Tony Li »

Glad to help!
DrewThomasArt
Posts: 60
Joined: Thu Mar 24, 2022 12:07 am

Re: How To Reference Savable Integers

Post by DrewThomasArt »

Tony Li wrote: Wed Nov 02, 2022 11:26 amGlad to help!
Somewhere along the way, things got buggy and now there's no proximity selector UI as shown below:
Screenshot (16).png
Screenshot (16).png (763.54 KiB) Viewed 810 times
As you can see, I have the proximity selector. But, when I press play the "selector use standard UI elements" turns inactive.
It was working fine until I started playing around with saves and spamming it, but it's very possible I did something to the Dialogue Manager. I made a new one (in the screenshot above) and the issue persists with all NPCS and Usable game objects. I haven't changed anything on any of them. I rewatched the tutorial that demonstrates it, made sure my collider was a trigger, etc.

EDIT: After getting this error:
"Dialogue System: SelectorUseStandardUIElements can't find a StandardUISelectorElements component in the scene."
I added the component to my player and am now getting this error:
Screenshot (17).png
Screenshot (17).png (824.81 KiB) Viewed 806 times
Also my professor and his friends said my game was brilliant and at some point I said I lot of it is due to this system and getting help from a guy named Tony Li. So thank you
User avatar
Tony Li
Posts: 21962
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Reference Savable Integers

Post by Tony Li »

Hi,
DrewThomasArt wrote: Wed Nov 02, 2022 6:13 pm EDIT: After getting this error:
"Dialogue System: SelectorUseStandardUIElements can't find a StandardUISelectorElements component in the scene."
I added the component to my player and am now getting this error:
Screenshot (17).png
Remove the Standard UI Selector Elements component from your player. It should be on the selector UI instead. To do this, inspect the Dialogue Manager GameObject's Instantiate Prefabs component. Assign the "Basic Standard UI Selector Elements" prefab (or a customized copy if you prefer) to the Prefabs list. Or, if you don't want to add it to Instantiate Prefabs, just add it directly to a Canvas that's a child of the Dialogue Manager.
DrewThomasArt wrote: Wed Nov 02, 2022 6:13 pmAlso my professor and his friends said my game was brilliant and at some point I said I lot of it is due to this system and getting help from a guy named Tony Li. So thank you
Great job! And glad to help.
DrewThomasArt
Posts: 60
Joined: Thu Mar 24, 2022 12:07 am

Re: How To Reference Savable Integers

Post by DrewThomasArt »

Tony Li wrote: Wed Nov 02, 2022 7:51 pm Hi,
DrewThomasArt wrote: Wed Nov 02, 2022 6:13 pm EDIT: After getting this error:
"Dialogue System: SelectorUseStandardUIElements can't find a StandardUISelectorElements component in the scene."
I added the component to my player and am now getting this error:
Screenshot (17).png
Remove the Standard UI Selector Elements component from your player. It should be on the selector UI instead. To do this, inspect the Dialogue Manager GameObject's Instantiate Prefabs component. Assign the "Basic Standard UI Selector Elements" prefab (or a customized copy if you prefer) to the Prefabs list. Or, if you don't want to add it to Instantiate Prefabs, just add it directly to a Canvas that's a child of the Dialogue Manager.
DrewThomasArt wrote: Wed Nov 02, 2022 6:13 pmAlso my professor and his friends said my game was brilliant and at some point I said I lot of it is due to this system and getting help from a guy named Tony Li. So thank you
Great job! And glad to help.
I've tried this, (as well as just putting it on the Canvas that's on the Dialogue Manager)
Screenshot (18).png
Screenshot (18).png (507.52 KiB) Viewed 800 times
It then gives me this error,
Screenshot (19).png
Screenshot (19).png (875.68 KiB) Viewed 800 times
And the "Selector Use Standard UI Elements" component on the player becomes inactive on game start. Clicking it active doesn't do anything
User avatar
Tony Li
Posts: 21962
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Reference Savable Integers

Post by Tony Li »

Hi,

Can you compare the setup to DemoScene1? Make a note of the components that are on the Player GameObject and the Dialogue Manager GameObject. In DemoScene1, the Player has a Selector instead of a Proximity Selector, so just pretend it's a Proximity Selector for the point of comparison.
Post Reply