Hello and thank you! I am glad you like NodeCanvas and FlowCanvas!
There is a small bug with Unity Object Fields GUI and interfaces, where for it to work, you have to drag and drop the MonoBehaviour (that implements the inteface) itself rather than drag and drop the gameobject. (dragging and dropping the gameobject does not work for some reason).
Here is a workflow solution to achieve that:
– Select the “child” gameobject (flowScript) and open its graph editor.
– “Lock” the graph editor (with the lock button on the top right of the graph editor toolbar).
– Now select the “top” gameobject and drag and drop the actor MonoBehaviour itself (not the gameobject) on the blackboard within the graph editor (which is still locked to view the “child” gameobject graph).
Please let me know if this works for you.
I know this is somewhat cumbersome. I will try to find a solution around the Unity Object Field and that limitation with interfaces.
Thank you!
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
If you mean to have a GUI graph editor in the final build game, then this is not possible since the graph editor is made for and using the UnityEditor namespace, which is only available within the Unity Editor.
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
The two of them work differently. Here are example code with explanation comments for you.
SIGNAL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using NodeCanvas.Framework; using UnityEngine; public class ExampleSignal : MonoBehaviour { public SignalDefinition signal; //To catch, subscribe to the signal void OnEnable() { signal.onInvoke += OnSinglaInvoke; } void OnDisable() { signal.onInvoke -= OnSinglaInvoke; } //Called when signal is invoked void OnSinglaInvoke(Transform sender, Transform receiver, bool isGlobal, params object[] args) { //handling receiver and isGlobal is optional but this is what the nodes are doing if ( isGlobal || receiver == this.transform ) { Debug.Log("Sender = " + sender); Debug.Log("arg0 = " + args[0]); Debug.Log("arg1 = " + args[1]); } } //Invoke a signal in code void Update() { if ( Input.GetKeyDown(KeyCode.Space) ) { //invoke the signal only to be received by this transform as target receiver. signal.Invoke(this.transform, this.transform, false, "hello", 13f); //invoke the signal globaly without a specific target receiver. signal.Invoke(this.transform, null, true, "hello", 13f); } } } |
CUSTOM EVENT:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using FlowCanvas; using ParadoxNotion; using ParadoxNotion.Services; using UnityEngine; public class ExampleCustomEvent : MonoBehaviour { public FlowScriptController graphOwner; //All custom events are handled through the EventRouter component. //To catch events in code we need to get or add an EventRouter if it does not exist already //on the gameobject of the graphowner that we want to catch events from. //Then subscribe to its onCustomEvent. void OnEnable() { var router = graphOwner.GetComponent<EventRouter>(); if ( router == null ) { router = graphOwner.gameObject.AddComponent<EventRouter>(); } router.onCustomEvent += OnCustomEventInvoke; } //To unsubscribe we only care if the EventRouter component was there in the first place. //If so, unsubscribe from its onCustomEvent. void OnDisable() { var router = graphOwner.GetComponent<EventRouter>(); if ( router != null ) { router.onCustomEvent -= OnCustomEventInvoke; } } //Called when the event is invoked/sent void OnCustomEventInvoke(string eventName, IEventData eventData) { Debug.Log("Sender = " + eventData.sender); Debug.Log("Event Value = " + eventData.valueBoxed); } //Send an event in code void Update() { if ( Input.GetKeyDown(KeyCode.Space) ) { //send an event to the graph owner with null value and this sender graphOwner.SendEvent("MyEventName", null, this); //send an event to the graph owner with a float value and this sender graphOwner.SendEvent<float>("MyEventName", 13f, this); } } } |
If you need any clarification please let me know. 🙂
Join us on Discord: https://discord.gg/97q2Rjh
Hello again,
Thank you for your input. I believe this has more to do with the implementation of the ForEach node (and similarily for the For Loop node).
I could implement a ForEach node to act the way you describe in your first post, however there is one problem: To continue with the next element in the iteration, we have to know when the current iteration has ended and there is no apparent way to know when a “flow” has ended since a node can have multiple output ports. Therefore for this to work, it will require implementing an extra Node (like a “Return” or “Continue” node), which will we will have to use at so that the ForEach node, knows when to proceed to the next element. In your example this “Return” / “Continue” node will have to be used right after the “Log Text” node for example.
Let me know what you think.
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello again and sorry for the late reply.
You indeed have to generate the AOT related classes and link.xml files ( please note that this is documented here by the way 🙂 )
I am glad that your project is working with the generated files (?). Thank you and sorry for the late replies once again.
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
“Manual Check” be done only through code by having a reference of the state, which for example you can get with the API of the FSM class and was initially added only for being used through code. HOWEVER, I would advise against it since it is something that is definitely going to be removed in future update since it is rather a leftover feature that sometimes confuse people.
With that said, “Check Event” condition task, even every frame, in itself has pretty much zero performance impact since its update code is simply this:
1 2 3 |
protected override bool OnCheck() { return false; } |
Regarding your 2nd post about the transition not happening, I just did a test and it’s working correctly. Can you please confirm that the Check Event and Send Event are using the same name (its case sensitive) and that the target GraphOwner of both are the same GraphOwner?
Let me know. Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
Indeed, sub-flowscript are treated like Actions rather than like Conditions in the Behaviour Tree, and unfortunately, at least right now, this means that they can’t be used with the Dynamic option of nodes in the Behaviour Tree because since the Dynamic option is mean to work specifically with Conditions only. With that said, I will look again at this and see how I can make it happen 🙂
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello again,
There is an option in the Preferences (Toolbar > Prefs) to set whether or not breakpoints pause the Unity Editor (by default they do since I believe it makes a bit more sense).
If the Unity Editor is paused, then you also have to unpause the Unity Editor (I could make this automatically when you press play in the FlowCanvas editor). But if you don’t like the game to be paused, you can disable the “Breakpoints Pause Editor” in the Preferences.
Let me know if that works for you. Thanks.
Join us on Discord: https://discord.gg/97q2Rjh
You are welcome 🙂
Join us on Discord: https://discord.gg/97q2Rjh
Hello again Tomas!
Indeed, each FSM State can be a sub-FlowScript, instead of a normal Action State. Because by design each graph is serialized and stored separately as an asset, it is true that for each FSM State that you’d like to be modeled with a sub-FlowScript, a FlowScript asset graph has to be created.
Regarding your questions:
1) Do you mean attach a FlowScript asset on an existing Action State so that it runs like an action, instead of having to create a sub-FlowScript State node and attaching the FlowScript there? ( it’s not possible right now, but is that what you mean? )
2) The sub-FlowScript State node has 2 parameters in its inspector called “Success Event” and “Failure Event”, which are triggered repsective if the sub-FlowScript ended in success or failure (via the “Finish” node). Here is the related Documentation.
Regarding returning a value from the sub-FlowScript back to the FSM, this can be achieved by mapping the variables of the FSM to/from the variables of the sub-FlowScript. Please see the documentation regarding variables mapping here.
Please let me know if that is what you meant (maybe I misunderstood your question).
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
Have you built the AOTClasses and xml files as described HERE please?
Let me know. Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hey,
You can get a Global Blackboard’s Variable like this for example:
1 2 3 4 5 6 |
void Start(){ var x = GlobalBlackboard.Find("Global").GetVariableValue<float>("myFloat"); Debug.Log(x); } |
In the ‘GlobalBlackboard.Find’ you have to pass the identifier name of the Global Blackboard (as set in its inspector). Then you can use the ‘GetVariableValue
Let me know if that is what you were after. Thanks.
Join us on Discord: https://discord.gg/97q2Rjh
Hello and sorry for the late reply.
Indeed this show up because there are multiple entries that would be listed for each component, but you are right that it is somewhat redundant. I will see to it 🙂
Thanks.
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
This is the right thing to do if you want to cache a value that is performance intensive to get. So yes that is totally fine 🙂
Caching this way vs a graph variable: cache node should be better performance wise, but we are talking about minimal differences if any, therefore I would suggest to just use the workflow that you prefer better 🙂
Join us on Discord: https://discord.gg/97q2Rjh
Hello,
Do you have any errors logged in the console? If yes, can you please post the console logs here?
Let me know. Thanks.
Join us on Discord: https://discord.gg/97q2Rjh