Playmaker Forum

PlayMaker Updates & Downloads => Share New Actions => Topic started by: Thore on July 13, 2019, 12:14:08 PM

Title: Playmaker + Scriptable Objects = Win
Post by: Thore on July 13, 2019, 12:14:08 PM
Scriptable Objects are amazing and everybody should use them. I went ahead and made two example scripts with copious amounts of comments that show how it works and how you can make your own, even without coding experience.

From Unity's documentation: (https://docs.unity3d.com/Manual/class-ScriptableObject.html)

Quote
A ScriptableObject is a data container that you can use to save large amounts of data, independent of class instances. One of the main use cases for ScriptableObjects is to reduce your Project’s memory usage by avoiding copies of values. This is useful if your Project has a Prefab that stores unchanging data in attached MonoBehaviour scripts. Everytime you instantiate that Prefab, it will get its own copy of that data. Instead of using the method, and storing duplicated data, you can use a ScriptableObject to store the data and then access it by reference from all of the Prefabs. This means that there is one copy of the data in memory.

General Concept
Scriptable Objects are a collection of variables stored into an asset. Suppose you play Dungeons & Dragons. The book contained a character sheet printed somewhere. It defines the variables that make up one particular character. But you don't actually use that character sheet itself. You would make copies of this sheet and then fill each out to make actual characters.

By analogy, you create a scriptable object type holding whatever data you want. And then you use that type to create as many instances as you like. For example, holding stats of your RPG characters. Then you can easily make instances and fill out the values for warrior, rogue and wizard etc.

(https://i.imgur.com/K1TEeos.png)

One of best things about them is that they are versatile: They can hold one individual variable, or data sets. You can keep any collection of variables in them, settings, stats, recipes, item lists, etc. It's even useful for a single object, because everything else can reference it and read/write into it, which is what the quote above says (i.e. instead that every enemy of one type is a copy, they actually all use the exact same data set. When you, say, increase the hit points, it changes for all at once).

You can also use them instead of enums! In this case, you can leave it completely empty and use it to have "pluggable" types that can be extended without the problems of enums. For this and more example cases, check out this playlist (https://www.youtube.com/playlist?list=PLuldlT8dkudpCEkYQJb_H26BcbE7ozisX) curated by Matt Shell.

Even more amazingly, they can be nested. You can make one Scriptable Object where you define a costume, perhaps keeping some prefabs that belong to the costume. And then you can plug that "costume object" into another scriptable object for characters. Or you can make ingredients made up from ingredients, and endlessly combine them.

It's very potent also to keep persistent data across scenes. You could create a type of scriptable object called "HP" which only contains a single int value, effectively like a global variable type. And then use that to permanently keep track of the HP across scenes. Also, in many games, you can simply have enemies write into the HP asset directly, when they deal damage, without complicated FSM setups. You can even generalize this and make an Int Holder Scriptable Object, and one instance represents player 1 HP, another holds player 2 HP and so on.

How It Works
Copy both scripts somewhere into your asset folder.

ScriptableTemplate.cs is the example script to generate actual scriptable objects of one particular type. For every type you want, you make a new script. It's akin to the character sheet printed in the D&D book, but which you do not touch at all, but make assets from to fill out.

GetSetScriptableObjects.cs is the example action for Playmaker that at first simply reads out the variables from a scriptable object asset you plugged in. You can open the script, and change it, so it sets data into the asset (store data). Here’s an example to show how to do this.


You'll notice that some values are copied over. They are not entirely "correct" on purpose, just look into the script and read my comments to see why (I use this to illustrate something).

The Playmaker script by default GETs the values from the Scriptable Object you plugged in. Open up that action script, and you also see below a function to SET the values. This is saving them to the asset.

With this equipped and tons of comments in the two scripts, you should be able to create your own types. I recommend creating different actions for getting and setting. My example is simply to illustrate how it works.



Bonus: To easily tell one scriptable object type from another, you can also give them icons. To make your own, just make a PNG, and name it "<ScriptName> Icon.png". Then, copy this into Assets/Gizmos, and change the Texture Type to Editor GUI and Legacy GUI. You can download my example and try it out.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: craigz on October 16, 2019, 11:55:14 PM
Thanks for making this! :D

They're SO cool! Hard to believe there's no comments on here 🤦‍♂️

:D

cheers!
craigz
Title: Re: Playmaker + Scriptable Objects = Win
Post by: rechronicle on February 07, 2020, 05:21:27 AM
Hello,
Is it actually possible to put GetSetScriptable action in the Ecosystem / make it work with Ecosystem?
Like an editable action that you can write what you want to get/set from/to the scriptable object.

Thanks!
Title: Re: Playmaker + Scriptable Objects = Win
Post by: jeanfabre on February 20, 2020, 08:26:59 AM
Hi,

Let me give it a proper go and see how I can put that on the ecosystem.

Bye,

 Jean
Title: Re: Playmaker + Scriptable Objects = Win
Post by: rechronicle on February 20, 2020, 10:21:38 PM
Like when we can drag and drop gameObject/component into the state and 'Get Property / Set Property' pops up on the pointer.
Not sure how it works tho.

Thanks!
Title: Re: Playmaker + Scriptable Objects = Win
Post by: PlaymakerNOOB on February 28, 2020, 10:51:58 AM
Creating scriptable actions seems like it will be insanely difficult to cover everything.  Although, totally looking forward to it!
Title: Re: Playmaker + Scriptable Objects = Win
Post by: daniellogin on February 28, 2020, 11:41:27 PM
Commenting just to keep a bookmark. Thanks for the post!
Title: Re: Playmaker + Scriptable Objects = Win
Post by: jeanfabre on March 02, 2020, 06:20:41 AM
Hi,

 you actually have a bookmark system on this forum :) so you can simply add that thread to that.

Bye,

 Jean
Title: Re: Playmaker + Scriptable Objects = Win
Post by: daniellogin on March 02, 2020, 11:23:30 PM
Hi,

 you actually have a bookmark system on this forum :) so you can simply add that thread to that.

Bye,

 Jean
Thanks. I didn't notice that but will use it now.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: Broken Stylus on March 03, 2020, 01:10:57 PM
I must be dumb but I don't understand what this does. Please, can anybody explain it to me in simpler terms?
Title: Re: Playmaker + Scriptable Objects = Win
Post by: wetcircuit on March 03, 2020, 01:51:58 PM
Based on the examples given…

You'd use scriptable objects, kind of like a Rolodex™, but connected to other scriptable objets and categories of objects…. Sort of an object oriented database.

I can see it being huge for sim management games, generative worlds…  the Brackey's video shows card-stats… And seems like it's easy to keep updated, like if you wanted to introduce a new category or change system-wide stats, or add content later with new rules….

I think I will try it with some character stats for my NPC…
Title: Re: Playmaker + Scriptable Objects = Win
Post by: Thore on March 03, 2020, 02:16:20 PM
You have to think of scriptable objects in two parts: first, the “template”. This defines what variables you want to store but not “filled out”. Say, a ‘card’ is made up of a string suite and an int number. Now you defined what a card is.

The second part is making individual cards. With the template you create an asset and fill out suite = Spades, number = 11. Or suite = Hearts, number = 7.

Since these “cards” are actual assets, they can be shared and referenced across the project, that way, when you spawn a million cards, they can use the exact same asset containing the data.

Imagine the following scenarios.

Example 1
Your game has a million of zombies each with a few stats (like walking speed). When you instance the million zombies, then there are a million of identical stats stored in memory. Now with scriptable objects, you can make one literal asset that contains your stats, once, and all zombies use that exact same asset. This is like a global variable of sorts, but with collection of variables.

Example 2
Maybe you know this problem. You create several characters that use the exact same type of FSM, but in each the variable values are different. One has more health, the other can run faster etc. What if you could store the values in a sort of character sheet? So you have just one prefab, and then you could slot in a character sheet and then those values would make each instance individual.

I use this to safe variable settings during prototyping. The problem is, an FSM holds only the values you use at the moment. You cannot save them away and load them for prototype purpose. Once you change running speed, hit points etc around, your previous values are gone. Now with scriptable objects you can save those “settings” away and load them, create variants etc.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: jeanfabre on March 06, 2020, 03:34:46 AM
Hi,

 the more I think of this the more I believe it could be easier to simply create an fsm template, and then create empty prefabs with just that template and fill in the data in the fsm inspector.

This way, you don't require any coding and you can load them and use them just like scriptable objects instances. The benefit with this will be that the template can have some logic done in its fsm, again without any coding.

Bye,

 Jean
Title: Re: Playmaker + Scriptable Objects = Win
Post by: LordHorusNL on March 06, 2020, 06:03:55 PM
Hi,

 the more I think of this the more I believe it could be easier to simply create an fsm template, and then create empty prefabs with just that template and fill in the data in the fsm inspector.

This way, you don't require any coding and you can load them and use them just like scriptable objects instances. The benefit with this will be that the template can have some logic done in its fsm, again without any coding.

Bye,

 Jean

One of the big drawbacks when using this method is that you can't store or change data on these FSM templates beyond the current session/scene like you can on scriptable objects.

So in theory it would be great for retrieving data, but useless when storing it.

And the option for storing data from session to session is one of the biggest benefits to using scriptable objects for me personally.

But damn you need a lot of custom actions when working with scriptables.


Edit: Never mind, turns out you can store persistent data on FSM templates, hot damn you learn something new with PlayMaker every day. :P
Title: Re: Playmaker + Scriptable Objects = Win
Post by: Broken Stylus on March 07, 2020, 02:25:15 PM
You have to think of scriptable objects in two parts: first, the “template”. This defines what variables you want to store but not “filled out”. Say, a ‘card’ is made up of a string suite and an int number. Now you defined what a card is.

The second part is making individual cards. With the template you create an asset and fill out suite = Spades, number = 11. Or suite = Hearts, number = 7.

Since these “cards” are actual assets, they can be shared and referenced across the project, that way, when you spawn a million cards, they can use the exact same asset containing the data.

Imagine the following scenarios.

Example 1
Your game has a million of zombies each with a few stats (like walking speed). When you instance the million zombies, then there are a million of identical stats stored in memory. Now with scriptable objects, you can make one literal asset that contains your stats, once, and all zombies use that exact same asset. This is like a global variable of sorts, but with collection of variables.

Example 2
Maybe you know this problem. You create several characters that use the exact same type of FSM, but in each the variable values are different. One has more health, the other can run faster etc. What if you could store the values in a sort of character sheet? So you have just one prefab, and then you could slot in a character sheet and then those values would make each instance individual.

I use this to safe variable settings during prototyping. The problem is, an FSM holds only the values you use at the moment. You cannot save them away and load them for prototype purpose. Once you change running speed, hit points etc around, your previous values are gone. Now with scriptable objects you can save those “settings” away and load them, create variants etc.

Thank you for this detailed explanation. I used my last neurons trying to comprehend it so here's my take at what it means:

Example 1
That's like a typical Unity Prefab (with its own FSMs).

Example 2
Wouldn't each character, instantiated from a Prefab too, have a FSM or too that would also fetch those stats from the sheet?
You ascribe an ID to each character which you use to find the proper values for a given variable.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: rechronicle on March 07, 2020, 10:45:51 PM
You ascribe an ID to each character which you use to find the proper values for a given variable.

How do you set up the connection between the data and their respective ID? Or is it just simply using 'Int Compare' and 'Int Switch'?
Title: the subject of this thread is the subject of this thread is
Post by: Broken Stylus on March 08, 2020, 08:10:10 AM
Something along those lines. I suppose an action that parses the sheet/array for a specific key (ID) would retrieve the entire line of stats. The advantage of sheets is that you could present them in a table of virtual limitless columns, which is not possible with Arrays, Array Lists or Hash Tables.

As to how define the IDs, either it has to be done manually for each character, something you cannot avoid, or you have so many computer generated characters that you create a random string of letters and numbers and attribute them to each new instance, with also storing them in string array every time which you'll check on to see if the string has already been created and attributed. That or you code your ID generator in such a way that you know it's never going to generate the same ID twice.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: DanielThomas on March 10, 2020, 02:39:02 PM
I can recommend a SO package such as Unity Atoms (which I use myself with positive results): https://adamramberg.github.io/unity-atoms/

The SO events and event listeners have really made a difference in making everything modular and been a nice bridge between scripts and Playmaker. Of course great at storing and sharing data between scripts/FSMs as well:
https://unity.com/how-to/architect-game-code-scriptable-objects
or:


I've made a few actions myself as I needed them, but they're for Unity Atoms v2 and v4 is just around the corner which has API breaking changes.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: jeanfabre on March 11, 2020, 02:34:16 AM
Hi,

 Very interesting this atoms thingy!

Bye,

 Jean
Title: Re: Playmaker + Scriptable Objects = Win
Post by: Thore on June 02, 2020, 07:04:42 PM
I am not quite ready to go all in with scriptable objects, but I found Matt Shell's cookbook playlist very useful and added some of these principles and script ideas to my project, and combined it with PlayMaker.

https://www.youtube.com/playlist?list=PLuldlT8dkudpCEkYQJb_H26BcbE7ozisX
Title: Re: Playmaker + Scriptable Objects = Win
Post by: GR00V3R on June 13, 2020, 11:32:29 AM
Hi Thore, et al!   :)

Firstly, THANK YOU for working on this Action!    :D

So, I've got a GetScriptableObjects Action that works, having followed your quite detailed instructions (much appreciated); however, I'm struggling to make the scriptable object field an FSM Variable, and so can only set it manually in the FSM state.

Here's my GetScriptableObject code:

Code: [Select]
namespace HutongGames.PlayMaker.Actions
{

    [ActionCategory(ActionCategory.ScriptControl)]
[Tooltip("This loads the CardAsset scriptable object and passes its data into Playmaker variables.")]
public class GetScriptableObjects : FsmStateAction
{

        public CardAsset scriptableObject;
        public FsmString title;
        public FsmString description;
        public FsmObject CardImage;
        public FsmObject CardTypeImage;
        public FsmInt moveRangeMin;
        public FsmInt moveRangeMax;
        public FsmInt attackDamage;
        public FsmInt attackRange;

        // All variables you use should be reset. This means that when the action runs another time, it will clear out old values first.
        // for some reason, the .Value is not used here.
        public override void Reset()
        {

            title = "";
            description = "";
            CardImage = null;
            CardTypeImage = null;
            moveRangeMin = null;
            moveRangeMax = null;
            attackDamage = null;
            attackRange = null;

        }

        // Code that runs on entering the state.
        public override void OnEnter()
{
            // You could put the code inside here, but it's cleaner to make a function call.
            GetScriptable();
            Finish();

}

        public void GetScriptable()
        {

            title.Value = scriptableObject.Title;    // note again, FSM variables need the .Value
            description.Value = scriptableObject.Description;
            CardImage.Value = scriptableObject.CardImage;
            CardTypeImage.Value = scriptableObject.CardTypeImage;
            moveRangeMin.Value = scriptableObject.MoveRangeMin;
            moveRangeMax.Value = scriptableObject.MoveRangeMax;
            attackDamage.Value = scriptableObject.AttackDamage;
            attackRange.Value = scriptableObject.AttackRange;

        }

    }

}

And here's the CardAsset scriptable object code:

Code: [Select]
public class CardAsset : ScriptableObject
{
    [Header("General Data")]
    public string Title;
    public CharacterAsset characterAsset;
    [TextArea(2,3)]
    public string Description;
    public Sprite CardImage;
    public Sprite CardTypeImage;

    [Header("Move Data")]
    public int MoveRangeMin;
    public int MoveRangeMax;

    [Header("Attack Data")]
    public int AttackDamage;  // if not 0, this is a Movement card
    public int AttackRange;

}

Any suggestions as to what I should be doing to allow scriptableObject to be an FSM Variable?
Title: Re: Playmaker + Scriptable Objects = Win
Post by: GR00V3R on June 13, 2020, 08:19:48 PM
I tried to come at this a slightly different way with the following, but I still get the same fundamental issue, which is that Unity won't allow implicit conversion from FsmObject to CardAsset.

Code: [Select]
using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{

    [ActionCategory(ActionCategory.ScriptControl)]
[Tooltip("This loads the CardAsset scriptable object and passes its data into Playmaker variables.")]
public class GetScriptableObjects : FsmStateAction
{

        // public CardAsset scriptableObject;
        public FsmObject tempScriptableObject;  // ADDED
        public FsmString title;
        public FsmString description;
        public FsmObject CardImage;
        public FsmObject CardTypeImage;
        public FsmInt moveRangeMin;
        public FsmInt moveRangeMax;
        public FsmInt attackDamage;
        public FsmInt attackRange;

        // All variables you use should be reset. This means that when the action runs another time, it will clear out old values first.
        // for some reason, the .Value is not used here.
        public override void Reset()
        {

            title = "";
            description = "";
            CardImage = null;
            CardTypeImage = null;
            moveRangeMin = null;
            moveRangeMax = null;
            attackDamage = null;
            attackRange = null;

        }

        // Code that runs on entering the state.
        public override void OnEnter()
{
            // You could put the code inside here, but it's cleaner to make a function call.
            GetScriptable();
            Finish();

}

        public void GetScriptable()
        {

            CardAsset scriptableObject = ScriptableObject.CreateInstance<CardAsset>(); // ADDED
            scriptableObject = tempScriptableObject; // ADDED
            title.Value = scriptableObject.Title;    // note again, FSM variables need the .Value
            description.Value = scriptableObject.Description;
            CardImage.Value = scriptableObject.CardImage;
            CardTypeImage.Value = scriptableObject.CardTypeImage;
            moveRangeMin.Value = scriptableObject.MoveRangeMin;
            moveRangeMax.Value = scriptableObject.MoveRangeMax;
            attackDamage.Value = scriptableObject.AttackDamage;
            attackRange.Value = scriptableObject.AttackRange;

        }

    }

}
Title: Re: Playmaker + Scriptable Objects = Win
Post by: Thore on June 14, 2020, 06:51:29 AM
Hi,

The TDLR version: create a FSM variable of "object". No need to fill in anything. Here, I called it "fsmScriptableObject". This code allows you to cast your custom Scriptable Object into the FsmObject variable.

Code: [Select]
fsmScriptableObject.Value = (MyScriptableObject)scriptable;
Now that it is an FsmObject, and "inside PlayMaker", you can pass it over to some other action that uses and reads it. To access it most easily again, you need to do something like this:

Code: [Select]
scriptable = (MyScriptableObject)objectToGet.Value;
        passedAlongVariable.Value = scriptable.someInt;

... we're putting FsmObject variable into "scriptable", and then it can be used as usual to read whatever variable you want. Here, we're fetching an int.

I made two example actions that show how this works, plus the necessary scriptableObject to use in the example.

/// How To ///

(1) add the three files into a separate folder (to delete later).
(2) right click in that folder, myMenu > MyScriptableObject to make one.
(3) inspect that new object and just set some number there.
(4) in PlayMaker, set it up like shown in the attached image. The variable is just an "object", no need to configure it.
(5) gets Scriptable Object, and in a different action read the Int inside it.

Hope that helps.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: GR00V3R on June 14, 2020, 07:56:24 AM
You are awesome. Worked a treat! Thank you for the thorough response!  :)
Title: Re: Playmaker + Scriptable Objects = Win
Post by: rpgmaker12 on July 11, 2020, 07:23:55 AM
very cool, well done
Title: Re: Playmaker + Scriptable Objects = Win
Post by: tbelgrave on January 29, 2024, 06:07:08 AM
Hi,

 the more I think of this the more I believe it could be easier to simply create an fsm template, and then create empty prefabs with just that template and fill in the data in the fsm inspector.

This way, you don't require any coding and you can load them and use them just like scriptable objects instances. The benefit with this will be that the template can have some logic done in its fsm, again without any coding.

Bye,

 Jean

Hi Jean, scriptable objects still confuse me a bit. Is there any tutorials on what you mentioned here?

Thx

~t
Title: Re: Playmaker + Scriptable Objects = Win
Post by: JaclynJohnson on March 08, 2024, 01:21:50 AM
Have you found the tutorials? I am also happy today because while searching for it online, I also found https://oxessays.com/cheap-essay (https://oxessays.com/cheap-essay) website link where I found professional essay writers who will help me with all of my assignments tasks. Now, I won't take too much time to submit my assignments, otherwise, my mentor also deducts my marks for submitting the late assignments.
Title: Re: Playmaker + Scriptable Objects = Win
Post by: tbelgrave on March 08, 2024, 02:32:01 PM
No unfortunately, but Chat GPT has been an incredible help getting me going with it, I've successfully implemented SO's in my project where I store info for my Avatars/Levels and so fourth.I might do up a tut when I get a bit further in my game.