Improving Conditions: A Property Editor

I double checked and I had the name right. Just to experiment, and kind of taking an educated guess, I tried changing the PropertyDrawer to just being typeof(Condition) and now suddenly everything is being drawn correctly. Maybe I just did something weird with how I made Predicate a subclass?

Anyways, as long as it’s all functioning, can you foresee this potentially causing any issue or do you think it’s fine?

Thank you again, as always, for all of your help. You’re seriously awesome Brian.

As long as its’ working, I’d call it a win!

This is awesome.

One recommendation if you intend on the Enum to be constantly changed is to use Scriptable Objects instead of Enums. I do not know how many times I have added an Element to my Enum or removed an Element from an Enum and spent hours trying to hunt down everything that was using that Enum and make sure that they are all set to the correct value.

I have actually done that with Stats, CharacterClasses, and Equiplocations in the past… While it solves one problem (easily adding enums), it created a few extra problems… Not terrible problems, but things like the Health component needing to know which ScriptableStat was the Health stat…

Similarly, you would need to attach the correct ScriptablePredicate(s) to each IPredicateEvaluator class so it would know what things it was testing for…

Something like

[SerializeField] ScriptablePredicate hasQuest;
[SerializeField] ScriptablePredicate completedQuest;
[SerializeField] ScriptablePredicate completedObjective;

public bool? Evaluate(ScriptablePredicate predicate, string[] parameters)
{
     switch (predicate)
            {
                case hasQuest: 
                    return HasQuest(Quest.GetByName(parameters[0]));
                case completedQuest:
                    QuestStatus status = GetQuestStatus(Quest.GetByName(parameters[0]));
                    if (status == null) return false;
                    return status.IsComplete();
                case completedObjective:
                    QuestStatus teststatus = GetQuestStatus(Quest.GetByName(parameters[0]));
                    if (teststatus==null) return false;
                    return teststatus.IsObjectiveComplete(parameters[1]);
            }
            return null;
}

Yes it does make it a little more complicated. I haven’t gotten to this portion of the course yet. I am guessing that the use of the magic string was because this was something that was planing on being changed, or we want the designer team to have a little more control. If we are leaving it at this are the only choices then Enum is perfect solution for this. This was just a suggestion as a replacement for magic strings that are magic strings because of the limitation on changing Enums. It all depends on the reason of choosing to use magic strings in the first place.

Amazing Brian. I can’t say how much this post has improved quest development and dialogue triggers. It’s self-explaining now and a designer could pick it up without undue frustration.

Quick tip for anyone that may be doing the course on the latest version of Unity. I’ve been upgrading as I’ve gone through the course to see if there’s a point where everything decides to break. One thing I discovered is at some point (guessing 2022.2) the OOTB inspector started acting a little bit wonky with lists and custom inspectors were nearly unusable due to freezing unless you click off the object and then back on with each change (frustrating to say the least with the Predicates). A setting got introduced in Project Settings->Editor->Use IMGUI Default Inspector that needs to be checked on and then everything works perfectly.

2 Likes

The Other way around this is to switch the editor scripts over to UI Elements instead of using IMGU

At some point, I will. Catch is that PropertyDrawers written with UIElements are only shown as UIElements if the Editor they are showing is is using UIElements (that may have changed in 2022/2023, but last time I checked, that was the case. Now it may be that this is happening if newer versions fo Unity are defaulting to using Elements to draw the default inspectors.

This thread triggered me to learn about this. It’s surprisingly easy to get started with using SO as enum. But what’s the advantage of an SO for enum over something like the below? I was about to say the limitation of the below is that you can’t re-order items. But it seems an SO doesn’t solve that because SO you lose the convenience of a “drop down”. But then when you hit select the inspector will sort the assets of the correct type so maybe SO is better?

public enum myEnum
{
  a= 1,
  b= 2,
  c= 3
};

I thought maybe you could reduce the scope of this problem by having a top level ScriptableObject referencing all your “ScriptableEnums” and then just pass that one SO around? You’re then only doing that assignment once. You could probably use OnValidate on this top-level SO to sweep up missing enums and throw a warning if you failed to map one.

Hello. Sorry for such kind of question, but should not we close here property with EditorGUI.EndProperty(); command?

That still doesn’t really tell you which Enum value represents Health. :slight_smile:

Would something like the below be really dumb? I haven’t tried it… just experimenting around live.

public class EnumReference : ScriptableObject
{
    public ScriptablePredicate HasQuest;
    public ScriptablePredicate CompletedQuest;
    public ScriptablePredicate CompletedObjective;

    public ScriptableStat Health;
    public ScriptableStat Damage;
}

Yes, we should!

1 Like

This is one of the advantages of using an enum as it works out of the box that way. One of the disadvantages is that you have things set up and working.

One if the disadvantages of using an enum.
You change that enum to be

  c
  g
  b

This will cause you to have to go through all of your game objects and make sure that they are no correct. Not a big deal on a small prototype, but on a huge project or even with a team of people working together it becomes easy to miss one.
Using SO solves this issue, just rename the SO as you need.

If you want a drop down list for your SO you can create a Property Drawer for it, in the Property Drawer it collects all of the available SO of that type and displays them in a list.

1 Like

The standard inspector (or in an editor, an ObjectField) will properly show all ScriptableObjects of the same type, so

[SerializeField] ScriptableStat statToUse

will provide a standard object picker which contains only ScriptableStats.

If only Unity would provide the same Functionality for MonoBehaviours attached to prefabs.

1 Like

I like using the standard object picker, but it doesn’t show as a drop down selection list like enums which for some reason people like better.

I use Jet Brains Rider as my IDE which you can find all Unity usage. They also have a Asset called Rider Flow, I believe that this is included the ability to find all MonoBehaviour that is attached to a prefab.

I wish that this was something built straight into Unity, right click on the MonoBehaviour and find all Game Objects.

This is something that can be done with their search feature. You have to have properties indexed in the index manager.

Windows >Search>Index Manager
Under Options make sure Properties is selected.

t: prefab has:ScriptableStat

I wonder if you need to specify a prebfab or if you can just use the has: like

has:ScriptableStat

I know you can search for properties that contain a certain value

statToUse:exactNameOfScriptableStat

There is a whole list of search filters that you can use replace 2021.2 with 2022
.3 to see those that work in 2022

There is also a whole list of search providers that we can use. Like p: for project

Unity has a power full built in search tool. I forget that these filters are available when I am searching my project for things.

I just stumbled upon an Attribute that you can use when I was looking up the filters that can be used, I haven’t used it yet.

Scroll down to the Search Picker Heading.

OK so I was playing around a little bit with the code. It works beautifully, but the ‘HasLevel’ option isn’t working for some reason. I tried a few of the other options, they seem to work well, but ‘HasLevel’ isn’t working for some reason. Where can we investigate this from?

Did you set up your BaseStats.cs to be an IPredicateEvaluator and add in the needed code to test for HasLevel?

Forgot to type in ‘IPredicateEvaluator’ when defining the ‘BaseStats.cs’ class… Thanks again Brian :sweat_smile:

Privacy & Terms