[RELEASED] Easy Character Movement 2

Perhaps a video will communicate what I am seeing more clearly and whether this comes down to user or configuration error and / or is expected behaviour:

Once I start the platform moving (by adding an initial force), there is a period of time where upon landing, the player slides a bit. Is this intended? Thanks!

Is your rolling animation root motion-based? If not, and if youā€™re open to using root motion, you can simply enable the Use Root Motion property during the roll animation and disable it once the rolling ends. One advantage of root motion is that the animationā€™s velocity completely overrides the ā€˜proceduralā€™ velocity.

Alternatively (no root motion), in your input-related code (e.g., the Update method), you can check if the character is rolling and set its movement direction to a previously cached direction (e.g., cache the direction at the start of the roll) to maintain a consistent forward roll:

private void Update()
{
    // Regular input code here...

    // Overrides movement direction while rolling
    if (IsRolling())
    {
        SetMovementDirection(cachedRollingDirection);
    }
}

Another approach is to override the CalcDesiredVelocity method to return a rolling velocity (e.g., cachedRollingDirection * rollingSpeed) while rolling.

Actually, this is the method where root motion velocity typically overrides procedural velocity, so a similar approach can work here too.

1 Like

This is how the current implementation based on differential equations works in this case: to calculate the platformā€™s velocity, the difference in position (delta position) is divided by the elapsed time (delta time). This represents the average velocity between two frames, so at least one previous frame and the current one are needed to calculate these deltas.

This effect is more or less pronounced depending on the speed of the platform as well as the characterā€™s properties for ā€˜brakingā€™ or adjusting its velocity upon landing. Additionally, the cameraā€™s tracking speed, as mentioned before, also affects the perception of this effect.

For example, in the video you shared, youā€™re clearly using very high friction and/or deceleration (instant/hard stop) and possibly some camera lag.

In contrast, in the following video (using default character settings and no camera lag), the effect is less pronounced. This is also observable in included examples like planet walk, etc.

For further clarity, if you push one of the green cubes (physics platforms) and jump onto it, youā€™ll notice the effect is almost imperceptible compared to when using high deceleration and friction values (as seen in your test video). This is why, in games where action takes place on moving platforms (e.g., Super Smash Brothers), itā€™s common to ā€˜hookā€™ the character to the platform so they maintain their speed even when not in direct contact with it or to use alternative implementations that may require custom coding (e.g., KCC).

That said, as part of an upcoming update currently in development, I plan to conduct additional tests and explore alternative implementations in case any unforeseen issues exist.

1 Like

Fantastic, thank you so much! I went with the root motion option, and it works really well! I do like how your default ā€œjumpā€ behaviour imparts some lateral control to the player, so I may look to extend my ā€œrollā€ function to do the same.

One other thing Iā€™ve been thinking about is my use of Animation Events to call the StopRolling() method. I really dislike Animation Events - they feel like a ā€œhackā€ and put a weird dependency on, and coupling of, Animation Clip / Animator and my Player Character component. Itā€™s also a pain when I want to swap out animation clips.

Do you have any opinion on Animation Events, from a ā€œbest practiceā€ perspective? I feel that the Player Character state model should ā€œknowā€ the player state - for example, when the player is rolling. It feels important when determining whether the character can transition to other states, for example. Iā€™m looking at adding other ā€œActionsā€, like picking up objects, attacking, interacting with doors etc, and I think Iā€™ll end up encountering this ā€œproblemā€ again in the future. If there are other, ā€œbetterā€ solutions to this, Iā€™d be really interested to hear.

One of my ā€œanalysis paralysisā€ problems in my GameDev journey has been around the fact that there are so many different ways to do one thing - I understand that thereā€™s often no ā€œbestā€ solution, and that consistency is key, but I also have a desire to write ā€œgoodā€ maintainable, extensible code, and sometimes experience is the only way to establish what good looks like. I really value your opinion in that respect!

Thatā€™s great; Iā€™m glad to hear the suggested solution worked well for you!

About your question:

While animation events are useful and have their purposes, for this and similar cases, you could use StateMachineBehaviour, which is ā€œtiedā€ to the animation state rather than the animation clip. This allows direct access to the character, enabling modifications as needed. For example, to implement a ā€œjump attackā€ using root motion:

public class RootMotionJump : StateMachineBehaviour
{
    // Cached Character
    private Character _character;

    public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // On RootMotionJump state enter...

        // Cache ECM2 Character
        if (_character == null)
            _character = animator.transform.root.GetComponent<Character>();

        // Set Flying movement mode to use root-motion vertical velocity
        _character.SetMovementMode(MovementMode.Flying);
    }

    public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // On RootMotionJump state exit...

        // Exit Flying movement mode.
        // It's perfectly fine to use Falling as our exit movement mode since it is automatically handled based on the character's ground status.
        _character.SetMovementMode(MovementMode.Falling);
    }
}

In this example, entering the animation state activates the flying movement mode; otherwise, the root motionā€™s vertical velocity would be discarded. Once the state is completed, it exits flying movement mode by setting MovementMode.Falling, which is automatically managed in response to grounding status, making it a great choice as an ā€œexitā€ state.

This same approach can be applied to different states that need to interact with the Character. By creating custom StateMachineBehaviour scripts, you can modularize specific behaviors, such as attacking, rolling, or any other custom movement, in a way thatā€™s both flexible and easy to manage.

1 Like

Brilliant, thanks again! This works great. Iā€™ve also used the same technique to add audio to the animation states. Great stuff!

My Third Person controller is looking and feeling really good. Iā€™ve just started on an NPC class, using your NavMeshCharacter component, inheriting from my Character enhancements, reusing my CharacterAnimator and animation controller without any changes. It all just works.

Iā€™m delighted with EMC2 and your help - thank you again!

1 Like

Thatā€™s great, thanks for the update and kind comments! Iā€™m glad to hear everythingā€™s working well for you. If you have any more questions, feel free to reach out. Happy coding!

Iā€™m really sorry to keep bothering you - Iā€™m enjoying getting stuck in to ECM2! I have switched my Character to root motion, setting useRootMotion to true in the inspector, and adding a RootMotionController component.

Iā€™ve added code into my Character component to subscribe to the MovementModeChanged base class event, and in that Iā€™m setting useRootMotion to IsWalking(). So the moment the player jumps and switches to ā€˜Flyingā€™ mode, root motion should be toggled off and the jump fully controlled outside of root motion.

This kind of works, but when I press jump the result is inconsistent: The character jumps, but with what feels like only a small amount of forward velocity. But every 4th or 5th jump, I suddenly get a lot of forward motion and the character jumps much further forward.

Iā€™ve made a short video that hopefully demonstrates what Iā€™m talking about: https://youtu.be/pbinCJp43pA

If I turn off Root Motion altogether, the jump works as expected.

Any idea whatā€™s causing this?

Hi! No worries :slight_smile:

Regarding your issue:

I believe this could be related to animation velocity. When using root motion, the animation velocity is applied directly, without any modifications, filters, or clamping. This ā€œrawā€ velocity is then adjusted when root motion is disabled. For example, if the velocity exceeds the max speed, the CalcVelocity method will apply ā€œbraking,ā€ forcing it to adhere to the max speed.

I recommend using the CalcDesiredVelocity method to visualize the animation velocity (try drawing a ray) so you can better understand what might be causing the issue. Additionally, you could try the included toggle root motion example to compare results.

2 Likes

Awesome, thanks again! I think it might actually to have been to do with the geometry in the scene and / or some weird collider thing. I seem to have fixed it, not quite sure how. But that works for me!

Iā€™ve been messing with the new Behavior package in Unity 6. Your movement, controller and navmesh components are so well designed, I just drop them onto a character model, hook them up to behavior actions, and Iā€™ve got highly configurable animal, creature and human AIs wandering around my scene! Iā€™ve said it before and Iā€™ll say it again, ECM2 is just brilliant, thank you again!

Hi @mroshaw

Thank you for the update! Iā€™m glad to hear you were able to resolve the issue, and I sincerely appreciate your kind comments regarding ECM2!

Let me know if I can be of any assistance.

Hello! I use SetMovementDirection and maxFlySpeed to move my jetpack character in the air. How can i implement a dodge roll 5 meters in the left and right direction smoothly? What is the best way for that? Thanks.

Hello!

Is there a new exemple of the more robust manger? I canā€™t seem to find it as of ECM2 1.4.2

Kindest Regards

Hi @Xwad

The simplest approach is to apply an impulse to your character in the desired direction. This can be achieved using the AddForce or LaunchCharacter function.

Another commonly used method is leveraging root motion. However, this requires your animations to support root motion for it to work effectively.

For a more advanced and robust Dash implementation, refer to the Walkthrough 4.3 example. This demonstrates how to create a custom movement mode specifically for executing a dash.

Hi @Rumpelito ,

The Unity 6 version includes two different examples for handling character input with Input System. One demonstrates managing custom actions in a way similar to the 1.3.x versions, which is used in most of the included examples and demos, ie (ThirdPersonInput, CharacterInput, etc)

An additional example showcases how to control a character (first or third person) using the PlayerInput component. These are covered in the Walkthrough - Controlling a Character section.

While both approaches are similar, each offers unique advantages depending on your project needs.

Hey Krull,
Not sure if Iā€™m being dumb but I canā€™t seem to import the Unity 6 version. Iā€™ve started a fresh project, imported ECM through the package manager, but it seems to be the Unity 2021+ version, as it uses the old Cinemachine namespace etc. Any help is appreciated.

Also thank you very much for the continued updates on this amazing asset.

Ow sorry, I didnā€™t specify enough.
What I meant by manager, was a manager for a lot of AI agents, like 100 or 200 for instance.

Kindest Regards

Hi @ProjectBrainworm,

Thank you for your kind comments!

About your issue:

Another user reported this issue, and it appears to be related to Unity serving an older version of the package.

Itā€™s worth noting that the Unity 6 version of the package was uploaded using the latest available Unity 6 release at the time, version 6000.0.26f1. As a result, using a Unity version older than this might default to downloading a 2021+ version of the package.

I recommend updating to the latest Unity 6 version and forcing a re-download of the package within Unity 6. If the package was previously downloaded with an older Unity version, it will likely default to the 2021+ version.

In the meantime, if the issue persists, please contact me through the support email (please include your invoice number). Iā€™ll be happy to provide the Unity 6 version directly.

Hi @Rumpelito,

Thanks for clarification.

ECM2 does not include an AI ā€˜managerā€™ since this functionality is highly specific to each game.

By default, a Character uses an ā€˜auto-simulationā€™ feature implemented via a LateFixedUpdate coroutine. For scenarios requiring a large number of characters, it is recommended to disable this auto-simulation by setting enableAutoSimulation to false. You can then manage character updates manually by calling the Simulate method within your Manager.

This approach works well when combined with the NavMeshCharacter component, which enhances a standard Character with navigation capabilities using Unityā€™s NavMesh and NavMeshAgents.

Thank you Krull, I downloaded the latest version of Unity 6 and it solved the issue, I didnā€™t realise I was still using 6000.0.25f1 so it was my mistake.

1 Like