Search Unity

[Released] Kinematic Character Controller

Discussion in 'Assets and Asset Store' started by PhilSA, Sep 29, 2017.

  1. Zebbi

    Zebbi

    Joined:
    Jan 17, 2017
    Posts:
    521
    Okay, it's been a while, but so here goes:
    I'm using a series of raycasts that test if there is an edge directly in front of my capsule, and if so, I take the normal and use ProjectOnPlane to allow my capsule to slide around it.

    You need to fire a ray directly ahead from the player/enemy, rotated to the left and firing straight down; this is your ground check (red). If it hits nothing, fire a second ray backwards (purple) (but down slightly so it doesn't fire straight over the top of the ground) to find the left closest edge normal to the player:
    upload_2020-7-18_8-44-26.png
    Code (CSharp):
    1.         leftRay = transform.position + Quaternion.Euler(0f, 20f, 0f) * transform.forward * 0.4f;
    2.         RaycastHit hitInfo = default(RaycastHit);
    3.         var raycast = Physics.Raycast(leftRay, Vector3.down, out hitInfo, edgeGapHeight, SceneClass.Instance(scene).
    4.         theLayersILoveNoEnemyNoPlayer);
    5.      
    6.         if (!raycast)
    7.         {
    8.             RaycastHit hitInfo1 = default(RaycastHit);
    9.             var raycast1 = Physics.Raycast(new Vector3(leftRay.x, ground.y + -0.02f, leftRay.z), new Vector3((-((Vector3)(Quaternion.
    10.             Euler(0f, 20f, 0f) * transform.forward * 0.4f))).x, 0f, (-((Vector3)(Quaternion.Euler(0f, 20f, 0f) * transform.forward * 0.4f
    11.             ))).z), out hitInfo1, edgeGapHeight, SceneClass.Instance(scene).theLayersILoveNoEnemyNoPlayer);
    12.          
    13.             if (raycast1)
    14.             {
    15.                 leftEdgeNormal = hitInfo1.normal;
    16.             }
    17.         }
    Do the same for the right side:
    upload_2020-7-18_8-45-27.png
    Code (CSharp):
    1.         rightRay = transform.position + Quaternion.Euler(0f, -20f, 0f) * transform.forward * 0.4f;
    2.         RaycastHit hitInfo2 = default(RaycastHit);
    3.         var raycast2 = Physics.Raycast(rightRay, Vector3.down, out hitInfo2, edgeGapHeight, SceneClass.Instance(scene).
    4.         theLayersILoveNoEnemyNoPlayer);
    5.      
    6.         if (!raycast2)
    7.         {
    8.             RaycastHit hitInfo3 = default(RaycastHit);
    9.             var raycast3 = Physics.Raycast(new Vector3(rightRay.x, ground.y + -0.02f, rightRay.z), new Vector3((-((Vector3)(Quaternion.
    10.             Euler(0f, -20f, 0f) * transform.forward * 0.4f))).x, 0f, (-((Vector3)(Quaternion.Euler(0f, -20f, 0f) * transform.forward *
    11.             0.4f))).z), out hitInfo3, edgeGapHeight, SceneClass.Instance(scene).theLayersILoveNoEnemyNoPlayer);
    12.          
    13.             if (raycast3)
    14.             {
    15.                 rightEdgeNormal = hitInfo3.normal;
    16.             }
    17.         }
    Now finally we need the forward normal to check where the edge is directly in front:
    upload_2020-7-18_8-46-46.png
    Code (CSharp):
    1.         forwardRay = transform.position + transform.forward * 0.4f;
    2.         RaycastHit hitInfo4 = default(RaycastHit);
    3.         var raycast4 = Physics.Raycast(forwardRay, Vector3.down, out hitInfo4, edgeGapHeight, SceneClass.Instance(scene).
    4.         theLayersILoveNoEnemyNoPlayer);
    5.      
    6.         if (raycast4)
    7.         {
    8.             edgeNormal = Vector3.zero;
    9.             manOnTheEdge = false;
    10.         }
    11.         else
    12.         {
    13.             manOnTheEdge = true;
    14.             RaycastHit hitInfo5 = default(RaycastHit);
    15.             var raycast5 = Physics.Raycast(transform.position, Vector3.down, out hitInfo5, edgeGapHeight * 2f, SceneClass.Instance(scene)
    16.             .theLayersILoveNoEnemyNoPlayer);
    17.          
    18.             if (raycast5)
    19.             {
    20.                 ground = hitInfo5.point;
    21.                 RaycastHit hitInfo6 = default(RaycastHit);
    22.                 var raycast6 = Physics.Raycast(new Vector3(forwardRay.x, ground.y + -0.02f, forwardRay.z), new Vector3((-transform.
    23.                 forward).x, 0f, (-transform.forward).z), out hitInfo6, edgeGapHeight, SceneClass.Instance(scene).
    24.                 theLayersILoveNoEnemyNoPlayer);
    25.              
    26.                 if (raycast6)
    27.                 {
    28.                     edgeNormal = hitInfo6.normal;
    29.                 }
    30.             }
    31.         }
    Once we have at least one situation where we have an edge, we can decide if we want to halt the player/enemy right in their tracks:
    Code (CSharp):
    1.         if (leftEdgeNormal == edgeNormal && rightEdgeNormal != edgeNormal)
    2.         {
    3.             stop = true;
    4.         }
    5.         else
    6.         {
    7.             stop = false;
    8.         }
    9.      
    10.         if (rightEdgeNormal == edgeNormal && leftEdgeNormal != edgeNormal)
    11.         {
    12.             stop = true;
    13.         }
    14.         else
    15.         {
    16.             stop = false;
    17.         }
    And finally, ProjectOnPlane comes to take care of figuring out exactly what our movement vector should be:
    Code (CSharp):
    1.         moveVector = Quaternion.Euler(transform.eulerAngles) * new Vector3(0f, gravity, speed);
    2.         projectedVector = Vector3.ProjectOnPlane(moveVector, edgeNormal);
    3.      
    4.         if (stop)
    5.         {
    6.             projectedVector = Vector3.zero;
    7.         }
    8.         else
    9.         {
    10.             GetComponent<CharacterController>().Move(projectedVector * Time.deltaTime);
    11.         }
    12.     }
    I apologise for this being an ungodly mess and probably very unreadable, but I could *not* find a good solution to this anywhere and had to really mess around until something worked. I'd be happy to try and answer any questions you have and explain as much as I can remember if you need some clarification!

    Shoutout to @PhilSA if he wants to provide a robust and built-in ledge detection, it would be enormously useful for enemies and players who need to stay on top of any surface.
     
    transat likes this.
  2. Zebbi

    Zebbi

    Joined:
    Jan 17, 2017
    Posts:
    521
    Shoutout to @PhilSA if he still supports KCC?
     
  3. Shturmovik

    Shturmovik

    Joined:
    Nov 5, 2014
    Posts:
    29
    Yeah - any sort of heads-up on the status of the asset would be much appreciated. Just switched to Unity 2020.1 to start early work on a new project, and everything KCC-wise seems to be working fine so far, but it's probably just a matter of time before something breaks.

    Trying to keep my internal component interfaces clean enough that I could even switch to one of Unity's own character controller solutions if I had to, but would much prefer to stick with KCC as it's so focused on doing one thing extremely well without dragging in a lot of extra functionality.

    However, for anyone who didn't catch it the first time around, I'll share this link:

     
  4. Jamoy1993

    Jamoy1993

    Joined:
    Jan 17, 2014
    Posts:
    14
    @PhilSA - I have sent you a conversation that you have not replied to about a potential bug. Could you have a look please?
     
  5. Onat-H

    Onat-H

    Joined:
    Mar 11, 2015
    Posts:
    195
    I need to change the collision layers of my character in runtime depending on the gamestate, but simply changing the layer mask doesn't seem to have an effect (I guess because the layer mask is only pulled once in awake..), is there a way to do this currently?
     
  6. unity_w8Ut9sYUwJx21g

    unity_w8Ut9sYUwJx21g

    Joined:
    May 16, 2020
    Posts:
    1
    So i have an object that rotates towards the players forward position. whenever i add a physics mover script to the object, my player doesn't move at all.

    Plus any idea how i can move the character with the rotating platform? the platform doesn't rotate with animations.
     
  7. transat

    transat

    Joined:
    May 5, 2018
    Posts:
    779
    While @PhilSA is hard at work on the DOTS version of KCC and on other projects, he might not be able to provide much support here. So a reminder that there is also a Discord set up for KCC (by a user) that you can ask questions in as well. It’s not very active but it might be a better place for us to help each other out...

    https://discord.gg/gk4eYkh
     
  8. gigazelle

    gigazelle

    Joined:
    May 6, 2017
    Posts:
    13
    Anyone know of an easy way to get the average of all normals touching the character controller, including both floors and walls?
     
  9. transat

    transat

    Joined:
    May 5, 2018
    Posts:
    779
    Hi Phil. Do you have any pointers on how to do this with KCC? And are there any simpler ways? For example, could I place a sphere collider in the middle of my horse and pair that with the quadruped grounding from FinalIK?

    @emrys90 did you manage to get this working?
     
  10. jamesliu123

    jamesliu123

    Joined:
    Dec 16, 2017
    Posts:
    3


    Hi, how to avoid to rebounding when the character's head is hitted under the collider.
    I used this code:
    Code (CSharp):
    1.  
    2. public  void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
    3. {
    4. ...
    5.  if(Vector3.Dot(hitNormal, Motor.CharacterUp) < 0f)
    6.            {
    7.                _headJumpHit = true;
    8.            }
    9. ...
    10. }
    11. ....
    12. public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
    13. ...
    14. if (_headJumpHit)
    15. {
    16.     _headJumpHit = false;
    17.     currentVelocity.x = 0;
    18.     currentVelocity.z = 0;
    19. }
    20. ...
    21.  
    but not very accurate.
    Help!!!
     
    FcsVorfeed likes this.
  11. jamesliu123

    jamesliu123

    Joined:
    Dec 16, 2017
    Posts:
    3
    the player was attacking , maybe open the KCC, use astarpath moving. when chasing the player, close the KCC and rigidbody.
     
    Gooren likes this.
  12. safacon

    safacon

    Joined:
    Sep 5, 2013
    Posts:
    5
    Does this system support additive scenes?
     
  13. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
  14. jamesliu123

    jamesliu123

    Joined:
    Dec 16, 2017
    Posts:
    3
    I changed the code
    Code (CSharp):
    1.    public virtual void HandleVelocityProjection(ref Vector3 velocity, Vector3 obstructionNormal, bool stableOnHit)
    2.         {
    3.             if (GroundingStatus.IsStableOnGround && !MustUnground())
    4.             {
    5.                 // On stable slopes, simply reorient the movement without any loss
    6.                 if (stableOnHit)
    7.                 {
    8.                     velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude;
    9.                 }
    10.                 // On blocking hits, project the movement on the obstruction while following the grounding plane
    11.                 else
    12.                 {
    13.                     Vector3 obstructionRightAlongGround = Vector3.Cross(obstructionNormal, GroundingStatus.GroundNormal).normalized;
    14.                     Vector3 obstructionUpAlongGround = Vector3.Cross(obstructionRightAlongGround, obstructionNormal).normalized;
    15.                     velocity = GetDirectionTangentToSurface(velocity, obstructionUpAlongGround) * velocity.magnitude;
    16.                     velocity = Vector3.ProjectOnPlane(velocity, obstructionNormal);
    17.                 }
    18.             }
    19.             else
    20.             {
    21.                 if (stableOnHit)
    22.                 {
    23.                     // Handle stable landing
    24.                     velocity = Vector3.ProjectOnPlane(velocity, CharacterUp);
    25.                     velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude;
    26.                 }
    27.                 // Handle generic obstruction
    28.                 else
    29.                 {
    30.                     velocity = Vector3.ProjectOnPlane(velocity, obstructionNormal);
    31.                  
    32. if(Vector3.Dot(obstructionNormal, CharacterUp) < 0)
    33. {
    34.     velocity.x = 0;
    35.     velocity.z = 0;
    36. }
    37.                 }
    38.             }
    39.         }
    if(Vector3.Dot(obstructionNormal, CharacterUp) < 0)
    {
    velocity.x = 0;
    velocity.z = 0;
    }
    The rebounding was Completely removed.
    Is this solution feasible?
     
    Last edited: Sep 1, 2020
  15. Zebbi

    Zebbi

    Joined:
    Jan 17, 2017
    Posts:
    521
    @PhilSA seems to be around judging by his profile, but is just ignoring this thread? (and tweets.)
     
  16. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    This is how Phil operates. Based on statistics, he didn't abandon the asset. He's just fully concentrated on DOTS version of this asset as usual. Sometimes, he shows up in this thread, responds to all questions and falls silent again.
    Also, easiest way to reach him is by mailing him.
     
  17. Fragment1

    Fragment1

    Joined:
    Aug 30, 2013
    Posts:
    67
    A question I hope someone can maybe answer. I'm trying to use this asset with Mirror, but the transform isn't updating on the server side?

    Is there any way to use it with mirror without reinventing the wheel?
     
  18. Dnns_

    Dnns_

    Joined:
    Oct 8, 2018
    Posts:
    1
    Hey im thinking ob buying this controller. I know its not a simple plugin in solution im just a but worried. On the shop side its sais:
    Note that its "kinematic" nature means that it will not get pushed by forces or rigidbodies automatically. These sorts of interactions have to be explicitly scripted

    What does that exactly mean? Does the character controller not collide with anything? The big reason i wanted to buy this was because of the collisions and movement in the video.
    Thanks for answering.
     
  19. transat

    transat

    Joined:
    May 5, 2018
    Posts:
    779
    Essentially it means you’ll need to add a script to the game objects that can push your character. Nothing too scary. The character will still collide with anything that has a collider.
     
  20. PaperMartin1

    PaperMartin1

    Joined:
    Jul 18, 2014
    Posts:
    4
    Hey, seems like the example character controller has no issue standing on moving rigidbodies that are going horizontally or downwards, but if they go upward it breaks XVLIBqVyiL.gif
    I'm not insanely good with physics & vector maths in general so I couldn't really find a solution for this on my own, anyone's got any idea how to handle this kind of situation? my game has rigidbody boats of various size so if the player can't stand on them unless they never go upward (like by waves) that'd really suck
    if any of y'all have suggestions I'll take them
    edit : my boats's physics is based on this video

    edit : I tried this solution https://forum.unity.com/threads/released-kinematic-character-controller.497979/page-2#post-3267702 and apart from slight stuttering when going up this seems to work
     
    Last edited: Sep 13, 2020
    Gooren, orangetech and FcsVorfeed like this.
  21. linq

    linq

    Joined:
    Jun 20, 2015
    Posts:
    7
    There are two kinematic character controller in the scene. If I disable one character controller in runtime, I get error StandardMovementController.cs:209
    Code (CSharp):
    1.  
    2.             for (int i = 0; i < characterMotorsCount; i++)
    3.             {
    4.                 KinematicCharacterMotor motor = motors[i];
    5.  
    6.                 motor.UpdatePhase2(deltaTime);
    7.  
    8.                 motor.Transform.SetPositionAndRotation(motor.TransientPosition, motor.TransientRotation);
    9.             }
    I fixed this error when I changed code.
    Code (CSharp):
    1.  
    2.             for (int i = 0; i < motors.Count; i++)
    3.             {
    4.                 KinematicCharacterMotor motor = motors[i];
    5.  
    6.                 motor.UpdatePhase2(deltaTime);
    7.  
    8.                 motor.Transform.SetPositionAndRotation(motor.TransientPosition, motor.TransientRotation);
    9.             }
     
    deiterate likes this.
  22. kirbyderby2000

    kirbyderby2000

    Joined:
    Apr 28, 2017
    Posts:
    35
    Hello! So I tried implementing a state to make the kinematic character controller move in a prone / crawling position, which I've done successfully simply by rotating the character to make its face point to the ground (90 degrees); however doing this makes the KCC report as being ungrounded because the pivot point of the capsule loses contact with the collider on the ground. It makes sense that this is the behavior because the bottom of the capsule is essentially the feet, but I'm wondering if there is another way to make ground checks other than doing my own manual ray casting from the pivot point towards the ground to see if the character is truly ungrounded while the character is prone. Is there a way to override the "feet" position of the KCC where ground checks are made? If there is, I would like to make the belly of my character its new "feet" position where the grounding of the character is evaluated.

    I've provided a screenshot below of where the pivot point of the character is when I rotate it 90 degrees, this is the point where the grounding is evaluated.



    Or if anyone has come up with a better way to implement prone movement using the KCC, I'd love to hear how you managed to do it.
     
    Last edited: Sep 26, 2020
  23. ParkyRander

    ParkyRander

    Joined:
    Jun 1, 2014
    Posts:
    8
    Any recommendations on how to achieve target matching/warping elegantly with KCC.
     
  24. diggerjohn

    diggerjohn

    Joined:
    Apr 28, 2009
    Posts:
    60
    Newb here ... I can't seem to find any discussion in the documentation about Character Rig requirements. My workflow has been through Mixamo for years. Trying to find out if there are any issues there. Does the Asset Build simply just take what is there and work with it? Thanks ...
     
  25. diggerjohn

    diggerjohn

    Joined:
    Apr 28, 2009
    Posts:
    60
    What I am trying to determine is how to successfully bring in a custom character. What are the rig requirements?
    I have tried multiple times.
    In the Asset Builder I have selected Biped and then set my Character as the Target.
    Doesn't seem to have any effect.
    Would appreciate any guidance at all.
     
    Last edited: Oct 18, 2020
  26. Shturmovik

    Shturmovik

    Joined:
    Nov 5, 2014
    Posts:
    29
    Sounds to me like you have this asset (https://assetstore.unity.com/packages/tools/physics/kinematic-character-controller-99131) confused with Unity's Kinematica?
     
  27. diggerjohn

    diggerjohn

    Joined:
    Apr 28, 2009
    Posts:
    60
    Last edited: Oct 19, 2020
  28. Shturmovik

    Shturmovik

    Joined:
    Nov 5, 2014
    Posts:
    29
    Ah - this thread is about the Kinematic Character Controller asset I linked to.

    Sorry if I didn't make that clear.
     
  29. diggerjohn

    diggerjohn

    Joined:
    Apr 28, 2009
    Posts:
    60
    Ooo ... that would explain a lot, thank you.
     
  30. closingiris

    closingiris

    Joined:
    May 18, 2019
    Posts:
    7
    Hello @PhilSA, I am making a game with non-traditional gravity, and after purchasing your controller noticed that the demo scene character controller has some serious defects when placed on the sphere. See the link below for demonstration video.

     
    Last edited: Oct 24, 2020
  31. closingiris

    closingiris

    Joined:
    May 18, 2019
    Posts:
    7

    If I were you I would not rotate, I would change the shape of the capsule so that it was wide.
     
    kirbyderby2000 likes this.
  32. kirbyderby2000

    kirbyderby2000

    Joined:
    Apr 28, 2017
    Posts:
    35
    That was my ideal solution but the problem introduced was that the collider would extend into undesired directions. When prone, the capsule collider should only extend forwards, not backwards, left, or right; bumping up the capsule collider's radius extends the shape in all these directions. When I was testing this method my dynamic colliders got pushed away from the KCC's sides because its collider size ended up being way bigger than intended. The only way to get the KCC collider to occupy the desired space while prone is to rotate it as shown in the picture.
     
  33. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    Hello, I am in the process of converting my game from the Unity character controller to KCC. KCC has one major change that I dislike:

    When the Unity character controller steps up onto a ledge, vertical velocity is added, and the horizontal velocity remains constant. This results in a nice smooth feeling, as if the character is an athlete to whom the step is barely an obstacle. With KCC, the horizontal velocity is reduced during step up. This results in a jarring stop in the motion, as if the character is frail and feeble and has to pause to take the step before continuing forward.

    I really dislike this change, is there a way to make steps feel like they do with the Unity character controller? I've tried messing around with the step settings and ledge settings but nothing seems to work.
     
  34. rufio

    rufio

    Joined:
    Nov 21, 2012
    Posts:
    4
    Actually came here to ask the very same thing, each step makes the character halt which is not desired for "old school" movement, it looks to me the issue is that the step handling code is called last in order and no remainder of the desired movement is added so the horizontal velocity is set to zero.

    Anyone who has solved this? I am looking into it but kind of hard to track down the exact culprit.
     
    cxode likes this.
  35. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    @rufio I'll post here and ping you if I manage to solve it. I've tried many things and dug pretty deep into the code but no luck so far. I'm probably going to email Phil soon, since he doesn't seem to be checking this thread anymore.
     
  36. rufio

    rufio

    Joined:
    Nov 21, 2012
    Posts:
    4
    Thanks, will do the same if I find something out!

    Meanwhile I caved in and made one based on the Unity character controller which means it can't rotate, but it works for what I need it for, feel free to use it. A bit sloppy and needs organizing bit it works OK (there is one edge case where I get jittering, but that is standing underneath a sloping plane pressing inwards at the same time as sliding against a wall, so not that frequent).


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [RequireComponent(typeof(CharacterController))]
    6. [RequireComponent(typeof(Rigidbody))]
    7. public class UnityCharacterController : MonoBehaviour
    8. {
    9.     [SerializeField] float jumpHeight = 2.1f;
    10.     [SerializeField] float gravity = 20f;
    11.     [SerializeField] Transform playerCamera;
    12.     [SerializeField] Vector3 _moveVelocity;
    13.     [SerializeField] float speed;
    14.     [SerializeField] float stepHeight = 0.5f;
    15.     [SerializeField] float skinWidth = 0.02f;
    16.     [SerializeField] CharacterController cC;
    17.     [SerializeField] Rigidbody rB;
    18.     [SerializeField] RaycastHit groundHit;
    19.     [SerializeField] bool snapToGround = true;
    20.     [SerializeField] float groundSnapDistance = 0.3f;
    21.     [SerializeField] LayerMask moveLayerMask;
    22.     [SerializeField] LayerMask groundLayerMask;
    23.     [SerializeField] bool bIsGrounded = false;
    24.     [SerializeField] Vector3 _groundVelocity;
    25.     [SerializeField] Vector3 _externalVelocity;
    26.     [SerializeField] bool pressedJump = false;
    27.  
    28.     public bool ccGrounded;
    29.  
    30.     Vector2 moveInput;
    31.     private const string MouseXInput = "Mouse X";
    32.     private const string MouseYInput = "Mouse Y";
    33.     private const string MouseScrollInput = "Mouse ScrollWheel";
    34.     private const string HorizontalInput = "Horizontal";
    35.     private const string VerticalInput = "Vertical";
    36.     float m_CameraVerticalAngle;
    37.     float rotationSpeed = 2.0f;
    38.     float jumpSpeed;
    39.  
    40.     private void OnValidate()
    41.     {
    42.         if(cC == null)
    43.         {
    44.             cC = GetComponent<CharacterController>();
    45.             if(cC == null)
    46.             {
    47.                 cC = gameObject.AddComponent<CharacterController>();
    48.             }
    49.         }
    50.         cC.stepOffset = stepHeight;
    51.         cC.skinWidth = skinWidth;
    52.         cC.slopeLimit = 60.0f;
    53.         cC.hideFlags = HideFlags.NotEditable;
    54.  
    55.         if(rB == null)
    56.         {
    57.             rB = GetComponent<Rigidbody>();
    58.             if(rB == null)
    59.             {
    60.                 rB = gameObject.AddComponent<Rigidbody>();
    61.             }
    62.         }
    63.         rB.isKinematic = true;
    64.         rB.useGravity = false;
    65.         rB.hideFlags = HideFlags.NotEditable;
    66.  
    67.         jumpSpeed = Mathf.Sqrt(2f * gravity * jumpHeight);
    68.     }
    69.  
    70.     // Start is called before the first frame update
    71.     void Start()
    72.     {
    73.  
    74.     }
    75.  
    76.     // Update is called once per frame
    77.     void Update()
    78.     {
    79.         CollectInput();
    80.     }
    81.  
    82.     private void FixedUpdate()
    83.     {
    84.         float deltaTime = Time.fixedDeltaTime;
    85.         //Nudge();
    86.         ProbeGround(deltaTime);
    87.         Move(deltaTime);
    88.     }
    89.  
    90.     void CollectInput()
    91.     {
    92.         moveInput.y = Input.GetAxisRaw(VerticalInput);
    93.         moveInput.x = Input.GetAxisRaw(HorizontalInput);
    94.  
    95.         // Create the look input vector for the camera
    96.         float mouseLookAxisUp = Input.GetAxisRaw(MouseYInput);
    97.         float mouseLookAxisRight = Input.GetAxisRaw(MouseXInput);
    98.         Vector3 lookInputVector = new Vector3(mouseLookAxisRight, mouseLookAxisUp, 0f);
    99.  
    100.         transform.Rotate(new Vector3(0f, (lookInputVector.x * rotationSpeed), 0f), Space.World);
    101.  
    102.         // add vertical inputs to the camera's vertical angle
    103.         m_CameraVerticalAngle += lookInputVector.y * rotationSpeed;
    104.         // limit the camera's vertical angle to min/max
    105.         m_CameraVerticalAngle = Mathf.Clamp(m_CameraVerticalAngle, -89.99f, 89.99f);
    106.         playerCamera.transform.localEulerAngles = new Vector3(m_CameraVerticalAngle, playerCamera.transform.localEulerAngles.y, playerCamera.transform.localEulerAngles.z);
    107.  
    108.         if(bIsGrounded && !pressedJump)
    109.         {
    110.             pressedJump = Input.GetKeyDown(KeyCode.Space);
    111.         }      
    112.     }
    113.  
    114.     void Nudge()
    115.     {
    116.         Vector3 nudge = Random.insideUnitSphere * skinWidth;
    117.         cC.Move(nudge);
    118.     }
    119.  
    120.     void ProbeGround(float deltaTime)
    121.     {
    122.         if(_moveVelocity.y > 0.0f)
    123.         {
    124.             return;
    125.         }
    126.  
    127.         _groundVelocity = Vector3.zero;
    128.         Vector3 probePos = transform.position - transform.up * (cC.height * 0.5f - cC.radius);
    129.         bIsGrounded = Physics.SphereCast(probePos, cC.radius, -transform.up, out groundHit, 1.0f, groundLayerMask);
    130.  
    131.         //gets correct normal, might be good to keep
    132.         /*if(bIsGrounded)
    133.         {
    134.             RaycastHit hit;
    135.             if(Physics.Raycast(probePos, groundHit.point - probePos, out hit, 1.0f, groundLayerMask))
    136.             {
    137.                 groundHit.normal = hit.normal;
    138.             }
    139.         }*/
    140.  
    141.         if (bIsGrounded)
    142.         {
    143.             Debug.DrawLine(groundHit.point, groundHit.point + groundHit.normal);
    144.             if (groundHit.distance > groundSnapDistance + skinWidth)
    145.             {
    146.                 bIsGrounded = false;
    147.             }
    148.             else if (groundHit.normal.y < 0.5f) //60 degrees
    149.             {
    150.                 //we still add any ground velocity since we want to slide off edge properly
    151.                 if (groundHit.collider.attachedRigidbody != null)
    152.                 {
    153.                     _groundVelocity = groundHit.collider.attachedRigidbody.velocity;
    154.                 }
    155.                 bIsGrounded = false;
    156.             }
    157.             else
    158.             {
    159.                 _moveVelocity.y = 0.0f;
    160.                 if(snapToGround)
    161.                 {
    162.                     cC.enabled = false;
    163.                     transform.position -= transform.up * (groundHit.distance - skinWidth);
    164.                     cC.enabled = true;
    165.                 }              
    166.                 if (groundHit.collider.attachedRigidbody != null)
    167.                 {
    168.                     _groundVelocity = groundHit.collider.attachedRigidbody.velocity;
    169.                 }
    170.             }                    
    171.         }
    172.     }
    173.  
    174.     void Move(float deltaTime)
    175.     {
    176.         if (!bIsGrounded)
    177.         {
    178.             _moveVelocity.y -= 20.0f * deltaTime;
    179.         }
    180.  
    181.         if (bIsGrounded)
    182.         {
    183.             GroundMove(ref _moveVelocity, deltaTime, pressedJump);
    184.             if(pressedJump)
    185.             {
    186.                 pressedJump = false;
    187.                 bIsGrounded = false;
    188.             }
    189.          
    190.         }
    191.         else
    192.         {
    193.             AirMove(ref _moveVelocity, deltaTime);
    194.         }      
    195.  
    196.         Vector3 _totalVelocity = _moveVelocity + _groundVelocity + _externalVelocity;
    197.  
    198.         if(_moveVelocity.y > 0.0f)
    199.         {
    200.             cC.stepOffset = 0.0f;
    201.         }
    202.         else
    203.         {
    204.             cC.stepOffset = stepHeight;
    205.         }
    206.  
    207.         Vector3 startPos = transform.position;
    208.         cC.Move(_totalVelocity * deltaTime);
    209.         Vector3 endPos = transform.position;
    210.  
    211.         Vector3 realMoveVel = (endPos - startPos) / deltaTime;
    212.         realMoveVel -= (_groundVelocity + _externalVelocity);
    213.  
    214.         ccGrounded = cC.isGrounded;
    215.  
    216.         if(bIsGrounded)
    217.         {
    218.             realMoveVel.y = 0.0f;
    219.         }
    220.         else if(realMoveVel.y != 0.0f)
    221.         {
    222.             realMoveVel.y = _moveVelocity.y;
    223.         }
    224.         _moveVelocity = realMoveVel;
    225.  
    226.         Vector3 flatVel = realMoveVel;
    227.         flatVel.y = 0.0f;
    228.  
    229.         //reset external velocity
    230.         _externalVelocity = Vector3.zero;
    231.     }
    232.  
    233.     public void AddExternalVelocity()
    234.     {
    235.  
    236.     }
    237.  
    238.     public void Teleport(Transform destination)
    239.     {
    240.         cC.enabled = false;
    241.         transform.position = destination.position;
    242.         transform.rotation = destination.rotation;
    243.         _moveVelocity = destination.TransformDirection(_moveVelocity);
    244.         cC.enabled = true;
    245.     }
    246.  
    247.     #region QUAKE
    248.     //ALL THINGS QUAKE
    249.     // Movement stuff
    250.     float moveSpeed = 15f;  // Ground move speed
    251.     float runAcceleration = 20f;   // Ground accel
    252.     float runDeacceleration = 20f;   // Deacceleration that occurs when running on the ground
    253.  
    254.     float airAcceleration = 5.0f;  // Air accel
    255.     float airDeacceleration = 5.0f;    // Deacceleration experienced when opposite strafing
    256.     float airControl = 10.9f;  // How precise air control is
    257.  
    258.     float sideStrafeAcceleration = 5f;   // How fast acceleration occurs to get up to sideStrafeSpeed when side strafing
    259.     float sideStrafeSpeed = 10f;    // What the max speed to generate when side strafing
    260.  
    261.  
    262.     float friction = 10.6f;  // Ground friction
    263.  
    264.     private void AirMove(ref Vector3 currentVelocity, float deltaTime)
    265.     {
    266.         Vector3 newVelocity = currentVelocity;
    267.         Vector3 targetDir;
    268.         float accel;
    269.         targetDir = new Vector3(moveInput.x, 0, moveInput.y);
    270.         targetDir = transform.TransformDirection(targetDir);
    271.  
    272.         targetDir.Normalize();
    273.         float targetSpeed = targetDir.magnitude * moveSpeed;
    274.  
    275.         // CPM: Aircontrol
    276.         float wishspeed2 = targetSpeed;
    277.         if (Vector3.Dot(newVelocity, targetDir) < 0)
    278.         {
    279.             accel = airDeacceleration;
    280.         }
    281.         else
    282.         {
    283.             accel = airAcceleration;
    284.         }
    285.  
    286.         // If the player is ONLY strafing left or right
    287.         if (moveInput.y == 0 && moveInput.x != 0)
    288.         {
    289.             if (targetSpeed > sideStrafeSpeed)
    290.             {
    291.                 targetSpeed = sideStrafeSpeed;
    292.             }
    293.             accel = sideStrafeAcceleration;
    294.         }
    295.  
    296.         Accelerate(ref newVelocity, targetDir, targetSpeed, accel, deltaTime);
    297.  
    298.         if (airControl > 0)
    299.         {
    300.             AirControl(ref newVelocity, targetDir, wishspeed2, deltaTime);
    301.         }
    302.  
    303.         // Apply gravity
    304.         //playerVelocity.y -= gravityDownForce * deltaTime;
    305.  
    306.         currentVelocity = newVelocity;
    307.     }
    308.  
    309.     /// <summary>
    310.     /// * Air control occurs when the player is in the air, it allows
    311.     /// players to move side to side much faster rather than being
    312.     /// 'sluggish' when it comes to cornering.
    313.     /// </summary>
    314.     /// <param name="wishdir"></param>
    315.     /// <param name="wishspeed"></param>
    316.     private void AirControl(ref Vector3 newVelocity, Vector3 wishdir, float wishspeed, float deltaTime)
    317.     {
    318.         float zspeed;
    319.         float speed;
    320.         float dot;
    321.         float k;
    322.         //float i;
    323.  
    324.         // Can't control movement if not moving forward or backward
    325.         if (moveInput.y == 0 || wishspeed == 0)
    326.         {
    327.             return;
    328.         }
    329.  
    330.         zspeed = newVelocity.y;
    331.         newVelocity.y = 0.0f;
    332.         // Next two lines are equivalent to idTech's VectorNormalize()
    333.         speed = newVelocity.magnitude;
    334.         newVelocity.Normalize();
    335.  
    336.         dot = Vector3.Dot(newVelocity, wishdir);
    337.         k = 32;
    338.         k *= airControl * dot * dot * deltaTime;
    339.  
    340.         // Change direction while slowing down
    341.         if (dot > 0)
    342.         {
    343.             newVelocity.x = newVelocity.x * speed + wishdir.x * k;
    344.             newVelocity.y = newVelocity.y * speed + wishdir.y * k;
    345.             newVelocity.z = newVelocity.z * speed + wishdir.z * k;
    346.  
    347.             newVelocity.Normalize();
    348.         }
    349.  
    350.         newVelocity.x *= speed;
    351.         newVelocity.y = zspeed; // Note this line
    352.         newVelocity.z *= speed;
    353.     }
    354.  
    355.     /// <summary>
    356.     /// Called every frame when the engine detects that the player is on the ground
    357.     /// </summary>
    358.     private void GroundMove(ref Vector3 currentVelocity, float deltaTime, bool doJump)
    359.     {
    360.         Vector3 wishdir, newVelocity = currentVelocity;
    361.         //Vector3 wishvel;
    362.  
    363.         bool wishJump = doJump;
    364.         // Do not apply friction if the player is queueing up the next jump
    365.         if (!wishJump)
    366.         {
    367.             ApplyFriction(ref newVelocity, 1.0f, deltaTime);
    368.         }
    369.         else
    370.         {
    371.             ApplyFriction(ref newVelocity, 0f, deltaTime);
    372.         }
    373.  
    374.         wishdir = new Vector3(moveInput.x, 0, moveInput.y);
    375.         wishdir = transform.TransformDirection(wishdir);
    376.         wishdir.Normalize();
    377.  
    378.  
    379.         float wishspeed = wishdir.magnitude;
    380.         wishspeed *= moveSpeed;
    381.  
    382.         Accelerate(ref newVelocity, wishdir, wishspeed, runAcceleration, deltaTime);
    383.  
    384.         // Reset the gravity velocity
    385.         newVelocity.y = 0;
    386.  
    387.         if (wishJump)
    388.         {
    389.             newVelocity.y = jumpSpeed;
    390.             wishJump = false;
    391.         }
    392.         currentVelocity = newVelocity;
    393.     }
    394.  
    395.     /// <summary>
    396.     /// Applies friction to the player, called in both the air and on the ground
    397.     /// </summary>
    398.     /// <param name="t"></param>
    399.     private void ApplyFriction(ref Vector3 newVelocity, float t, float deltaTime)
    400.     {
    401.         Vector3 vec = newVelocity;
    402.  
    403.         float speed;
    404.         float newspeed;
    405.         float control;
    406.         float drop;
    407.  
    408.         vec.y = 0.0f;
    409.         speed = vec.magnitude;
    410.         drop = 0.0f;
    411.  
    412.         // Only if the player is on the ground then apply friction
    413.         if (bIsGrounded)
    414.         {
    415.             //control = speed < runDeacceleration ? runDeacceleration : speed;
    416.             if (moveInput.y == 0.0f && moveInput.x == 0.0f)
    417.             {
    418.                 drop = 0.2f * runDeacceleration * friction * deltaTime * t;
    419.             }
    420.             else
    421.             {
    422.                 drop = runDeacceleration * friction * deltaTime * t;
    423.             }
    424.  
    425.         }
    426.  
    427.         newspeed = speed - drop;
    428.  
    429.         if (newspeed < 0)
    430.         {
    431.             newspeed = 0;
    432.         }
    433.         if (speed > 0)
    434.         {
    435.             newspeed /= speed;
    436.         }
    437.  
    438.         newVelocity.x *= newspeed;
    439.         // playerVelocity.y *= newspeed;
    440.         newVelocity.z *= newspeed;
    441.     }
    442.  
    443.     /// <summary>
    444.     /// Calculates wish acceleration based on player's cmd wishes
    445.     /// </summary>
    446.     private void Accelerate(ref Vector3 newVelocity, Vector3 targetDir, float targetSpeed, float accel, float deltaTime)
    447.     {
    448.         float currentspeed = Vector3.Dot(newVelocity, targetDir);
    449.         float addspeed = targetSpeed - currentspeed;
    450.  
    451.         if (addspeed <= 0)
    452.         {
    453.             return;
    454.         }
    455.  
    456.         float accelspeed = accel * deltaTime * targetSpeed;
    457.  
    458.         if (accelspeed > addspeed)
    459.         {
    460.             accelspeed = addspeed;
    461.         }
    462.  
    463.         newVelocity.x += accelspeed * targetDir.x;
    464.         newVelocity.z += accelspeed * targetDir.z;
    465.     }
    466.     #endregion
    467.  
    468.     void OnDrawGizmosSelected()
    469.     {
    470.         // Draw a yellow sphere at the transform's position
    471.         /*Gizmos.color = Color.red;
    472.         Vector3 newPos = new Vector3(transform.position.x, groundHit.point.y +  0.5f / 1.42f, transform.position.z);
    473.         Gizmos.DrawWireCube(newPos, Vector3.one / 1.42f);*/
    474.         Vector3 probePos = transform.position - transform.up * (cC.height * 0.5f - cC.radius);
    475.         Gizmos.DrawWireSphere(probePos, cC.radius);
    476.     }
    477. }
    478.  
    And then for any moving platform I use something like this (also works for conveyer belts etc.):
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [RequireComponent(typeof(Rigidbody))]
    6. public class MovingPlatformNew : MonoBehaviour
    7. {
    8.     [SerializeField] GameObject goalNode;
    9.     [SerializeField] [HideInInspector] Vector3 goal;
    10.     [SerializeField] [HideInInspector] Vector3 start;
    11.     [SerializeField] float speed = 0.5f;
    12.     [SerializeField] [HideInInspector] float movementTime;
    13.     [SerializeField] [HideInInspector] float movementTimer;
    14.     [SerializeField] [HideInInspector] int direction = 1;
    15.     [SerializeField] [HideInInspector] Rigidbody rB;
    16.     [SerializeField] [HideInInspector] float freezeTimer;
    17.  
    18.     private void OnValidate()
    19.     {
    20.         if (goalNode == null)
    21.         {
    22.             goalNode = new GameObject();
    23.             goalNode.transform.parent = this.transform;
    24.             goalNode.transform.localPosition = Vector3.zero;
    25.             goalNode.name = "GOAL_NODE";
    26.         }
    27.  
    28.         start = transform.position;
    29.         goal = goalNode.transform.position;
    30.         movementTime = Vector3.Distance(start, goal) / speed;
    31.      
    32.         if (rB == null)
    33.         {
    34.             rB = GetComponent<Rigidbody>();
    35.             if (rB == null)
    36.             {
    37.                 gameObject.AddComponent(typeof(Rigidbody));
    38.                 rB = GetComponent<Rigidbody>();
    39.             }
    40.         }
    41.         rB.isKinematic = true;
    42.         rB.hideFlags = HideFlags.NotEditable;
    43.     }
    44.  
    45.     // Start is called before the first frame update
    46.     void Start()
    47.     {
    48.      
    49.     }
    50.  
    51.     public void Freeze(float timeToFreeze)
    52.     {
    53.         freezeTimer = timeToFreeze;
    54.     }
    55.  
    56.     // Update is called once per frame
    57.     public void FixedUpdate()
    58.     {
    59.         float deltaTime = Time.fixedDeltaTime;
    60.         if(freezeTimer > 0.0f)
    61.         {
    62.             freezeTimer -= deltaTime;
    63.             return;
    64.         }
    65.         movementTimer += deltaTime * direction;
    66.         if (movementTimer <= 0f || movementTimer >= movementTime)
    67.         {
    68.             movementTimer = Mathf.Clamp(movementTimer, 0f, movementTime);
    69.             direction *= -1;
    70.         }
    71.         Vector3 goalPosition = Vector3.Lerp(start, goal, movementTimer / movementTime);
    72.         rB.MovePosition(goalPosition);
    73.     }
    74. }
    75.  
    EDIT: forgot one thing, you need to setup interpolation for the camera, but that should be a minor thing.
     
    Last edited: Nov 17, 2020
  37. tuf_dev

    tuf_dev

    Joined:
    Jan 1, 2015
    Posts:
    8
    How many characters can this asset handle without significant performance loss?
     
  38. theguywiththelemon

    theguywiththelemon

    Joined:
    Dec 10, 2017
    Posts:
    2
    Hey, I have a character with gravity and additive horizontal velocity (meaning its not set each frame, instead is added to and subtracted from) and when he lands on the ground after falling, it seems like his vertical velocity is redirected forward, giving and large, an unintended boost in horizontal velocity. I suspect this is the char controller resolving the collision with the ground and pushing the capsule collider out of the ground? Any tips for stopping this from happening? I am already not enabling gravity when grounded. Thanks!
     
  39. trueh

    trueh

    Joined:
    Nov 14, 2013
    Posts:
    74
    Hi:

    This is an easy one. We are using assembly definitions and references in our project to improve compilation times. KCC does not including any assembly definition so we are unofficialy creating them ourselves. May you be so kind of including assembly definitions in KCC for the next update? This way we will not to have to re-create them each time we install or update KCC.

    Thank you and best regards.
     
  40. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    I sent a support email about this, and less than 24 hours later Phil send a response. He said that he would try to add my desired stepping behavior as an optional feature, though he made no promises this would be possible, and he told me he'd get back to me by the end of the week. Tagging @rufio since you also wanted to know about this.
     
  41. WaaghMan

    WaaghMan

    Joined:
    Jan 27, 2014
    Posts:
    245
    Hi! Just purchased this component and managed to integrate in our game. Not a straightforward task, but not extremely hard either!

    We found an issue with character landing on ground with very little horizontal velocity, but lots of vertical one, just like the one reported by @theguywiththelemon, and found the culprit:

    On the HandleVelocityProjection() method, this line:

    Code (csharp):
    1. velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude;
    There, there's a multiplication by velocity.magnitude that causes the projected velocity to conserve all energy, no matter the angle of landing/collision.

    I know it's meant to redirect horizontal velocity up/down when on a slope, but when landing on a flat surface at high speeds, it causes a sudden reposition and weird feeling when landing.

    Since our game also has slopes (approximately 45º), we can't just remove the multiplication, so I did the following change:

    Code (csharp):
    1.  
    2. // Make it so landing on floors doesn't redirect all movement forward
    3. if (Vector3.Dot(velocity.normalized, obstructionNormal) < -0.75f)
    4.     velocity = GetDirectionTangentToSurface(velocity, obstructionNormal);
    5. else
    6.     velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude;
    7.  
    This way, when facing normals that are almost completely opposite of our velocity, we don't reproject the vector, but when walking on upwards slopes, we can still move forward instead of colliding on the ground.

    It's an almost arbitrary value so I would prefer a better solution, such as not reprojecting velocity on the Y component (just the XZ values), but at least it works.
     
    TomatoLamp and cxode like this.
  42. papathor

    papathor

    Joined:
    Oct 8, 2012
    Posts:
    41
    Has anyone successfully gotten an AI Kinematic Character Controller to work with the A* Pathfinding Project, instead of Unity's built in pathfinding? I'd appreciate some guidance on how to get a KCC to use A*.
     
  43. tkg_dhughes

    tkg_dhughes

    Joined:
    Jan 4, 2019
    Posts:
    3
    Hi all,

    I'm interested in integrating these important fixes in versions 3.2 and 3.3 into a fairly heavily modified version of the 3.1 motor:
    • Fixed tunneling issue (going through geometry)
    • Fixed slowing down when moving in air against a corner
    Due to the stage of the project, I can't wholesale update the package so I am trying to distill the fixes to the core changes to minimise the blast radius.
    Does anyone know the actual changes made? and if not, is it possible to download versions other than the latest so I can do a manual diff?

    Thanks in advance
     
  44. tkg_dhughes

    tkg_dhughes

    Joined:
    Jan 4, 2019
    Posts:
    3
    FWIW I have managed to significantly reduce the blast radius of the tunneling fix by only adding the initial penetration and overlap checks early in InternalCharacterMove. I can elaborate more if anyone requires it but I anticipate that few other people will have to do this sort of bisection!
     
  45. FcsVorfeed

    FcsVorfeed

    Joined:
    Aug 15, 2014
    Posts:
    50
    the newest version, If the ceiling is a mesh with one side, the character will be stuck when jumping @PhilSA
     
  46. michalcichra

    michalcichra

    Joined:
    Aug 26, 2020
    Posts:
    6
    Hi,

    I found a super weird issue when two player characters collide. Their hit normals go into some insane numbers.
    The code is trivial, just add forces as shown in the example character controller.

    Code (CSharp):
    1.     public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
    2.         ref HitStabilityReport hitStabilityReport)
    3.     {
    4.         if (hitCollider.gameObject.CompareTag("Player"))
    5.         {
    6.             ProcessPlayerCollision(hitCollider, hitNormal, hitPoint);
    7.         }
    8.  
    9.     }
    10.  
    11.     public void ProcessPlayerCollision(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint)
    12.     {
    13.         Debug.LogFormat("Player Collision Normal: {0} Point: {1} Force: {2}", hitNormal, hitPoint, hitNormal * BounceForce);
    14.         Assert.IsTrue(hitNormal.magnitude < 10000, "hit normal vector is buggy and has bullshit numbers");
    15.  
    16.         var playerCharacterController = hitCollider.GetComponent<PlayerCharacterController>();
    17.  
    18.         playerCharacterController.AddVelocity(hitNormal * (-1 * BounceForce));
    19.  
    20.         AddVelocity(hitNormal * BounceForce);
    21.     }

    But when I jump with both those players and move them against each other in the air I get the following collisions:


    Player Collision Normal: (1.0, 0.0, 0.0) Point: (0.1, 3.0, 0.0) Force: (10.0, 0.0, 0.0)
    Player Collision Normal: (1.0, -0.1, 0.0) Point: (0.0, 2.9, 0.0) Force: (9.9, -1.2, 0.0)
    Player Collision Normal: (-10661140000000000000000.0, 0.0, 0.0) Point: (0.5, 2.3, 0.0) Force: (-106611400000000000000000.0, 0.0, 0.0)


    I assume it has to do something with interpolation as it works with the interpolation disabled.
     
    Gooren likes this.
  47. blai30

    blai30

    Joined:
    Aug 18, 2015
    Posts:
    9
    Can I use this asset for 2D (not 2.5D) platformer? It doesn't look like there is 2D functionality out of the box, however is it possible to implement one myself by inheriting a class?
     
  48. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    Good catch! The author responds over e-mail much much faster, so I would recommend contacting him about this issue that way.
     
  49. rtargosz

    rtargosz

    Joined:
    Aug 22, 2012
    Posts:
    17
    Anybody using the new Input System with KCC? I've been experiencing some keyboard input event loss or lag, even with frame rates in my scene up over 100 FPS. I'm wondering if changing Project Settings->Input System Package->Update Mode from Dynamic Update to Fixed Update may help since KCC does a lot of processing using Fixed Update by default?
     
  50. rtargosz

    rtargosz

    Joined:
    Aug 22, 2012
    Posts:
    17
    I've spent the last few hours trying to debug this with a few different options. It looks like the events are coming in fine with the new Input System package, but that (of course) fixed update will only take one event of each type per frame, which is bad at lower frame-rates for input handling. I've therefore left the project setting at dynamic update.

    I then tried both Update() and LateUpdate(), and found that for some reason LateUpdate() works better for my case. I'm taking the input, passing it to KCC via a method like the example project SetInputs() one, then kicking off animations in AfterCharacterUpdate().

    I was previously using an upper body avatar mask to handle some interactions like casting a spell or interacting with the environment. In the upper body layer, I had a null animation as the default, then used the Any State event to transition to the appropriate animation when the AfterCharacterUpdate() method set the correct parameter.

    I have changed this so that all transitions come from the null, default animation on the upper body layer, using the parameters to handle which animation to play. In addition, the transitions back to null are based on 'has exit time', but I truncate it down to the grace period of my action (e.g. 0.25s), have a crazy short transition duration (.01s) and set the interruption source to Current State then Next State with ordered interruption enabled.

    After all of this, my player can now interact as quickly as they can press the keys, provided the grace period has expired, and the appropriate animations will be shown. Hopefully this is helpful to others!
     
    Deozaan likes this.