NodeCanvas Forums › General Discussion › Implement two interfaces in action class
Hi,
I’m working on a new Apex action class/task where the messages of the Apex agent are subscribed and checked. At the moment a pure, separate Monobehaviour at my agentObject is doing this job, but for working with several Apex-related ActionTasks it seems better to have this functionality direct in my NC-Actions.
My MonoBehaviour class has implemented a second interface “IHandleMessage<UnitNavigationEventMessage>” for this job, see code example. If I try to implement this interface to a nodeCanvas actionTask, I get some errors, this seems the wrong way. So is there a preferred special method to implement such a interface in nodeCanvas or should I stay with the separate monobehaviour, write the agent status in a blackboard variable and start, read and stop this Monobehaviour from my actionTasks?
The rough script of the Monobehaviour with IHandleMessage:
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 49 50 51 52 53 |
using UnityEngine; using NodeCanvas; using NodeCanvas.Variables; using Apex.Messages; using Apex.Services; public class ApexCheckStatus : MonoBehaviour, IHandleMessage<UnitNavigationEventMessage> { public Blackboard blackboard; private void OnEnable() { GameServices.messageBus.Subscribe(this); } private void OnDisable() { GameServices.messageBus.Unsubscribe(this); } public void Handle(UnitNavigationEventMessage message) { switch(message.eventCode) { case UnitNavigationEventMessage.Event.DestinationReached: { Debug.Log("I have arrived :-)"); blackboard.SetDataValue("unitNavigationStatus", message.eventCode); break; } case UnitNavigationEventMessage.Event.WaypointReached: { Debug.Log("Almost there..."); blackboard.SetDataValue("unitNavigationStatus", message.eventCode); break; } case UnitNavigationEventMessage.Event.StoppedDestinationBlocked: { Debug.Log("I am blocked!"); blackboard.SetDataValue("unitNavigationStatus", message.eventCode); break; } } } } |
Hey,
What kind of error do you get if you implement the interface on a Task?
Doing so you can Subscribe the task to the message bus in OnInit. Unfortuntaly though right now there is no good spot to Unsubscribe it (I’m working on this).
In any case though, I still think that the way you are doing it is the best approach since that will make the status run in parallel of anything that your tree might be doing. For this particular case it seems fine to me, but please let me know what kind of errors you get by implementing it in a Task.
Cheers
Join us on Discord: https://discord.gg/97q2Rjh
Hey,
I will log the exact error and let you know.
Doing it with this MonoBehaviour is fine, but is it in this case not necessary to watch permanently the blackboard value unitNavigationStatus from nodeCanvas side?
I would use an root interruptor for this, check unitNavigationStatus and have the whole agent nodes as child, to receive a new navAgent status immediately and react, no matter what BT-Nodes are executed at the same moment.
Right, or do you have a more elegant approach for this timing thing in mind?
Thanks for all good advice anyway, I begin to love nodeCanvas for its clean and stable architecture – with every sucessful approach more 😉
Hey,
I’m really glad that you like NC 🙂
I’m not exactly sure what you are after, but I will go ahead and speculate something :).
Do you want to create an action that moves the agent with APEX and implement this interface to see the status of the APEX agent before ending the action in success or failure?
If that is so, then implementing the interface in the Task is probably the best approach. Just let me know of errors of what’s not working and we will make it work 🙂
If the tree is irelevant to those events (eg you are controling APEX agent in other way but you want to know of it’s status in NC) then your approach is fine.
Let me know
Join us on Discord: https://discord.gg/97q2Rjh
Hey,
your speculation is right, the agent will be controlled complete with a NC-Behaviourtree. I want to make that move-action to end in success when waypoint arrived, retarget if agent is blocked and end with failure if waypoint is unreachable.
This action task will only be the first one of a series of Apex based behavior tasks. I plan to make:
– Patrol several points
– Run maxspeed to a point
– Flee from a point / a object
– Search an area around a starting point
– Follow a leading agent
– take Cover
– some kind of flocking behavior
You see that is a lot of stuff and therefore I suppose it will need a fast and direct integration of that Apex messaging for agent controlling. At the moment I’m not sure how to split up the tasks for efficient modularity – some parts like initializing, messaging and the basics moveToPoint, get new waypoint, steering etc. will be used in every behavior, other tasks will be used in just one single behavior.
Is it useful in this case, to create something like a base class for all this actions? Never done that before;-) ??
Anyway, here are the actual errors when I plug that interface in:
Assets/02-Scripts/NC-Actions/Apex/ApexMoveToPosition.cs(16,27): warning CS0108:
NodeCanvas.Actions.ApexMoveToPosition.blackboard’ hides inherited member NodeCanvas.Task.blackboard’. Use the new keyword if hiding was intended
Assets/02-Scripts/NC-Actions/Apex/ApexMoveToPosition.cs(13,18): error CS0535: NodeCanvas.Actions.ApexMoveToPosition' does not implement interface member
Apex.Services.IHandleMessage<Apex.Messages.UnitNavigationEventMessage>.Handle(Apex.Messages.UnitNavigationEventMessage)’
And something strange: During working I saw, that there are several _MonoManagers in my scene, seems that after a unity crash a new MonoManager is added, and old are hangin around too…
Allright, enough stuff, I’m working on it and I am curious about Your advice again 🙂
Cheers
Hey,
Sorry for late reply.
So, I don’t have APEX so the following code might not work as is, but you will get the idea of how you can go about it.
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 |
using UnityEngine; using NodeCanvas; using NodeCanvas.Variables; using Apex.Steering; using Apex.Messages; using Apex.Services; namespace NodeCanvas.Actions{ [Category("Apex")] [AgentType(typeof(IMovable))] public class ApexMoveTo : ActionTask, IHandleMessage<UnitNavigationEventMessage> { [RequiredField] public Transform target; protected override string OnInit(){ GameServices.messageBus.Subscribe(this); return null; } protected override void OnExecute(){ (agent as IMovable).MoveTo(target.position, false); } public void Handle(UnitNavigationEventMessage message){ switch(message.eventCode){ case UnitNavigationEventMessage.Event.DestinationReached: { EndAction(true); break; } case UnitNavigationEventMessage.Event.StoppedDestinationBlocked: { EndAction(false); break; } } } } } |
As for the errors you are getting:
1. As the error says, you are declaring blackboard which already exists (it’s inherited from Task). You can use the inherited blackboard directly without the need to declare a new one unless the blackboard you want to use is not the agent’s one, in which case you should give it another name.
2. Well the second is also simple. You need to implement the interface member 🙂
The _MonoManager issue has been fixed in the new version. Sorry about that.
Let me know if it works for you.
Cheers
Join us on Discord: https://discord.gg/97q2Rjh
Hei,
works perfect now, no problem to implement the IHandleMessage, thanks!
I’m currently struggling to initiate correct a coroutine for checkin with Physics.OverlapSphere at the same time.
But using an FSM to drive both patrolling and checking parallel might be the better way, what do the experts say to this question?
Using an FSM to parallelize (what a word 😉 such small tasks or implement coroutines in one big task itself? And is this only a question of the visualization via FSM-Editor or do performance aspects play a major role here?
I simply don’t have enough c# experience to evaluate these strategies and I’m glad about some advice at this point.
I will keep you up to date with next progress (and retrograde steps 😉 ) in this Apex-AI project..
Hey again,
I would always strongly advice in greating big self-containable tasks that are specific to the game you are making. That way they can be reused throuout the game easily, instead of trying each time to “hack” around a specific behaviour out of smaller tasks.
This is practicaly the reason why I haven’t included hundreds of tiny tasks like for example Vector3.Angle or Max etc. I really think that in a real project creating behaviour out of such tiny tasks is more of a pain than a gain, instead of writing specific tasks FOR the game.
I hope this helps 🙂
Sure, let us know how it goes 😉
Join us on Discord: https://discord.gg/97q2Rjh