Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[RELEASED] Easy Character Movement 2

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

  1. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @Predulus,

    A ECM2 character can be controlled directly in your Character class or externally using a Controller.

    A Controller (while not a concrete representation exists in ECM2) is the interface between a character and the human player (or AI) controlling it, be it in the form of a c# script or a visual scripting system like Bolt or in your case PlayMaker.

    When externally controlling a character, you will use its input action commands, such as SetMovementDirection, Jump, StopJumping, Crouch, StopCrouching, etc. typically in response to user input to control your Character.

    So a typical case is extend the Character class to add extra functionality required by your game, and then use a visual scripting tool to implement your Controller.

    In ECM2 the Character class introduces the concept of Movement Modes, e.g. Walking, Falling, Flying, Swimming and Custom. Each movement mode has a set of predefined rules and properties to determine how the character is moved through the world.

    This, while somewhat related to Character states (e.g. Logical states like Jumping, Attacking, Dying, etc.), should not be confused, as the sole purpose of a MovementMode is to determine how the character should be moved through the world.

    Typically you wont need to directly modify the character's movement mode as the Walking / Falling are automatically controlled in response of the character's grounding status, however you can manually set the character's movement mode you desire, using the SetMovementMode function, e.g. Set your character in Flying movement mode, this change in movement mode, will trigger the MovementModeChanged event and calls the OnMovementModeChanged event handler (method).

    The MovementMode.None, basically disables the Character's movement, so the Character wont react to input or external forces, for example, you can use this pause your game.

    You can use the character's speed (eg: Character GetSpeed() method) to determine if is moving (e.g. speed > someThreshold) or if is idle, e.g. speed == 0.

    I suggest you take a look at the user manual, to get a better understanding of the above topics, as definitely will help you to fully take advantage of ECM2, however if you have any further questions, let me know.

    Cheers,
    Krull
     
    Predulus likes this.
  2. Predulus

    Predulus

    Joined:
    Feb 5, 2018
    Posts:
    90
    Thanks a lot mate! :)

    I've definitely been going through the manual, but there is a lot to it, and a lot of code to get through and understand ;)
     
    Krull likes this.
  3. mookfasa

    mookfasa

    Joined:
    Dec 21, 2016
    Posts:
    46
    @Krull

    Trying to implement a Dash on the CMThirdPersonCharacter. I copied all the code from the sample into my custom script and everything seems to work fine upon play. But when I hit play again I get an Input error. The Dash effect it working as expected and it seems to be something with the input itself. I tired adding the input system from the dash sample
    Code (CSharp):
    1. Assets/ECM2/Samples/Examples/5.- Gameplay/5.- Dash/Input Actions/Dash Example Input Actions.inputactions
    On the first play it worked but upon playing again it was giving me the same errors.

    Cheers,
    mookfasa


    Code (CSharp):
    1. MissingReferenceException while executing 'started' callbacks of 'Player Controls/Dash[/Keyboard/e]'
    2. UnityEngine.InputSystem.LowLevel.NativeInputRuntime/<>c__DisplayClass7_0:<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType,UnityEngineInternal.Input.NativeInputEventBuffer*)
    3. UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate (UnityEngineInternal.Input.NativeInputUpdateType,intptr)
    4.  
    Code (CSharp):
    1. MissingReferenceException: The object of type 'CustomCharacterControllerME' has been destroyed but you are still trying to access it.
    2. Your script should either check if it is null or you should not destroy the object.
    3. UnityEngine.Component.GetComponent[T] () (at <4d9f7249f1de41e384668fea10e9822f>:0)
    4. ECM2.Characters.Character.get_characterMovement () (at Assets/ECM2/Source/Characters/Character.cs:311)
    5. ECM2.Characters.Character.GetUpVector () (at Assets/ECM2/Source/Characters/Character.cs:1443)
    6. ECM2.Characters.Character.LaunchCharacter (UnityEngine.Vector3 launchVelocity, System.Boolean overrideVerticalVelocity, System.Boolean overrideLateralVelocity) (at Assets/ECM2/Source/Characters/Character.cs:2590)
    7. ECM2.CustomCharacterControllerME.Dash () (at Assets/ECM2/ME/Controllers/Third Person/Scripts/CustomCharacterControllerME.cs:115)
    8. ECM2.CustomCharacterControllerME.OnDash (UnityEngine.InputSystem.InputAction+CallbackContext context) (at Assets/ECM2/ME/Controllers/Third Person/Scripts/CustomCharacterControllerME.cs:57)
    9. UnityEngine.InputSystem.Utilities.DelegateHelpers.InvokeCallbacksSafe[TValue] (UnityEngine.InputSystem.Utilities.InlinedArray`1[System.Action`1[TValue]]& callbacks, TValue argument, System.String callbackName, System.Object context) (at Library/PackageCache/com.unity.inputsystem@1.0.2/InputSystem/Utilities/DelegateHelpers.cs:51)
    10. UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
    11. UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)
     
  4. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @mookfasa,

    About your error message it seems you are missing the dash input action, please make sure your input action asset contains the Dash input action, you can copy from the Dash Example Input Action asset (the one included in the dash example).

    Please let me know if need any further help.

    Regards,
    Krull
     
  5. mookfasa

    mookfasa

    Joined:
    Dec 21, 2016
    Posts:
    46
    hmmm I think I found the issue. I usually turn on Project Settings > Editor > Enter Play Mode Settings. Turning this off removed the error. I also tried it in a completely new project and I am getting the error as well. The version of unity that I am using is 2020.3.3 - URP.
     
  6. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Thanks for update, can you please try this and see if the setting cause the same issue ?

    Its the dash example merged into a ThirdPersonCharacter derived class, and its input action assets.

    Thanks,
    Krull
     

    Attached Files:

  7. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    @mookfasa, I replicated your issue, that's correct, the Project Settings > Editor > Enter Play Mode Settings is the culprit, however if you check the Reload Domain option, it works as intended.

    I think this could be somewhat related to character setting input actions on Awake, but I need to do further tests to give a final response.

    Regards,
    Krull
     
  8. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Hi @Krull

    I hope you're going well :)

    Until you have time to develop the basic helper component to allow a character follow the terrain slope, I thought I'd give it a try myself. I override the following function:

    Code (CSharp):
    1. protected override void UpdateRotation() {
    2.         base.UpdateRotation();
    3.         RaycastHit hit;
    4.         if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.5f, mask))
    5.         {
    6.             transform.up = hit.normal;
    7.         }
    8.     }
    Ufff.... in general...yes, my animal follows the terrain slope, but..all input events are ignored or the rotation does not react on them. I think this is a really bad solution. I think I have to wait for the work from the pro :)
     
  9. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @asored,

    Thank you for patience, I appreciate it!

    Yes, your issue is caused because your code is overriding the character's rotation (the one with the input rotation) with the slope rotation.

    Here I attach a basic version of the component to be available in the ECM2 update, it is not polished, but works and definitely will help you until the update.

    It works by sampling a 3x3 area and using its average normal to orient the character. To use it, simply add this to your Character.

    Do not hesitate to message me if you have any questions.

    Kind regards,
    Oscar
     

    Attached Files:

    asored, Predulus and Rin-Dev like this.
  10. mookfasa

    mookfasa

    Joined:
    Dec 21, 2016
    Posts:
    46
    Thanks Krull! The package you zipped worked correctly!
     
    Predulus and Krull like this.
  11. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Wooow. Thanks a lot! I will invest some time to study your code to learn from this. Looks very clean and elegant. And.....it works like a charm :):) Wonderful. Thank you :D
     
    Krull likes this.
  12. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Thank you :), glad I could help. Let me know if you need any further help.

    Regards,
    Krull
     
    asored likes this.
  13. mookfasa

    mookfasa

    Joined:
    Dec 21, 2016
    Posts:
    46
    Hi @Krull

    I am trying to modify the move platform script to have it turn it on and off. When toggling it off the platform stops. Which is what I want. But when turning it back on the platform jumps ahead instead of starting where it currnetly is. Here is the modified code.

    Code (CSharp):
    1. using ECM2.Components;
    2. using ECM2.Common;
    3. using UnityEngine;
    4.  
    5. namespace ECM2
    6. {
    7.     /// <summary>
    8.     /// Example of how animate a platform using scripted animation.
    9.     ///
    10.     /// This extends PlatformMovement and override its OnMove method to update its position (and rotation if needed).
    11.     /// </summary>
    12.  
    13.     public sealed class PlatformTranslate : PlatformMovement
    14.     {
    15.         #region EDITOR EXPOSED FIELDS
    16.  
    17.         [SerializeField]
    18.         private float _moveTime = 3.0f;
    19.  
    20.         [SerializeField]
    21.         private Vector3 _offset;
    22.  
    23.         [SerializeField]
    24.         private bool _pingPongOnOff;
    25.  
    26.         #endregion
    27.  
    28.         #region FIELDS
    29.  
    30.         private Vector3 _startPosition;
    31.         private Vector3 _endPosition;
    32.  
    33.         #endregion
    34.  
    35.         #region PROPERTIES
    36.  
    37.         public float moveTime
    38.         {
    39.             get => _moveTime;
    40.             set => _moveTime = Mathf.Max(0.0001f, value);
    41.         }
    42.  
    43.         #endregion
    44.  
    45.         #region METHODS
    46.  
    47.         /// <summary>
    48.         /// Ease function.
    49.         /// </summary>
    50.  
    51.         public static float EaseInOut(float time, float duration)
    52.         {
    53.             return -0.5f * (Mathf.Cos(Mathf.PI * time / duration) - 1.0f);
    54.         }
    55.  
    56.         /// <summary>
    57.         /// Apply platforms movement.
    58.         /// Eg: Update its position and/or rotation here.
    59.         /// </summary>
    60.  
    61.         protected override void OnMove()
    62.         {
    63.             if (_pingPongOnOff)
    64.             {
    65.                 float t = EaseInOut(Mathf.PingPong(Time.time, moveTime), moveTime);
    66.  
    67.                 position = Vector3.Lerp(_startPosition, _endPosition, t);
    68.             }
    69.  
    70.         }
    71.  
    72.         #endregion
    73.  
    74.         #region MONOBEHAVIOUR
    75.  
    76.         private void Reset()
    77.         {
    78.             _moveTime = 3.0f;
    79.             _offset = Vector3.zero;
    80.         }
    81.  
    82.         private void OnValidate()
    83.         {
    84.             moveTime = _moveTime;
    85.         }
    86.  
    87.         public void Awake()
    88.         {
    89.             rigidbody.isKinematic = true;
    90.  
    91.             _startPosition = transform.position;
    92.             _endPosition = _startPosition + _offset;
    93.         }
    94.  
    95.         #endregion
    96.     }
    97. }
     
  14. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @mookfasa,

    Yes, the cause of your issue is it uses Time.time which will keep updating outside of the script, so when unpaused it will be in a different pose.

    Yo can solve it using a timer variable as follows:

    Code (csharp):
    1. protected override void OnMove()
    2. {
    3.     if (paused)
    4.         return;
    5.  
    6.     _time += Time.deltaTime;
    7.     if (_time > moveTime * 2.0f)
    8.         _time = 0.0f;
    9.  
    10.     float t = EaseInOut(Mathf.PingPong(_time, moveTime), moveTime);
    11.  
    12.     position = Vector3.Lerp(_startPosition, _endPosition, t);
    13. }
    So the _time do not update while paused.

    Regards,
    Krull
     
  15. mookfasa

    mookfasa

    Joined:
    Dec 21, 2016
    Posts:
    46
    @Krull Thank you!
     
    Krull likes this.
  16. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Hi @Krull

    I actually try to implement your controller to a AI character. I simply try to move a specific character between two positions.

    For that I’ve created a new ECM2 Agent Controller and parenting it with my model. Everything is fine. It automatically adds a NavMesh Agent to the character.

    But the problem: When I start the game on play, my Player character automatically becomes a Nav Mesh Agent too. The NavMeshAgent component was adding automatically on runtime. So there are many conflicts while moving.

    Is there a reason for that?

    Thanks and best regards,
    Asored
     
  17. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @asored

    Mmm, that's strange as an AgentCharacter can not affect other Character, is your player an AgentCharacter too ? If it does then it makes sense, as it includes its NavMeshAgent.

    By other hand, an AgentCharacter by default implements a typical click to move IF you assign its Input Actions Asset (actions property).

    To control an AgentCharacter externally (controller, AI, etc.) leave its actions property empty and use its MoveToLocation method to issue the character to intelligently navigate to the given point using its NavMeshAgent.

    Regards,
    Krull
     
  18. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Hi @Krull,

    thank you! Strange..hmm..I deactivated the NavMeshAgent on my player as workaround and I will search for the reason soon. I tried to implement the Agent Character Movement now.

    In general it works with the MoveToLocation function. But I see that you set the agent.updateRotation to false in your controller. So I need to handle the rotation myself? Because my AI character is not rotating forward while walking.

    I wrote a script to handle a random AI movement using your AgentCharacter controller as parent:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. using ECM2.Characters;
    6.  
    7. public class RandomWanderAI : AgentCharacter
    8. {
    9.     public float wanderRadius;
    10.     public float wanderTimer;
    11.     public Animator animator;
    12.     private Transform target;
    13.     private NavMeshAgent agent;
    14.     private float timer;
    15.  
    16.     // Use this for initialization
    17.     void OnEnable () {
    18.         agent = GetComponent<NavMeshAgent> ();
    19.         timer = wanderTimer;
    20.         agent.updateRotation = false;
    21.     }
    22.  
    23.     // Update is called once per frame
    24.     void Update () {
    25.         timer += Time.deltaTime;
    26.         if (timer >= wanderTimer) {
    27.             Vector3 newPos = RandomNavSphere(transform.position, wanderRadius, -1);
    28.             base.MoveToLocation(newPos);
    29.             animator.SetBool("IsWalking", true);
    30.             timer = 0;
    31.         }
    32.     }
    33.  
    34.     void LateUpdate() {
    35.        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(agent.velocity.normalized), 10 * Time.deltaTime);
    36.     }
    37.  
    38.     public static Vector3 RandomNavSphere(Vector3 origin, float dist, int layermask) {
    39.         Vector3 randDirection = Random.insideUnitSphere * dist;
    40.         randDirection += origin;
    41.         NavMeshHit navHit;
    42.         NavMesh.SamplePosition (randDirection, out navHit, dist, layermask);
    43.         return navHit.position;
    44.     }
    45. }
    With my LookRotation in LateUpdate the character rotates correctly, but with strange glitches... is there a way to handle this with your controller?

    Thanks in advance!
    Asored
     
    Last edited: May 26, 2021
  19. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @asored,

    I noticed a few issues with your custom character.

    An AgentCharacter is basically a regular Character with navigation support, so it brings you the same functionality as a Character (e.g. rotate towards movement direction, sprint, crouch, jump, etc.) but with the extra functions to let the character intelligently navigate the world.

    When creating a Character or Character derived class like the AgentCharacter, for basic usage (not adding new mechanics) you just need to make use of its input action commands to control your character (e.g. SetMovementDirection, Jump, StopJumping, MoveToLoction, etc).

    Remember, when creating a Character derived class you extend its methods (using override modifier) in order to replace or add new mechanics, and that's the reason why you are getting issues since in your script you are basically rewriting part of its already included features replacing the AgentCharacter implementation.

    That's one of the many advantages of object oriented programming and inheritance, you reuse / extend existing functions.

    So in your case, to implement a wander mechanic, you just need to use the MoveToLocation and let the AgentCharacter take care of the other things, for example:

    Code (csharp):
    1.  
    2. public sealed class WanderingCharacter : AgentCharacter
    3. {
    4.     public float wanderRadius;
    5.     public float wanderTimer;
    6.     private float timer;
    7.  
    8.     public static Vector3 RandomNavSphere(Vector3 origin, float dist, int layermask)
    9.     {
    10.        Vector3 randDirection = Random.insideUnitSphere * dist;
    11.        randDirection += origin;
    12.        NavMeshHit navHit;
    13.        NavMesh.SamplePosition (randDirection, out navHit, dist, layermask);
    14.        return navHit.position;
    15.     }
    16.  
    17.     private void Wandering()
    18.     {
    19.        timer += Time.deltaTime;
    20.        if (timer >= wanderTimer) {
    21.            Vector3 newPos = RandomNavSphere(transform.position, wanderRadius, -1);
    22.          
    23.            MoveToLocation(newPos);
    24.  
    25.            animator.SetBool("IsWalking", true);
    26.  
    27.            timer = 0;
    28.        }
    29.     }
    30.    
    31.     protected override void OnStart()
    32.     {
    33.        base.OnStart();
    34.  
    35.        timer = wanderTimer;
    36.     }
    37.  
    38.     protected override void OnMove()
    39.     {
    40.        base.OnMove();
    41.  
    42.        // Wandering state
    43.  
    44.        Wandering();
    45.     }
    46. }
    47.  
    As you can see in the above code, the AgenCharacter already caches the animator and as a Character will automatically rotate towards its given movement direction, assigned with its MoveToLocation function.

    Think of this way, to move a character you just need to use its SetMovementDirection with your desired direction vector in world space, while to move an agent, you set its target world position using its MoveToLocationFunction.

    I suggest you follow the user manual and the included examples (while not AI related), those should give you a better understanding of how to extend a Character or externally take control of it.

    Having said that, while I developed ECM and ECM2 to be easy to use, unfortunately it still needs some programming or visual scripting to make the most of it.

    Kind regards,
    Krull
     
    JohnnyGo-Time and asored like this.
  20. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Thank you, @Krull. With your explanation I well understand what's the problem was. In short words: I completely overwrote your controller logic with my own functions from the child class. (for example Update()). Well. I knew about using your virtual functions for overriding purposes. It makes absolutely sense that for main events like Update or Start it would be the same. Using your functions from the parent class the AI behavior is working fine now. This understanding helps me also for other issues I had. Great! :)

    I think I have still problems with the water detection using your PhysicsVolume script (Using GAIA and his own built in water). But I want first try to find a solution by myself and by studying your examples before asking you.

    Wish you a nice weekend :)

    Best regards,
    Asored
     
    Krull likes this.
  21. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    934
    Is there any kind of API documentation available?

    I would like to take a look at it before purchasing this asset
     
  22. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Hmm.. I tried to find a solution today for the Physics Volume issue – but without success. For understanding better the issue I've recoreded a small video.



    As you see in the video, I found a workaround to create swimming behavior. But I can't get the PhysicsVolume behavior to work. Also if I create a simple cube with the PhysicsVolume as parent (for testing purposes), my player does not changes movement and ignores the PhysicsVolume completely.

    Also I tried to call some events like OnPhysicsVolumeChanged, but this event gets never called.

    Could it be that the PhysicsVolume logic does not work with Root Motion animation movement? Or is there an error in my settings?

    Additional information: In the video you see the deactivated "Is Trigger" on Box Collider from the Water class. Activating the trigger the result is the same as before.

    I really appreciate your help. Workarounds are temporary fine. But just temporary :)

    Thanks so much!

    Asored
     
  23. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @Ruchir,

    Thank you for your interest in ECM2!

    Uunfortunately at this moment the API Reference is not ready yet, just the user manual. I am aware of this limitation and should be available soon, in the meantime, let me know If have any questions.

    Regards,
    Krull
     
  24. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @asored

    That's correct! glad I was able to help you :)

    About the PhysicsVolume, well this is just a trigger and the trigger should be bigger enough to encompass your water area, and obviously your character should be able to collide with those triggers.

    For example, I noticed a few issues in your video, your water volume its 1x1x1 in size so probably the character is not interacting with it, Worth not a PhysicsVolume behaves a little different from a regular trigger, I mean for a Character to be considered inside a PhysicsVolume, its center must be inside the trigger area while on a regular trigger the minimal intersection is enough. This is by design, so a character can float at a water line and still be considered inside until its center is completely out.

    Additionally, in your water volume, you have the max fall speed set to zero, I suggest you use a greater value or your character won't be able to dive. You can use the buoyancy property to control your character, where a value above 1 (e.g. 1.1), will make your character float back to the water line.

    I suggest you do a quick test, copy the water volume from the demo scene and position it on your scene where your character can walk into it, it should work.

    Regards, and have a nice weekend too!
    Krull
     
  25. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Thanks @Krull, I understand!

    I have a terrain where the water depends on the water level. So I have no specific water objects or something else.
    Can I implement your Physics Volume logic also dynamically depending on the water level to know: this must be water. So change automatically the CharacterMovement to Swimming?

    Or should I react on this manually by creating something like this:

    Code (CSharp):
    1. if (transform.position.y <= 37) {
    2.   // If player position is less then water level, set CharacterMovement manually to Swimming
    3. } else {
    4.   // Is leaving water. Set CharacterMovement back to Walking
    5. }
    Would something like this be a clean solution? Or is there a better way to handle automatic water detection using your controller?

    Again: Thanks in advance for your efforts. I think this is my last question for now.......I'm sorry for the trouble :/
     
  26. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @asored

    You can use a PhysicsVolume for this, as this is just a trigger (a box defining an area in your world), it doesn't even need a visual representation. You can scale it to stimulate your water level, however a character won't be considered swimming until its center position is inside this PhysicsVolume (trigger area).

    By other hand, yes, you can issue a character to swim / stop swimming without a physics volume using its Swim / StopSwimming methods respectively, however your character won't float due to buoyancy immersion depth calculation, as this check how deep in water the character is immersed and it uses the PhysicsVolume top as waterline.

    Having said that, in your custom controller you can override the ImmersionDepth method, to check if it is swimming and not inside a water volume, return a value of 1 (fully immersed), e.g:

    Code (csharp):
    1. public override float ImmersionDepth()
    2. {
    3.     // If swimming without a water physics volume, return a simulated immersion depth
    4.  
    5.     if (IsSwimming() && !IsInWater())
    6.         return 1.0f;
    7.    
    8.     // Return real immersion depth
    9.  
    10.     return base.ImmersionDepth();
    11. }
    Dont worry about it :)

    Kind regards,
    Krull
     
    asored likes this.
  27. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    176
    I'm really looking forward to the update on vaulting, wall running, wall-grab!

    Can I get a rough estimate?
     
  28. Rin-Dev

    Rin-Dev

    Joined:
    Jun 24, 2014
    Posts:
    574
    Could ledge grab also be incorporated somehow? I'm assuming the same way a wallgrab would be.
     
  29. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    I'm really enjoying ECM2. Thanks for your hard work with this new controller!

    One thing that keeps tripping me up is the decision to put ECM2 at the very top of the Objects list. I keep reaching for 'Create Empty' and having to fight my way past the ECM2 menu. Can this be moved to the bottom, or at least below 'Light'?

    upload_2021-6-1_10-24-11.png
     
  30. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Yes, I will be adding those as examples in future updates, unfortunately I can not provide a release date. Having said that please keep in mind ECM2 is a general purpose controller so while I add those mechanics as examples, are just that, examples of how to implement custom mechanics (game specific) with ECM2.

    Regrds,
    Krull
     
  31. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @dock,

    Thank you, happy to know you like ECM2 :)

    About your question:

    You can modify the ECM2FactoryEditor (ECM2\Source\Editor) and replace this:

    Code (csharp):
    1. [MenuItem("GameObject/ECM2/Character", false, 0)]
    with:
    Code (csharp):
    1. [MenuItem("Tools/ECM2/Character", false, 0)]
    Do the same for the Agent and First person in the same file).

    This will move the ECM2 category from context menu to the main tool bar (on top) in the Tools category.

    Regards,
    Krull
     
    RogDolos likes this.
  32. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    176
    Is there a recommended way to manage controllers for multiple characters?

    For example
    There are characters A, B, C, and D above the scene.
    It works a bit simply by changing the Enable state of the Controller, but this approach presents some problems.
    (Do not operate normally in the order in which the controller is activated,
    If an active character hits the collider of a disabled character, the character will fly away )
    In addition, if the character controller starts disabled, the character's collider is attached to the ground, but the character is airborne.

    Is there an exact initialization method or recommended method?


    I put the gif that reproduced the problem on the link below.
    https://ibb.co/Xp2sVvk
     
    Last edited: Jun 2, 2021
  33. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @seoyeon222222

    Yes, that make sense, as a disabled character (I assume you mean the Character script), will behave as a regular rigidbody with no ECM2 interaction at all.

    a Character is initialized in its OnAwake method and its OnOnEnable is used to enable its input actions (if any) so once created (instantiated), a character remains initialized without further interaction.

    You can take a look at the demo scene and its DemoController.cs, where it enable / disable the characters GameObject as needed (e.g: SetActive(false), SetActive(true) ).

    By other hand, to disable a Character (e.g. not be able to move or interact with others), you can set its MovementMode to none, this is similar at the previous pause method in ECM, e.g:

    Code (csharp):
    1. SetMovementMode ( MovementMode.None );
    Let me know if you need any further help.

    Regards,
    Krull
     
    seoyeon222222 likes this.
  34. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    ECM2 v1.0.1 API REFERENCE

    For those interested, H E R E you can find the ECM2 v1.0.1 (current) API Referece documentation, this will be included in the next ECM2 update with the package.

    - Krull
     
  35. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    176

    Thanks to reply.

    I checked DemoController.cs for an example.
    It was making the actual character not active in Scene by making the character itself SetActive.
    It was little far from my problem of setting up each control of several characters in same Scene at the same time.

    SetMovementMode ( MovementMode.None );
    It looks working as intended.
    How do I get back to control?
    I checked Movement Mode Enum, but it is difficult to check the proper value against None.
    In fact, if i change the mode to Walking, it will work as intended. (can move well)
    but If i forced to change the State to Walk even though character is not actually walking,
    I'm concerned about bugs in other areas that will refer to the character's State.
     
  36. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    You can check if character is disabled, using its isDisabled() method.

    To re-activate a disabled character (movement mode - none) you can safely set its movement mode to falling (preferred) or walking, since those movement modes are automatically managed and updated based on character’s grounding state.

    once disabled (movement mode = none) a character can only leave that state manually calling your new desired movement mode.
     
    seoyeon222222 likes this.
  37. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Thanks @Krull, I'll try it soon! :) Thanks also for creating an API Reference. This is a big helper! Awesome!

    Regards,
    Asored
     
    Krull likes this.
  38. Zartok

    Zartok

    Joined:
    Apr 21, 2017
    Posts:
    4
    Hello there :) Bought this asset and I'm kinda new to coding. In your Character.cs or AgentCharacter.cs, how would I go on if I wish to make it so that the movement does not trigger when clicking UI objects? As of now it stil moves when clicking on different UI objects.
     
  39. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @Zartok,

    First of all thank you for purchasing ECM2!

    About your question:

    Yes, as that kind of interaction is typically game dependent, for example, typically the game is paused when UI is opened, or slowed like in doom eternal when weapons UI is displayed, etc.

    Having said that, if you want to prevent AgentCharacter from validating a movement when the mouse cursor is over an UI element, you can add the following to the AgentCharacter or to your AgentCharacter derived class (e.g. a custom AgentCharacter).

    Add the following namespace on top of your script:

    Code (csharp):
    1. using UnityEngine.EventSystems;
    Then in the same AgentCharacter.cs file, modify the OnMouseClick input action handler function as follows:

    Code (csharp):
    1. /// <summary>
    2. /// Mouse click input action handler.
    3. /// </summary>
    4.  
    5. protected virtual void OnMouseClick(InputAction.CallbackContext context)
    6. {
    7.     if (EventSystem.current && EventSystem.current.IsPointerOverGameObject())
    8.         return;
    9.  
    10.     _mouseButtonPressed = context.started || context.performed;
    11. }
    This code will check if mouse cursor is over a ui and prevent mouse click.

    By other hand to pause your game, the easiest way is setting the Unity Time.timeScale to zero and set it back to 1 to un-pause.

    Last but not the least, if you want to 'pause' a game character, simply set its movement mode to None to disable all its movement, and set it back to Falling to re-enable it.

    Let me know if you need any further help.

    Regards,
    Krull
     
    Last edited: Jun 3, 2021
    asored likes this.
  40. Zartok

    Zartok

    Joined:
    Apr 21, 2017
    Posts:
    4
    Thanks a lot :) That worked like a charm. I'm trying to implement the character controller into a TopDown ARPG, appreciate the offer to help Krull ^^
     
    asored and Krull like this.
  41. ge01f

    ge01f

    Joined:
    Nov 28, 2014
    Posts:
    121
    @Krull Just picked up ECM2 after enjoying ECM.

    Any issues integrating with Rewired? I know your demos use New Input and it seems your documentation say it's integral to the design.

    I like how Rewired works, and would prefer to stay with that. I dont see it mentioned in the docs. I dont need it integrated, just checking to see what you recommend for using it with your code. Thanks!
     
  42. Candescence

    Candescence

    Joined:
    Aug 26, 2014
    Posts:
    107
    @Krull Just wondering, any suggestions on how to refactor the wall-jump example from ECM to ECM2? I've successfully gotten the wall-slide working, but not the jump. Learning how ECM2 is different from its predecessor has been a bit of an interesting learning experience, but it would be nice to have a properly ported example rather than my fuddling about.

    Also, the Bolt examples don't work with Unity 2021's visual scripting module (aka the internally integrated version of Bolt), just an FYI. Having a separate set of examples for 2021 would be helpful, especially since 2021's version of Bolt finally has support for the Input System.
     
  43. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @ge01f,

    Thank you for purchasing ECM2 (and ECM)!

    About your question, absolutely while it uses the new input system by default, you are not forced to use it and can be replaced for the input solution you prefer.

    I suggest you take a look at the included Old Input examples (ECM2\Samples\Examples\1.- Input\1.4.- Old Input Examples) , as it would be pretty similar to add rewired support, basically just like ECM, you override its HandleInput method and add your preferred input solution.

    Another option is to externally take control of your character (e.g. a Controller). In both cases Just make sure you leave the Character's actions property empty so the character won't process input actions.

    In the end to move a Charcter you just need to use its input action commands, e.g: SetMovementInput, Jump, StopJumping, Crouch, StopCrouching, etc. be in your custom character (extending a Character class) or from another script or visual solution (eg: Controller, Bolt, etc.)

    Regards,
    Krull
     
  44. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    762
    Hi @Candescence,

    Yes I agree, however while ECM2 shares many things in common with ECM it is basically just a different product built from the ground up but happens to have an upgrade option, so unfortunately there is not a 100% direct port between both products. Having said that, I will include as part of the next update a guide showing ECM2 from a ECM user perspective.

    Additionally, I plan to port missing ECM examples to ECM2 and add more examples, so please bear with me on this.

    Having said that, the easiest way to implement the wall-jump once you have implemented the wall-slide, is use the LaunchCharacter function, this is a versatile function (used by dash, slide, etc.) that allows you to add / replace your character's velocity while comply with new continuous collision algorithm (aka CollideAndSlide).

    Thank you for the report! I will check it out, and yes, I will include a separate package for 2021, probably distributed with a native 2020.x and 2021.x versions too.

    Kind regards,
    Krull
     
  45. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    That is exactly, what I am looking for.
    Is it easy enough to set up the ECM2 for animals?
     
  46. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    I have purchased ECM2, just for the reason that, the package is updated and have a Unity forum thread,
    where the developer answers the questions. Keep up the good work.
     
    Krull likes this.
  47. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    Could you please make some tutorial about how to use ECM2 with animals and make them swimming in the water.
    Thanks.
     
  48. asored

    asored

    Joined:
    Nov 6, 2020
    Posts:
    22
    Hi @Artini

    yes, it is very easy to use ECM2 with animals. Look at the first page of this thread. The ECM2 developer posted some instructions regarding creating colliders depending on your animal body. With this way I can absolutely use this asset for my lion player. Also swimming behavior is no problem with a built in component "Physics Volume" or using methods of the Character class. You can read about it in the official manual. Also you can check my post #75, there I had the same question as yours.

    I wish you much fun with ECM2. This asset makes character development easy :)

    Best regards,
    Asored
     
    Krull likes this.
  49. Minzie

    Minzie

    Joined:
    Jul 26, 2019
    Posts:
    77
    Hey, I'm interested in this asset. Can I know if this is usable in multiplayer? Is this compatible with playmaker? Also what is your plan in updating more movement e.g. climbing rope, etc.?
     
  50. Candescence

    Candescence

    Joined:
    Aug 26, 2014
    Posts:
    107
    Okay, thanks! Though, is there any way to adjust the horizontal velocity? Here's the current set of code for the wall jump launch:

    Code (CSharp):
    1. public float wallJumpImpulse
    2. {
    3.     get { return Mathf.Sqrt(2.0f * wallJumpHeight * gravity.magnitude); }
    4. }
    Code (CSharp):
    1. // Apply wall-jump impulse
    2. var wallJumpVelocity = (_wallNormal + Vector3.up).normalized * wallJumpImpulse;
    3. LaunchCharacter(Vector3.ProjectOnPlane(GetVelocity(), transform.up) + wallJumpVelocity);
    I'd like to be able to adjust the horizontal velocity independently of the vertical, so I can do stuff like Mega Man X wall jumps without needing to adjust the player's horizontal speed to overcome the horizontal impulse.

    Edit: Actually, I neglected to take the character's acceleration into account. Would still like to be able to have the horizontal impulse value to tweak, but I think I can work around it.

    Edit 2: I'm also having problems making new input actions work, despite setting them up exactly as they should be:

    Code (CSharp):
    1. protected InputAction fireInputAction { get; set; }
    2.  
    3.         protected virtual void OnFire(InputAction.CallbackContext context) {
    4.             if (context.started || context.performed) {
    5.                 FirePressed();
    6.             } else if (context.canceled) {
    7.                 FireReleased();
    8.             }
    9.         }
    Code (CSharp):
    1.  
    2. protected override void SetupPlayerInput()
    3.         {
    4.             // Init base character controller input actions (if any)
    5.  
    6.             base.SetupPlayerInput();
    7.          
    8.             // Attempts to cache and init this InputActions (if any)
    9.  
    10.             Debug.Log("Setting up actions...");
    11.  
    12.             if (actions == null) {
    13.                 return;
    14.             }
    15.  
    16.             fireInputAction = actions.FindAction("Fire");
    17.             if (fireInputAction != null) {
    18.                 fireInputAction.started += OnFire;
    19.                 fireInputAction.performed += OnFire;
    20.                 fireInputAction.canceled += OnFire;
    21.             }
    22.         }
    23.  
    I also made sure the inputs themselves are set up correctly in Unity, so I have no idea what I'm missing, because I've done extensive debugging and the setup seems to work fine, but the inputs aren't activating regardless.
     
    Last edited: Jun 5, 2021