playMaker

Author Topic: Using FsmBoolField in a CustomActionEditor  (Read 1793 times)

nickfourtimes

  • Playmaker Newbie
  • *
  • Posts: 27
Using FsmBoolField in a CustomActionEditor
« on: January 22, 2019, 04:22:33 PM »
Heya,

I've got an action, and it may require a variable number of FsmBools. In my CustomActionEditor, I'm doing the following:

Code: [Select]
public override bool OnGUI() {
    ...
    EditorGUILayout.BeginHorizontal();
    EditorGUILayout.LabelField("Bools");
    EditorGUILayout.EndHorizontal();

    // show an FsmBool for each required bool
    ++EditorGUI.indentLevel;
    for(int i=0; i < numbools; ++i) {
        EditorGUILayout.BeginHorizontal();

        if (null == baseAction.Fsm) {
            Debug.LogWarning("no fsm");
        } else if (null == baseAction.bools[i]) {
            Debug.LogWarning("bad element " + i);
        } else {
            baseAction.bools[i] =
                HutongGames.PlayMakerEditor.VariableEditor.FsmBoolField(new GUIContent("Bool " + i), baseAction.Fsm, baseAction.bools[i]);
        }
        EditorGUILayout.EndHorizontal();
    }
    --EditorGUI.indentLevel;
    ...
}

However, the assignment to baseAction.bools[ i ] doesn't seem to work. You can select an FSM variable in the drop-down list, but when you select it, the action doesn't seem to retain that boolean variable.

Am I using FsmBoolField() incorrectly?

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Using FsmBoolField in a CustomActionEditor
« Reply #1 on: January 23, 2019, 12:42:32 AM »
Hi,

 yes this is tricky as you should instead an array : FsmBool[]
this way you are sure all data is properly serialized.

can you show me the base action and how you defined your bools?

FsmBoolField only work with single variable definition, not inside an array.

so another way could be that if you klow you don't need more than 10 bools, you create Bool_1, Bool_2 etc etc and manage them like that. It's of course ugly, but again you are sure of the serialization

Bye,

 Jean

nickfourtimes

  • Playmaker Newbie
  • *
  • Posts: 27
Re: Using FsmBoolField in a CustomActionEditor
« Reply #2 on: January 23, 2019, 11:17:06 AM »
This is my CustomAction (just a variant on SetAnimationTime, and I've omitted irrelevant code). Basically, if you give the action a particular AnimationClip, I want it to provide a number of FsmBools based on the number of AnimationEvents in the clip.

Code: [Select]
[ActionCategory(ActionCategory.Animation)]
    [Tooltip("Sets the current Time of an Animation, Normalize time means 0 (start) to 1 (end); useful if you don't care about the exact time. Check Every Frame to update the time continuously. This variant provides a boolean for each AnimationEvent in the animation.")]
    public class MySetAnimationTime : BaseAnimationAction {

        [RequiredField]
        [CheckForComponent(typeof(Animation))]
        public FsmGameObject animatingObject;

        [RequiredField]
        [ObjectType(typeof(AnimationClip))]
        [Tooltip("The animation clip to check for a tag.")]
        public FsmObject animationClip;

        public FsmFloat time;

        public FsmBool[] myBools;

        public bool normalized;
        public bool everyFrame;

        // for our drop-down stuff
        [HideInInspector]
        public int clipId;


        // ---------------------------------------------------------------------------------------- METHODS


        private void SetAnimationTime(GameObject go) {
            // same code as in SetAnimationTime
        }


        // ---------------------------------------------------------------------------------------- FSM METHODS

        public override void Reset() {
            animatingObject = null;
            animationClip = null;
            time = null;
            normalized = false;
            everyFrame = false;
            initialised = false;
            myBools= new FsmBool[0];

            return;
        }


        public override void OnEnter() {
            if(initialised) {
                // noop
            } else {
                Init();
            }

            SetAnimationTime(animatingObject.Value);

            if (!everyFrame) {
                Finish();
            }

            return;
        }


        public override void OnUpdate() {
            SetAnimationTime(animatingObject.Value);

            return;
        }
    }


And this is my CustomActionEditor:

Code: [Select]
[CustomActionEditor(typeof(MySetAnimationTime))]
public class MySetAnimationTimeEditor : CustomActionEditor {

    // -------------------------------------------------------------------------------------------- DATA MEMBERS
   
    // state
    GameObject prevObject;
    MySetAnimationTime mySetAnimTimeAction;


    // -------------------------------------------------------------------------------------------- METHODS

    void AnimationClipDropdown() {
        // code to choose an AnimationClip from the available clips on this Animation
    }


    void ShowMyBooleans() {
        var numbools = 0;

        // get a list of all the events/tags in the animClip
        if(null != mySetAnimTimeAction.animationClip && null != ((AnimationClip)mySetAnimTimeAction.animationClip.Value).events) {
            var animClip = (AnimationClip)mySetAnimTimeAction.animationClip.Value;
            numbools = animClip.events.Length;

            // create the array of booleans on the target
            if (0 < numbools && (null == mySetAnimTimeAction.myBools || 0 == mySetAnimTimeAction.myBools.Length)) {
                mySetAnimTimeAction.myBools = new HutongGames.PlayMaker.FsmBool[numbools];
                for (int i=0; i < numbools; ++i) {
                    mySetAnimTimeAction.myBools[i] = new HutongGames.PlayMaker.FsmBool();
                }
            }
        }

        // the label for all the snapping-point bools we're going to select from
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("My Bools");
        EditorGUILayout.EndHorizontal();

        // show each of the FsmBools
        ++EditorGUI.indentLevel;
        for(int i=0; i < numbools; ++i) {
            EditorGUILayout.BeginHorizontal();

            if (null == mySetAnimTimeAction.Fsm) {
                Debug.LogWarning("no fsm");
            } else if (null == mySetAnimTimeAction.myBools[i]) {
                Debug.LogWarning("bad eleement " + i);
            } else {
                mySetAnimTimeAction.myBools[i] =
                    HutongGames.PlayMakerEditor.VariableEditor.FsmBoolField(new GUIContent("Event " + i), mySetAnimTimeAction.Fsm, mySetAnimTimeAction.myBools[i]);
            }
            EditorGUILayout.EndHorizontal();
        }
        --EditorGUI.indentLevel;

        return;
    }


    // -------------------------------------------------------------------------------------------- GUI METHODS

    public override bool OnGUI() {
        mySetAnimTimeAction = (MySetAnimationTime)target;

        EditField("animatingObject");

        AnimationClipDropdown();

        EditField("time");
        EditField("snappedThreshold");

        ShowMyBooleans();

        EditField("normalized");
        EditField("everyFrame");

        return GUI.changed;
    }
}

Probably making all sorts of mistakes here, but I couldn't find any other examples of this use case online.

nickfourtimes

  • Playmaker Newbie
  • *
  • Posts: 27
Re: Using FsmBoolField in a CustomActionEditor
« Reply #3 on: January 23, 2019, 11:19:37 AM »
To be honest, in the meantime I think I'll just go with your suggestion of creating ten FsmBools off the bat and letting the designer fill them out as necessary, it just seems to be a much more reliable solution.

nickfourtimes

  • Playmaker Newbie
  • *
  • Posts: 27
Re: Using FsmBoolField in a CustomActionEditor
« Reply #4 on: January 23, 2019, 11:30:44 AM »
Hm... that said though, I do want to be able to use the CustomActionEditor to like, show specific labels next to each FsmBool. So, for instance, instead of simply listing the FsmBools in the array as "Element 0," "Element 1," "Element 2," and so on, I could change the labels myself to read something like: "Event 0.52s," "Event 1.05s," "Event 6.92s" and so on.

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Using FsmBoolField in a CustomActionEditor
« Reply #5 on: January 24, 2019, 03:49:52 AM »
Hi,

 then you can do that with a custom class wrapping an FsmBool, and you do a custom property drawer.

check out this post for more infos: https://hutonggames.com/playmakerforum/index.php?topic=19944.msg87644#msg87644

 Bye,

 Jean

nickfourtimes

  • Playmaker Newbie
  • *
  • Posts: 27
Re: Using FsmBoolField in a CustomActionEditor
« Reply #6 on: January 24, 2019, 03:57:24 PM »
Hm. So I've got an FsmBool wrapper:
Code: [Select]
using HutongGames.PlayMaker;

public class MyBool : FsmBool {
}

...and I've got an ObjectPropertyDrawer:
Code: [Select]
using HutongGames.PlayMakerEditor;
using UnityEditor;
using UnityEngine;

[ObjectPropertyDrawer(typeof(MyBool))]
public class MyBoolEditor : ObjectPropertyDrawer {

    public override Object OnGUI(GUIContent label, Object obj, bool isSceneObject, params object[] attributes) {
        GUILayout.BeginVertical();

        obj = EditorGUILayout.ObjectField(label, obj, typeof(MyBool), isSceneObject);

        GUILayout.Label("This is a custom object property drawer!");

        GUILayout.EndVertical();

        return obj;
    }

}

...and within one of my custom actions, I have a MyBool variable:
Code: [Select]
public MyBool someBool;

However, in the inspector for the custom action, all I see is "Some Bool" and an empty space, without the GUI label that I expected to be shown. Am I setting things up incorrectly? I couldn't find much documentation besides this, though the C# example there seems to be missing.

Thanks for your continued patience.

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Using FsmBoolField in a CustomActionEditor
« Reply #7 on: January 25, 2019, 01:55:48 AM »
Hi,l

 nop, you need a wrapper, not an extension, else you fallback into the same problem.

like that:

Code: [Select]
using HutongGames.PlayMaker;

public class MyBool  {

public FsmBool Mybool;

}

have another go with this, and if you are still struggling, I'll do a small working example.

 Bye,

 Jean