News Forums RAIN General Discussion and Troubleshooting Setting up custom motors for motion

This topic contains 21 replies, has 4 voices, and was last updated by  bblanque 1 month, 3 weeks ago.

Viewing 15 posts - 1 through 15 (of 22 total)
  • Author
    Posts
  • #5099

    DrKillinger
    Participant

    Hi guys

    I was wondering if it’s possible to set up a custom motor script in Rain? I’m busy checking Rain out to see if my current project will work well. I love what I see so far, but I have a set of very specific motor scripts for various types of vehicles (tanks, hovercraft, etc) with their own acceleration and turning behaviours.

    In short, is it possible to port my code as a motion in Rain, and if so, can someone perhaps point me in the right direction in the API to get a handle on doing so?

    Thanks!

    Edit: It struck me that I might just use a custom script to replace “move”. Would this be preferable?

    Edit2: Never mind. All was answered after diving through the API a bit. I might be back later for guidance, but so far things seem great.

    • This topic was modified 1 year, 8 months ago by  DrKillinger. Reason: Symantics
    • This topic was modified 1 year, 8 months ago by  DrKillinger.
    • This topic was modified 1 year, 8 months ago by  DrKillinger.
    #5107

    prime
    Keymaster

    Yes, you can absolutely set up a Custom Motor. You can start by overriding BasicMotor and just modifying the Move and Face methods. Here are some things to keep in mind:

    The job of the Motor is to
    a) Grab the current state of the Body in UpdateMotionTransforms. This usually equates to copying Transform data in the the AI Kinematic
    b) Modify the AI Kinematic state based on Move and Face. Do this however you want. The BasicMotor uses instantaneous velocities calculated from trying to follow paths generated by the Navigator. These velocities are set into the Kinematic.
    c) Apply Kinematic changes back to the Body in ApplyMotionTransforms. This usually equates to calling Kinematic.UpdateTransformData and then copying Kinematic position and rotation back into the Body transform.

    Here’s how that looks in BasicMotor

    /// <summary>
            /// UpdateMotionTransforms updates the AI Kinematic structure with the current
            /// values associated with the AI Body.
            /// </summary>
            public override void UpdateMotionTransforms()
            {
                _ai.Kinematic.Position = _ai.Body.transform.position;
                _ai.Kinematic.Orientation = _ai.Body.transform.rotation.eulerAngles;
                _ai.Kinematic.ResetVelocities();
            }
            /// <summary>
            /// ApplyMotionTransforms applies physical forces back to the AI Body
            /// </summary>
            public override void ApplyMotionTransforms()
            {
                _ai.Kinematic.UpdateTransformData(_ai.DeltaTime);
                _ai.Body.transform.position = _ai.Kinematic.Position;
                _ai.Body.transform.rotation = Quaternion.Euler(_ai.Kinematic.Orientation);
            }
    #5118

    DrKillinger
    Participant

    Thanks so much Prime! I actually found my embarrassing mistake last night and got the custom motor into Rain. Right now, I’m just looking at how I’m supposed to manipulate the parent transform to move and rotate.

    is _ai.Body the parent GameObject?

    #5119

    prime
    Keymaster

    Yes, _ai.Body (or AI.Body) is the game object the AI should be moving.

    #5120

    DrKillinger
    Participant

    Well bugger me, it works! Refactoring my tracked and wheeled vehicle code now, thanks for the help!

    #5121

    DrKillinger
    Participant

    In terms of BasicMotor, is Face() called from within Move()? I see the API describes Move() as having many operations, including “…turning to face the target, etc.”.

    #5130

    prime
    Keymaster

    Face is not called from within Move, but it is called by the Behavior Tree Move node. By default, if no separate Facing target is set, the BasicMotor will try to turn the Character to face forward while moving.

    #5134

    DrKillinger
    Participant

    Ok, I ask because if I override the Move() function, Face() seems to not work anymore.

    Looking through Kinematic, should I manipulate Position directly to move as I’d like? Here’s some testing code, and when I use it I lose Face functionality:

    public override bool Move()
    {
    	_ai.Kinematic.Position += (_ai.Kinematic.Forward*2*Time.deltaTime);	
    	return false;
    }

    Why would this cause Face() to not try and face the target anymore? (I’m inheriting from BasicMotor, by the way). Sorry if I haven’t understood.

    While I’m at it, does Rain have a quick way of determining degrees to face a target, so that I can implement something similar to the Default Face Before Move Angle? I have a function for determining this, but maybe Rain has something to make my code a bit more concise.

    • This reply was modified 1 year, 8 months ago by  DrKillinger.
    #5141

    prime
    Keymaster

    Your code will have no impact on Face(). However, it is best not to change Kinematic.Position directly. That’s because other functions, including Face, use Kinematic.Position as part of their own calculations. Those methods should be able to assume that Kinematic.Position represents the current AI position, not the one you want in the future.

    That’s why you should do something more like

    _ai.Kinematic.Velocity = _ai.Kinematic.Forward * 2f * _ai.DeltaTime;

    and then call UpdateTransformData in ApplyMotionTransforms as in the code I posted. I also recommend you use AI.DeltaTime instead of Time.deltaTime.

    Take a look at the SimpleSteering class and Utility.MathUtils for helper functions.

    #5144

    DrKillinger
    Participant

    Maybe I’m being thick, but if I only override Move() and make it always move forward, it should still be turning to face my moveTarget, while always moving in a forward direction:

    public class CustomMotor : BasicMotor
    {
    	public override bool Move()
    	{
    		_ai.Kinematic.Velocity = _ai.Kinematic.Forward * defaultSpeed * _ai.DeltaTime;
    		return false;
    	}
    }

    But when I do this, it only moves forward. No steering or pathfinding occurs. Any idea as to why this would happen? Sorry for bothering you.

    • This reply was modified 1 year, 8 months ago by  DrKillinger.
    • This reply was modified 1 year, 8 months ago by  DrKillinger.
    #5151

    prime
    Keymaster

    That example isn’t meant to be your complete solution. You also need to decide how you are going to deal with turning.

    If this is a vehicle solution, then forward (or reverse) velocity is all you get. Next, add rotation to the solution based on the turn rate of your vehicle. This would be a change to _ai.Kinematic.Orientation. Just adjust the Y rotation +/- some degrees. On subsequent frames the forward velocity will be in a new direction and turning can occur.

    Here’s an example of simple movement (non vehicle)

    public override bool Move()
            {
                if (IsAt(moveTarget))
                    return true;
                _ai.Navigator.pathTarget = moveTarget;
                MoveLookTarget target = _ai.Navigator.GetNextPathWaypoint(Allow3DMovement);
                SimpleSteering.DoDirectMovement(_ai, target.Value, CloseEnoughDistance, CloseEnoughAngle, FaceBeforeMoveAngle, Allow3DMovement, Allow3DRotation);
                return false;
            }
    #5164

    DrKillinger
    Participant

    Oooooooooh… I thought Face() dealt with the turning side of things. Everything’s working now. Thanks for the effort, I really appreciate it.

    #5177

    DrKillinger
    Participant

    If you’re still checking this thread, I have a public function in my motor that returns whether the AI is walking or running, but not sure how to access it from another script. Any advice?

    #5213

    prime
    Keymaster

    The motor is always accessible from AI.Motor. If is is your custom motor, it would be something like:

    MyMotor tMotor = AI.Motor as MyMotor;
    bool walking = tMotor.IsWalking;

    If you are running in code that doesn’t have access to the AI directly, then you’ll need something like:

    AIRig tRig = gameObject.GetComponent<AIRig>();
    MyMotor tMotor = tRig.AI.Motor as MyMotor;
    #5214

    prime
    Keymaster

    Face() does deal with the turning side of things if you have a separate faceTarget set on the motor. However, the BasicMotor automatically tries to turn the AI toward the forward direction during the Move call.

Viewing 15 posts - 1 through 15 (of 22 total)

You must be logged in to reply to this topic.