Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

[RELEASED] Easy Character Movement 2

Discussion in 'Assets and Asset Store' started by Krull, May 5, 2021.

  1. unitydevv

    unitydevv

    Joined:
    Aug 14, 2016
    Posts:
    11
    Hi @Krull
    I want to ask a solution for an issue which i am having with ecm2 character controller . So basically in the character movement script , i have set the collision layers to not collide with my "enemyweapons" layers. while testing in a cube the character is able to pass through the cube with "enemyweapons" layer which is working as expected but i have a script in the cube with OnCollisionEnter method and that method is detecting the controller which should not happen .even though i have disabled the collisions even from Project settings-> Physics option as well

    Can you tell me why the cube is detecting the controller ?
     
  2. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @unitydevv

    A Character can collide against another if its capsule can collide with the other object, this is the physical collision between the character's rigidbody collider (its capsule) and the other non-kinematic rigidbody collider.

    The CharacterMovement collision layers, basically defines the collisions handled by the CM algorithm (ie: during its Move method call), separated from the unity's collisions.

    The unity collision could be caused by 'others' being non-kinematic rigidbodies and / or due the Physics Contact Generation setting, enabling kinematic rigidbodies contacts.

    Additionally, if needed you can use the Character IgnoreCollision method to ignore specific collider(s) or rigid bodies and the CapsuleIgnoreCollision method, this will disable 'physical' collision between the character's capsule and the given collider, just like the Physics.IgnoreCollision method
     
  3. unitydevv

    unitydevv

    Joined:
    Aug 14, 2016
    Posts:
    11
    Hi @Krull
    I cant use ignore collision , as there will be many colliders which has “enemyweapons” layer and some will spawn at runtime as well , what i need is to ignore collision for a particular layer.
    Basically i have separate colliders inside the character to detect hit from enemies but the enemy weapon is only detecting the character controller collider and not detecting the hit collider inside it.
     
  4. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    You can achieve the same result using the layer matrix, just make sure your character's layer doesn't collide with your 'other' object(s) or in your collision script check if 'other' is player tag and ignore it.


    Mmm, could these colliders be causing the OnCollision method call? make sure those don't collide with character (as above) or even better mark them as triggers and use OnTriggerXXX if possible.
     
  5. unitydevv

    unitydevv

    Joined:
    Aug 14, 2016
    Posts:
    11
    @Krull The collision script is on enemy weapon object , and when the weapon hit the character its only detecting the character controller collider and not detecting inside collider at all.
     
  6. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    @unitydevv ,

    As commented, Unity could detect collisions against a character based on plain unity collisions if their layers collide (physics collision matrix), worth note, unity will only call OnCollisionXXX methods if one of the colliders also has a non-kinematic rigidbody.

    So in your case if you are getting an enemy weapon vs character collision this must be due to their layers (layer matrix) set to collide.

    The CharacterMovement collision layers are independent of unity collisions, this basically defines the objects a character can collide when moving, as being a kinematic rigidbody unity won't handle collision or collisions response.
     
  7. CaffeinatedCoolaid

    CaffeinatedCoolaid

    Joined:
    May 10, 2021
    Posts:
    59
    I think there could be some refactoring for the design of Character.
    Almost all of the boiler plate methods and fields could easily be turned to an interface with default methods
    and an extension class to call them. The benefits of this would be that you could easily create more modular code that you know would work controllers extending from the base class or even a completely custom one as well as speed up custom controller implementation.

    Example implementation:
    Code (CSharp):
    1. public interface ICharacter
    2. {
    3.     internal CharacterMovement characterMovement { get; }
    4.  
    5.     public Vector3 GetUpVector() => characterMovement.transform.up;
    6.  
    7.     public void SetVelocity(Vector3 velocity) => characterMovement.velocity = velocity;
    8.  
    9.     public void AddForce(Vector3 force, ForceMode forceMode = ForceMode.Force) =>
    10.         characterMovement.AddForce(force, forceMode);
    11.  
    12. }
    13.  
    14. public static class CharacterExtension
    15. {
    16.     public static Vector3 GetUpVector<T>(this T character) where T : ICharacter
    17.         => character.GetUpVector();
    18.  
    19.     public static void SetVelocity<T>(this T character, Vector3 velocity) where T : ICharacter
    20.         => character.SetVelocity(velocity);
    21.  
    22.     public static void AddForce<T>(this T character, Vector3 force, ForceMode forceMode = ForceMode.Force)
    23.         where T : ICharacter
    24.         => character.AddForce(force, forceMode);
    25.  
    26. }
    27.  
    28. public class ExampleCharacter : MonoBehaviour, ICharacter
    29. {
    30.     private CharacterMovement _characterMovement;
    31.  
    32.     protected CharacterMovement characterMovement
    33.     {
    34.         get
    35.         {
    36. #if UNITY_EDITOR
    37.             if (_characterMovement == null)
    38.                 _characterMovement = GetComponent<CharacterMovement>();
    39. #endif
    40.  
    41.             return _characterMovement;
    42.         }
    43.     }
    44.  
    45.     CharacterMovement ICharacter.characterMovement => characterMovement;
    46.  
    47.     public virtual Vector3 GetUpVector()
    48.     {
    49.         return Camera.main.transform.up;
    50.     }
    51. }
    Another added benefit is that this would not break any existing project code for users extending from one of the Character base classes.
     
  8. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776

    Hi,

    Thank you for sharing your thoughts with us.

    While I see your point, this is basically a interface vs base class (composition vs inheritance, etc) discussions, each has its pros and cons and some users would prefer one over other.

    From my perspective this is a 'is-a' relationship I mean your player (ie: Link, Marion, etc.) 'is-a' Character so extending a base Character class make sense, so you can reuse its default functionality, extend it or override it as your game needs. It has been designed that way, to reuse Character default functionality (reuse logic) but with the ability to extend it or override it as your game needs.

    For example, one common pattern I usually follow and suggest is override the GetMaxSpeed, GetMaxAcceleration, etc. methods, so you return the value based on your character's current logical state; override the CalcVelocity method to use a different friction model, etc. In this cases reusing and extending the Character default functionality.

    Well, this also applies to inheritance, since your custom character is completely separate from the core Character class.

    Regards,
    Oscar
     
  9. Filein

    Filein

    Joined:
    Oct 23, 2014
    Posts:
    7

    @Krull
    Hello. I'm currently testing using ECM2 and InputSystem for my project. Specifically, when running my project on mobile, I've noticed that the FPS is low and the camera behaves unexpectedly by jumping. As a test, I increased the Timescale in the editor to around 20 and encountered similar issues. The attached video is from the default sample, with a wider floor to accommodate the Timescale test. I haven't made any other changes. I would like to understand the cause of this phenomenon. My assumption is that there may be a discrepancy between Cinemachine's update and simulation. Could you please provide some insights?
     
  10. Dooprod

    Dooprod

    Joined:
    Aug 17, 2014
    Posts:
    1
    Hello!

    If you use Cinemachine FreeLook (and you should!)
    if I were you, I would check the parameter "Blending Mode" of this camera.

    Currently, I assume you are using one of these 3 values:
    - Lock to target with world up
    - Lock to target no roll
    - Lock to target

    If that is the case, you should choose:
    - World space
    - Simple follow with world up


    I you use the default Cinemachine Virtual Camera (CM 3rd Person Camera),
    check all values of the Character Look component, on the ECM_Character.

    Did you make changes in the template or maybe in the project itself? Can you share more information on what you see and what you want? Also do not hesitate to share your configuration (unity version, packages...) I just created a brand new project and imported ECM into it. When I press play, everything works by default...



    By the way I recommend you to use Cinemachine FreeLook for a third person game! It's a very complete camera which will have more option for this kind of game! You can adjust transition, axis recentering, orbits with spline curvature... Fully compatible with the new input system (add Cinemachine Input Provider component)
    It's easy to setup - so there is no reason not to try it!



    For the "low FPS" part, it's not easy to understand what is happening without informations... I have been using ECM for several years (2018, first version) on very different configurations and I never noticed the slightest impact on the performance, even with 20 characters walking around... It's very optimized!

    So I just did a quick test on several devices with the same scene:
    - (low-end) iPhone 7 : OK
    - (middle-end) Samsung Galaxy Tab A8 : OK
    - (high-end) iPad Pro 5th Generation : OK
    - (high-end) iPad Pro 6th Generation : OK
    - (vr middle-end) Oculus Quest 2 : OK

    Just to push a little bit, I took a scene template from a Synty Studio Pack (Space SciFi...), I took one of their character, and I put the whole thing in multiplayer via Photon. So one player is on PC (Windows), and the other one on the Samsung Galaxy Tab A8... The result :



    (what you see is on the Samsung Galaxy Tab)
    It's not even optimize (shadow, mesh combining, baked light...)!

    We need to find what is wrong with your config...
    So give us more information about your game,
    and do not hesitate to redo the tests starting from a new project.

    Keep us posted on your progress ;-)
    @++
    Y.
     
    Filein and Krull like this.
  11. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Dooprod ,

    Thank you very much for your help regarding this topic, I sincerely appreciate it!

    Actually I talked with @Filein regarding this issue by email, and the strange camera behaviour was caused by Cinemaching using a smart update, changing it to a late update solved it.

    Regarding the low fps, I agree with you it's hard to say without further details, probably some frames lock? or due the shader error (magenta cube on video).

    kind regards,
    Krull
     
  12. Asarge

    Asarge

    Joined:
    Jun 2, 2018
    Posts:
    26
    Hi Krull,

    I'm having trouble recreating/accessing the StepUp function to achieve the desired vault effect. I've tried a few dozen attempts with various detection/movement and some have gotten close but each have their own problems. This attempt was close but I think has some colliding issues during the MoveTowards,
    https://pastebin.com/yvDciaBZ

    I also tried going off the OnCollided function for detection and using that for the top of the objects height,
    if(collisionResult.hitLocation == HitLocation.Sides)
    topOfVaultObject = collisionResult.collider.bounds.center + Vector3.up * collisionResult.collider.bounds.extents.y;

    The detection seems to go more smoothly but transitioning the player over is the hard part as I'm unsure if the collider is conflicting with how ECM2 solves it as I can't follow the solving functions too well. If you could elaborate on a more specific example to move the character up and over once the detection condition goes through it would be much appreciated.
     
  13. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Asarge

    Well, in general (not only for ECM2) when performing a vault mechanic, is detect if a character is able to reach the target destination and if so, move the character, typically by root motion playing the vault animation; here since you already resolved the collision, you can even disable the character collision during animation, and enable when vaulted (if needed).

    The typical vault mechanics (as previously commented) is 'looking-ahead' simulating the character's movement, starting from your position, check if character can move up (up to your max vault height), then from this virtual new position (up) check forward up to a maximum desired distance (typically the vault animation distance), and last from this new virtual position (vaulted position), check down to detect if the character will end in walkable ground. If all this succeeds, do vault.

    I recommend using the CharacterMovement MovementSweepTests and FindGround to simulate the vault movement checks (up, forward, down), as these are the same function used internally by CM and will ensure proper simulation continuity.

    I suggest you take a look at this video, it's for an unreal engine, however it describes in detail the steps to perform the vault mechanics in greater detail and definitely should help you get a clear overview of it.
     
    RogDolos and Asarge like this.
  14. Poly_Games

    Poly_Games

    Joined:
    Apr 23, 2018
    Posts:
    3
    Hello @Krull,
    is a server-authoritative movement solution for Netcode for game objects planned or in the works?
    If yes do you have an approximate date, when it will release?
     
  15. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776

    Hi @Poly_Games,

    Unfortunately no at the moment, since the offered networking integrations are based on what the networking libraries offer, so it depends if NetCode releases support for it.
     
  16. ptm_oo

    ptm_oo

    Joined:
    Oct 30, 2014
    Posts:
    35
    Hi @Krull !

    I was wondering if there could be more optimized way to write this part of code:
    ice_screenshot_20230706-140713.png
    Array.Sort() allocates a lot of memory when using many Character controllers. Please let me know if I'm mistaken.

    Also, Do you have any advise how to use many Characters in sufficient way? Like, is there a way to reduce update time (eg. for object outside the screen) or something else that could potentially help to run smoothly like 400 of Characters. I understand if that's impossible, there are a lot of Physics Casts there.
    Thanks
     
  17. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @ptm_oo,

    Thank you for reporting this, yes I was able to reproduce it, so a solution would be to replace the Array.Sort method by an alternative method, possibly a custom solution implementing a truly zero allocations method.

    I'll evaluate some alternatives to replace it as part of the following ECM2 update.

    Well the benchmark scene is able to simulate about 1000 characters at high rates, as you can see here.

    A few ideas, for example if your game is mostly over flat surface, you can disable ground check for your enemies, and implement a custom movement mode where you do not need ground status to move or do a very basic ground check like you would do with normal CC.

    Another option is implement a manager, and instead each character have its own move co-routine (LateUpdateMethod disabled), you updateall your managed characters in a single update coroutine, similar to what the included benchmark does.

    Additionally you can lower the character's update rate based on some heuristics, like distance to character, if it's visible or not, etc. After all, by default the character's LateUpdate method is just a coroutine using WaitFixedUpdate so it is executed after internal physics update, something only really needed, if you are using heavy physics interactions.

    Lastly and following the manager method, is to implement a custom update loop, so you can simply skip (do not update at all) characters further than character's or not visible. You can take a look at the custom simulation examples for a working example of a manager using a custom simulation loop to update the characters.

    Let me know if you have any further questions.
     
  18. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    I was able to do additional tests, and the allocations caused by the Array.Sort actually are related to the IComparer, however in my tests replacing it with a Comparison delegate seems to perform worse than the IComparer even with the allocations.

    To completely remove the allocations, I implemented a custom in-place sorter (quick sort):
    Code (csharp):
    1. static void Sort(RaycastHit[] array, int leftIndex, int rightIndex)
    2. {
    3.     float pivot = array[leftIndex].distance;
    4.  
    5.     int i = leftIndex;
    6.     int j = rightIndex;
    7.  
    8.     while (i <= j)
    9.     {
    10.         while (array[i].distance < pivot)
    11.         {
    12.             i++;
    13.         }
    14.  
    15.         while (array[j].distance > pivot)
    16.         {
    17.             j--;
    18.         }
    19.         if (i <= j)
    20.         {
    21.             RaycastHit temp = array[i];
    22.             array[i] = array[j];
    23.             array[j] = temp;
    24.             i++;
    25.             j--;
    26.         }
    27.     }
    28.  
    29.     if (leftIndex < j)
    30.         Sort(array, leftIndex, j);
    31.  
    32.     if (i < rightIndex)
    33.         Sort(array, i, rightIndex);
    34. }
    To use it, simply replace the Array.Sort method call with:
    Code (csharp):
    1. Sort(_hits, 0, rawHitCount - 1);

    However, worth noting I have not performed a complete benchmark analysis but looks promising and definitely should help you.
     
    Last edited: Jul 11, 2023
    Dooprod likes this.
  19. MichelVictor

    MichelVictor

    Joined:
    Apr 15, 2018
    Posts:
    8
    If I put 2 characters at same time in the Scene, both move perfectly, when I disable one of them, the other stop moving, why this happens?

    If I remove DeinitPlayerInput() from OnDisable, this stops to happens, really weird the fact that if I disable another character the Deinit works for all characters in the scene.
     
    Last edited: Jul 21, 2023
  20. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @MichelVictor,

    Yes, this happens when both characters share the same InputActions assets, so when a character is disabled, it 'invalidates' the asset input actions causing the other to stop moving since its using the same asset.

    This can be solved by making each Character use its own InputActions Asset so they don't share it. Another option is to make use of the Unity PlayerInput component and PlayerInputManager to handle local multiplayer.

    Let me know if I can be of further assistance.
     
  21. Pacana

    Pacana

    Joined:
    Nov 24, 2014
    Posts:
    12
    Hello!

    I just started using this asset today and I'm using it in conjunction with Fish-Networking. Everything is going super well since I was following along with the Fish-Net Server Authorization example. The only problem that I seem to be having is that my Cinemachine camera (Dolly Track) makes it look like the character is jittering like crazy. I set the Cinemachine camera to update in LateUpdate, but it still happens.

    I'm not sure the proper way to approach this.
     
  22. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Pacana,

    First of all, thank you for choosing ECM2!

    About your issue:

    Mmm, I think this could be due to how Fish-Net handles interpolation, it smooths the visuals (ie: your character's model), while the Character is moved at simulation timestep, however by default the Camera follow target is parented to the Character which is not interpolated causing the jittery.

    The solution is to make the 'Camera Follow GameObject' child of your Character's model so it correctly follows the smoothed visuals.
     
  23. Pacana

    Pacana

    Joined:
    Nov 24, 2014
    Posts:
    12
    So my character is setup like:
    Character (NetworkObject)
    ModelRoot
    Geometry
    The Cinemachine camera has a target group, and when the player loads in I register the Character object as a member of the target group. I've also tried registering the ModelRoot and Geometry to be the targets instead.

    On the Character prefab that gets loaded in when the client starts, there is a PredictedObject (Fish-Net) component. The Graphical Object is set to be the ModelRoot transform, while the Network Transform is set to be the Character (NetworkObject) root.

    No matter what I set as the target, the jitter remains.

    Based on my setup, I think that I followed your advice. The jitter remains, however.

    This also might be more of a question for the Fish-Networking community.
     
  24. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Let me try to clarify my previous post:

    This is the default character-rig used in the included ECM2 Fish-Net example (Server-Authority):

    upload_2023-8-4_20-55-11.png

    and its corresponding PredictedObject configured to 'smooth' the character's model, in this case the ECM2_Capsule GameObject:

    upload_2023-8-4_20-56-1.png

    So my suggested solution, its make your CameraTarget GameObject (the one CM tracks) child of your Characters's model, ie:

    upload_2023-8-4_20-57-31.png

    This, due with the included Cinemachine Examples the CameraTarget is parented to the Character since its interpolation is handled by Unity which unlike Fish-Net it interpolates the Rigidbody not just its child model.

    If your issue persists, I suggest trying a basic scene with a camera using the SimpleCameraController tracking your CameraTarget so you can be sure it works, and later adding Cinemachine in order to better isolate the issue.

    Also, I definitely think the Fish-Net guys could help on this issue too
     

    Attached Files:

    Pacana likes this.
  25. BrunoHilt

    BrunoHilt

    Joined:
    Jan 4, 2022
    Posts:
    3
    Hi!

    Sorry if I missed an answer somewhere in this thread, but I was wondering whether there was a function or bool included that disabled all character movement and then enables it back whenever needed.

    My specific use case is a simple dialogue system where the player stops moving and needs to select a dialogue option. Currently I'm simply disabling the FirstPersonCharacter script whenever I enter dialogue, but this has the unintentional side effect of keeping player velocity going whenever the component is re-enabled.

    I'm also wondering whether or not this would constitute some sort of performance loss over an in-built function, but that might of course just be a very beginnerish fear with no real substance.

    As I said, the only real visible issue is the velocity thing, so if this is otherwise perfectly fine I'm content to keep using it. But of course I would love to hear if there's a better way.

    Thanks a lot!
     
  26. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @BrunoHilt,

    You can set the Character movement to None (ie: MovementMode.None) this will zero out its velocity stopping the character movement, the same can be done with rotation mode (RotationMode.None).

    It's okay not to issue at all, additionally you can set the character's velocity to zero or combine it with setting its rotation / movement mode to none, so the velocity is zeroed.
     
  27. troggg

    troggg

    Joined:
    Dec 29, 2017
    Posts:
    1
    Hi! I'm currently using this package in a simple 3d platformer, and I'm having trouble with providing a sort of "turning radius" for the player character. I'm trying to emulate a movement system similar to Super Mario 64, in which the faster the character is moving, the slower they are to change their direction in the direction the player is inputting, in order to simulate how a fast-moving object requires more force to change directions dependent on its velocity. I've tried poking around the
    CalcVelocity
    method, but my vector math is pretty weak, and I'm having a hard time achieving the desired effect. I was just wondering if anybody else who was using this package has tried to do something like this, thanks!
     
  28. Pacana

    Pacana

    Joined:
    Nov 24, 2014
    Posts:
    12
    Thanks for the help so far. I still haven't figured out exactly how to fix this, but I've noticed a few things. I think that the main problem is that the Cinemachine camera is not updating at the same rate as the visuals. This would mostly be a Fish-Net thing that I have to figure out, however.

    I noticed that as I increase the tick rate for the server, the smoother the camera becomes.

    My only question for you would be when in the Unity callback loop does the position of a character update?

    EDIT:
    So I fixed the problem... Even though my Cinemachine camera fixed to only have movement along the Z axis, the camera had a non-zero Dampen X value. I removed that dampen and all was good! I also had to remove the Dampen Z value and keep it set to 0, but that's not a big issue to deal with currently.

    Thank you for your help with the issue, even when the issue wound up having absolutely nothing to do with ECM2. I'm really enjoying how simple it has been to work with the tool!
     
    Last edited: Aug 7, 2023
    Krull likes this.
  29. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    How performant is this(pc)? Lets say 50 controllers, will any features like the ground detection be hard on performance?
     
  30. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @troggg

    While I have not tryied to reproduce it, you can use the CalcVelocity method (override it) to completely replace the default friction-based formula, for example:

    Code (csharp):
    1. /// <summary>
    2. /// Replace the character's friction model for Walkin movement mode, in this case using a basic lerp model.
    3. /// </summary>
    4.  
    5. protected override Vector3 CalcVelocity(Vector3 velocity, Vector3 desiredVelocity, float friction, bool isFluid = false)
    6. {
    7.     if (IsWalking())
    8.     {
    9.         // New 'physical' model using a simple lerp
    10.  
    11.         return Vector3.Lerp(velocity, desiredVelocity, 1.0f - Mathf.Exp(-friction * deltaTime));
    12.     }
    13.  
    14.     // Default physical model
    15.  
    16.     return base.CalcVelocity(velocity, desiredVelocity, friction, isFluid);
    17. }
    however by default the character will rotate towards its current movement direction, so in your case, you will need to modify it default behavior too (i.e: implementing a custom rotation mode), so you can adjust the rotation as your movement needs.

    Also, I think there is an article related to Mario 64 movement "Classic Super Mario 64 Third-Person Control and Animation" in the Game Programming Gems 2 book which could worth check it out too.
     
  31. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Pacana ,

    That's great, thank you for the update and happy to hear you could be able to solve your issue :)
     
  32. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    I think it should work fine. For example on my dev machine (i7 8700k gtx 1080, etc) on character movement synthetic benchmark test I got about +150 FPS for 1000 characters and ~68 FPS for 2k chars (image below), but obviously this is just chars, no animations, no agents etc.
     
  33. Pacana

    Pacana

    Joined:
    Nov 24, 2014
    Posts:
    12
    Unfortunately, once I got to the next phase of what I was working on, it's starting to seem like I wont have success with this asset when paired with Fish-Net and Client-Side Prediction (CSP). I was able to implement a simple test with a Kinematic rigidbody and was able to make it work perfectly with Fish-Net. After a few days of trying to get ECM2 to work with the CSP, I think I need to give up :(

    I'm trying to find someone on their Discord that had similar challenges. If anyone was able to overcome it and get it to work then I will make sure I post the update to that here in case anyone else has similar questions / problems.

    That being said, I really do love this asset, and it was so incredibly easy to implement in my initial, non-networked tests.
     
  34. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    Hi Krull, I bought the asset. Could you tell me the best ways to get every bit of performance possible out of it? To start off, it seems there is something that makes the character use way more resources when it is on a terrain, is there a way to tone that way down? I don't need good looks or perfect alignment to terrain.

    Video
     
    Last edited: Aug 10, 2023
  35. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Sorry to hear it : /

    mmm if you would like to share with me a minor example reproducing the issue, I could take a look at it.
     
  36. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Ah I see, please try profiling in a development build to completely remove any editor 'optimization' causing the issue.

    If this persists, I think this is could be due CM when on a terrain, it tries to read the Terrain interpolated normal (FindTerrainOpposingNormal method) and possible causing the lower performance.

    You can disable it modifying the CharacterMovement FindGeomOpposingNormal function (Line 1398), commenting the terrain section, so it uses the normal unmodified hit normal, as follows:

    Code (csharp):
    1.  
    2. /// <summary>
    3. /// Helper method to retrieve real surface normal, usually the most 'opposing' to sweep direction.
    4. /// </summary>
    5.  
    6. private Vector3 FindGeomOpposingNormal(Vector3 sweepDirDenorm, ref RaycastHit inHit)
    7. {
    8.     // SphereCollider or CapsuleCollider
    9.  
    10.     if (inHit.collider is SphereCollider _ || inHit.collider is CapsuleCollider _)
    11.     {
    12.         // We don't compute anything special, inHit.normal is the correct one.
    13.  
    14.         return inHit.normal;
    15.     }
    16.  
    17.     // BoxCollider
    18.  
    19.     if (inHit.collider is BoxCollider _)
    20.     {
    21.         return FindBoxOpposingNormal(sweepDirDenorm, ref inHit);
    22.     }
    23.  
    24.     // Non-Convex MeshCollider (MUST BE read / write enabled!)
    25.  
    26.     if (inHit.collider is MeshCollider nonConvexMeshCollider && !nonConvexMeshCollider.convex)
    27.     {
    28.         Mesh sharedMesh = nonConvexMeshCollider.sharedMesh;
    29.         if (sharedMesh && sharedMesh.isReadable)
    30.             return MeshUtility.FindMeshOpposingNormal(sharedMesh, ref inHit);
    31.  
    32.         // No read / write enabled, fallback to a raycast...
    33.  
    34.         return FindOpposingNormal(sweepDirDenorm, ref inHit);
    35.     }
    36.  
    37.     // Convex MeshCollider
    38.  
    39.     if (inHit.collider is MeshCollider convexMeshCollider && convexMeshCollider.convex)
    40.     {
    41.         // No data exposed by Unity to compute normal. Fallback to a raycast...
    42.  
    43.         return FindOpposingNormal(sweepDirDenorm, ref inHit);
    44.     }
    45.  
    46.     // MODIFICATION
    47.     // Terrain collider
    48.  
    49.     //if (inHit.collider is TerrainCollider)
    50.     //{
    51.     //    return FindTerrainOpposingNormal(ref inHit);
    52.     //}
    53.  
    54.     return inHit.normal;
    55. }
    56.  
     
  37. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    I made the modification and used the built game this time, that improved it, but I still see a huge loss in performance over terrains.

    Video from built game:
     
  38. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Yes, definitely something is happening not seen / reported before. Please Could you tell me what unity version are you using so I can further investigate the issue?

    Thanks!
     
  39. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    Unity 2022.3.7, URP
     
  40. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi,

    Thank you for your response.

    As commented before, I performed several tests and definitely concluded it's an issue with the included demo terrain (green one), probably due to its size / resolution, causing very bad performance on Unity's native functions like OverlapCapsule, CapsuleCast, etc.

    Additionally I recreated the same tests using the now free KCC, getting the same issues, very bad performance and the bottleneck is Unity's native functions on the same green terrain.

    As you can see in the below image, it is simulating 1000 characters on a new terrain (near real world size / scale) getting 50+ fps on a ~6 years old test machine.

    ECM2_Terrain_Performance_1000.png

    This additional test (package attached below) shows 100 player controlled characters in a new terrain showing correct ECM2 behavior, ~600 fps on a ~6 years old test machine.

    ECM2_Terrain_Performance_100.png

    Worth note, for these tests I implemented a very basic 'manager' responsible for simulating the whole characters instead of using the character auto-simulation (a co-routine). So I suggest following this manager approach for games where you need to control a huge amount of characters.

    You can find a more robust 'manager' implementation in the Custom Simulation example (Easy Character Movement 2\Examples\4.- Custom Simulation)
     

    Attached Files:

  41. Asarge

    Asarge

    Joined:
    Jun 2, 2018
    Posts:
    26
    Do you think it would be suitable to use ECM2 for enemies as well? I'm trying a more boid-like spherecast pathfinding that doesn't rely on navmesh or tags and having the ECM2 collision handling would work well with that. Is the agent character the closest example set up for enemies or do you have any example scripts set up for non-input entities?
     
  42. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    Great, thank you.
     
    Krull likes this.
  43. Minzie

    Minzie

    Joined:
    Jul 26, 2019
    Posts:
    77
    Hi @Krull
    1. How can I make the character to not be able to jump too frequent? I mean, currently my character able to jump again as soon as it lands. I want to have a wait time before it can jump again. I've already set all the jump properties to zero like below picture. But still it can directly jump after landed when I hit the space continuously.
    upload_2023-8-13_16-35-45.png

    2. Can I request to have "swim speed modifier" included in "Swim" portion just like there is "sprint speed modifier"? And this "swim speed modifier" is also included in GetMaxSpeed() calculation? This way it'll be easier to adjust the speed while swimming. Maybe you can also add to "flying" part as well if it's not too much of request :)
    upload_2023-8-13_16-40-10.png

    Thank you.
     
  44. Asarge

    Asarge

    Joined:
    Jun 2, 2018
    Posts:
    26
    You can utilize the OnJumped() and OnLanded() functions from ECM2 to achieve this
    Code (CSharp):
    1.     public float jumpCooldown = 1.0f;
    2.     private bool hasJumped = false;
    3.  
    4.     protected override void OnJumped()
    5.     {
    6.         base.OnJumped();
    7.  
    8.         // use this is you want the cooldown to trigger from jumps and not all landings
    9.         hasJumped = true;
    10.     }
    11.  
    12.     protected override void OnLanded()
    13.     {
    14.         base.OnLanded();
    15.  
    16.         if (hasJumped)
    17.         {
    18.             StartCoroutine(JumpCooldown());
    19.             hasJumped = false;
    20.         }
    21.     }
    22.  
    23.     private IEnumerator JumpCooldown()
    24.     {
    25.         // could change jumpCount here as well
    26.  
    27.         canEverJump = false;
    28.         yield return new WaitForSeconds(jumpCooldown);
    29.         canEverJump = true;
    30.     }
    Check the water volume inspector it should have properties for the friction and max fall speed which will change your speed in water.
     
    Minzie and Krull like this.
  45. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Asarge,

    Definitely, you can use ECM2 for Player Controlled character and enemies as well, for example in the above terrain scene, it shows 100 concurrent player controlled characters talking about ~1ms to 1.5ms (worst case), causing minimal impact on a game.

    The AgentCharacter basically extends a Character adding navigation capabilities using the NavMeshAgent desired velocity to drive the character.

    When using an AgentCharacter, the idea is to let your AI decide how the Agent should behave and use its MoveToLocation method to intelligently move around the world through a NavMesh.

    The only change for NPC is to disable its input management, so your AI takes control of it.
     
    Asarge likes this.
  46. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Hi @Minzie,

    The solution kindly provided by @Asarge (thanks!) is really nice and definitely should help you to achieve this behavior.

    The Jump Pre-Ground Time property basically lets you define how early (before landing) trigger a jump.

    While the Jump Post-Ground Time property basically defines the 'Coyote-Time' and lets you trigger a jump even if the character is not grounded but was during this specified time. This is mostly used in platformers to define how easy or how hard it is to perform an edge jump.


    Sure, Ill add this in the following update :)

    In the mean time you can use the friction approach suggested by @Asarge using a Physics Volume or in your custom controller, extend the GetMaxSpeed method (override it) to add a swimming case, pretty much like the sprint is handled.
     
    Minzie likes this.
  47. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    So this a question about CharacterMovement, mind you I'm not using Character, just CharacterMovement. I'm trying to use it only for gravity simulation and ground detection, its attached to a transform that is moved around through other means, it mostly works well but I'm seeing some sliding behavior sometimes as if they are walking on ice, any idea on how I could fix that?


    Code (CSharp):
    1.  
    2.         float maxSpeed = 1f;
    3.         float acceleration = 1f;
    4.         float deceleration = 1f;
    5.         float friction = 1f;
    6.         float brakingFriction = 1f;
    7.         Vector3 gravity = new Vector3(0, -9.81f, 0);
    8.         void PerformantGravityLogic()
    9.         {
    10.             characterMovement.SimpleMove(Vector3.zero, maxSpeed, acceleration, deceleration, friction, brakingFriction, gravity);
    11.         }
    I'm running this on FixedUpdate/LateUpdate. I tried setting high values for deceleration/friction but that didn't solve it.

     
  48. Minzie

    Minzie

    Joined:
    Jul 26, 2019
    Posts:
    77
    Thanks a lot @Krull & @Asarge for the reply & explanation! Well, I thought the "wait" time before next jump is built-in in ECM2. And I'm very thankful to @Asarge for giving the detailed example. This is superrr helpful to noncoder like me :)

    Thanks again to both of you! :D
     
    Krull and Asarge like this.
  49. Asarge

    Asarge

    Joined:
    Jun 2, 2018
    Posts:
    26
    This worked very well thanks! For non-humanoid enemies (giant spider for example) how should the collider be set up so it can function with ECM2 detection? I have Technie Collider Creator 2 which can set up accurate mesh colliders and rigidbodies for each bone but I'm having trouble finding a solution that fits. For example if the collider is from the ground it generally works for world collisions but can't walk over higher objects and the player can't run underneath it. Any ideas how I could get that to work?
    collider.png
     
  50. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    776
    Could be due it moved twice, your other approach and the Move method call, also could be caused by the CharacterMovement not finding walkable ground.

    However if you would like to use the ground detection of the CharacterMovement without it driving your 'character', you can use the CharacterMovement FindGround and / or ComputeGroundDistance methods as this are the same functions used internally by the Move without affecting movement at all.

    If you decide to make use of CharacterMovement alone, I suggest you take a look at the included CharacterMovement package, as it includes additional examples for CM alone.