News › Forums › RAIN › Sample Projects, How To, and Code › RAIN Actions
This topic contains 9 replies, has 5 voices, and was last updated by ninjapps 4 months, 3 weeks ago.
-
AuthorPosts
-
July 4, 2022 at 12:29 pm #30996
I have been developing a 2D game for some time, using RAIN for the AI and A* Pathfinding project for navigation.
In the name of good software development practice I have been developing reusable RAIN actions for use in
my BTs. I have decided to share some. First up is an action that allows you to call a method on a component attached to the body of an AI. I have found this extremely useful for simple tasks like playing effects and such as it allows you to perform a custom action without creating a new class.
I hope someone finds this useful.using UnityEngine; using System.Collections; using RAIN.Action; using RAIN.Core; using RAIN.Representation; using System.Reflection; using System; [RAINAction] public class CallMethod : RAINAction { public CallMethod() { actionName = "CallMethod"; } //The name of the component which has the method to call. This should be attached to the AI.Body gameObject. public Expression TargetComponent; //The name of the method to call. public Expression TargetMethod; //cache the method signature to avoid expensive reflection calls. private MethodInfo _methodInfo; private object _component; //cache the target names so that we can test if they change private string _previousTargetComponent = ""; private string _previousTargetMethod = ""; public override void Start(AI ai) { //test if target has changed bool targetComponentChanged = string.IsNullOrEmpty(_previousTargetComponent) || _previousTargetComponent != TargetComponent.ExpressionAsEntered; bool targetMethodChanged = string.IsNullOrEmpty(_previousTargetMethod) || _previousTargetMethod != TargetMethod.ExpressionAsEntered; if (targetComponentChanged || targetMethodChanged || _component == null || _methodInfo == null) { //get target component type Type componentType = Type.GetType(TargetComponent.ExpressionAsEntered); if (componentType != null) { //get the target method signature _methodInfo = componentType.GetMethod(TargetMethod.ExpressionAsEntered); //get the target component _component = ai.Body.gameObject.GetComponent(TargetComponent.ExpressionAsEntered); //update target names _previousTargetMethod = TargetMethod.ExpressionAsEntered; _previousTargetComponent = TargetComponent.ExpressionAsEntered; } } } public override RAINAction.ActionResult Execute(AI ai) { if (_methodInfo == null || _component == null) { Debug.LogError("RAINAction.CallMethod has failed: Cannot find method to call."); return ActionResult.FAILURE; } //invoke the methods _methodInfo.Invoke(_component, null); return ActionResult.SUCCESS; } }
Adam
July 7, 2022 at 10:07 am #31140Excellent! Just what I was looking for. Thanks!
August 19, 2022 at 1:27 pm #32911Hello.
I’m new to RAIN, and am trying to run a pretty standard .js script from within the behavior tree.
I assume this is what I need for that, but keep getting “method not found”. I have the name of the script in the TargetComponent field, and script’s function that I’m trying to call in the TargetMethod field. The script is a component of my character’s top-level gameObject.
Any suggestions?
Thanks.August 22, 2022 at 12:50 am #32963I’m a bit confused. what TargetComponent field are you referring to? and what TargetMethod field?
August 22, 2022 at 12:54 am #32964Oops. I guess I should have read the whole thread.
Hmm. Seems like a pretty inefficient approach - assuming that it is a bit uncommon to share code between your components and your AI. In most cases I would just grab the Component directly off the object and then call the method without resorting to reflection. Was that code built to handle many shared calls (like dozens?)
In most cases you will just want to create a Custom Action in RAIN through the behavior tree, then fill in the Start and Execute methods.
August 22, 2022 at 2:02 am #32974@gitoffame your approach seems correct, but the script wasnt tested with JS. I am at work at the moment but I will test when I get home and see if I can get it to work for JS
@prime, correct, reflection may not be the most efficient approach, but the script is not meant for heavy lifting. It is meant for simple one off calls that I don’t think warrant an entire custom action. Unity uses reflection extensively. All of the Monobehaviour methods (Awake, Update etc ) are called using reflection for example, and Unity’s messaging systems, which I though RAIN uses, also functions because of reflection. I dont think reflection it is such a major concern as long as you understand the implications of using it. Perhaps I should have mentioned something about these implications in the original post though so people are aware of them.
August 22, 2022 at 2:26 pm #32979@Adam fair enough. I tend to caution people on the forums because not everyone is a programmer, so not everyone will understand the implications of using reflection. For most people who aren’t power programmers, they’ll be better off just writing custom actions that find and cache the relevant component, then just call methods directly.
Also, we’ve considered adding a reflection layer ourselves that would allow you access to public methods, properties, and variables on your component scripts within behavior trees. If we get enough interest we’ll do it.
Thanks
August 27, 2022 at 10:48 am #33042Ah. I’ll admit, first off, that I’m just stumbling into all this. Unfortunately, I’m also pretty unfamiliar with C#. Maybe it’s time I learned a little…
What I’m trying to do is pretty basic; I have a couple sub-objects in my character object that I want to activate at the start of the attack animation and deactivate at the end of the animation. If I can pull that off, I think I’ll be pretty much set with what I need to accomplish for this project.
Thanks for your replies.August 27, 2022 at 2:46 pm #33043Many ways to do this:
1) Use Unity’s event system associated with animations. You can set events that are raised when the animation hits certain points in the anim curve, and then handle those in a component on your character object. None of that needs to be done through RAIN.
2) If you are managing the animations through RAIN and want to manage the activations as well, then just add a Custom Action to your behavior tree to run in parallel with the animation. It can activate your subobjects in the Start method and disable them in the Stop method.
February 19, 2022 at 10:06 am #35984 -
AuthorPosts
You must be logged in to reply to this topic.