Search Unity

[Released] Kinematic Character Controller

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

  1. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Some parameters on the motor make ground snapping prevented on ledges when having certain velocities or distances from a ledge. This variable tells you if the snapping was prevented this frame

    That specific chunk of code is meant for cases like this:
    https://i.gyazo.com/c758f39eb0e9df03d472b1c757c481b7.mp4

    The snapping to ground is being prevented at the top of the triangle in order to give you a proper "launching off slope" trajectory. In this case, the ground normal we use for calculating our launching velocity is the ground normal from the slope we are coming from (right side of the screen)
     
  2. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    This is how you'd get the collision relative velocity:
    Code (CSharp):
    1. public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
    2.         {
    3.             Rigidbody r = hitCollider.attachedRigidbody;
    4.             if(r)
    5.             {
    6.                 Vector3 relativeVel = Vector3.Project(r.velocity, hitNormal) - Vector3.Project(Motor.Velocity, hitNormal);
    7.             }
    8.         }
     
  3. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Thanks for bringing this up to me, I will investigate and see what I can find
     
  4. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    There's no integration of the new input system, but it's pretty straightforward to implement with KCC.

    All the input is currently handled in ExamplePlayer. Simply removing the legacy input handling from that class and replacing it with new input system will do the trick
     
    slimshader likes this.
  5. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    934
    Can you please the "sky runner" an example project included in this package,it will help a lot :)
     
  6. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I can send the project to those who give me their KCC invoice # via PM

    I'd like to avoid shipping it with KCC itself due to too much bloat, unfinished code, absence of documentation, etc...
     
    Last edited: May 4, 2019
    Ruchir likes this.
  7. Sanyol

    Sanyol

    Joined:
    Jan 28, 2013
    Posts:
    24
    Hello @PhilSA,
    do you think it will be possible to have Capsule Collider but with different XYZ sizes ? I want to align it to the car model but the there is no way to align it correctly (only width or length can be correct).

    One more question - Is it possible to align character to slopes ?
     
    Last edited: May 5, 2019
  8. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    This is unfortunately not possible because KCC needs to work with the assumption that the portion of the collider that is in contact with the ground is a hemisphere at many points in its calculations. One workaround would be to just put a KCC sphere at the front of your character object and then put another collider in the back to fill the rest of the space, like this:

    (green is KCC capsule, blue is other collider(s))

    By making the KCC capsule ignore the blue collider and adding code that makes any blue collider overlaps "push away" the KCC capsule, I think this could work. But this is a 100% untested idea

    Yes:


    I've attached a modified version of ExampleCharacterController that supports this. The only addition compared to the one that comes by default with KCC is under the "// HERE" comment in UpdateRotation()
     

    Attached Files:

  9. adouce

    adouce

    Joined:
    Feb 19, 2019
    Posts:
    6
    Thanks for your help !

    Do you have any advice about how to implement this :
    I am trying to have a GO, child of the KCC, that would constantly be stuck on the ground. So basically, it would follow the character's movement, expect for the jumps. I'm trying to achieve it through a raycast in LateUpdate (after KCC and movers have moved), but I get stuttering when changing gravity, or when I'm on a rotating mover.

    I feel it is because of the Update / Fixed Update difference, as I don't get it if I disable Interpolation.
     
  10. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,444
    Did you set your script ordering to call your script AFTER all other scripts in LateUpdate?
     
  11. ahmedmohiappsinnovate

    ahmedmohiappsinnovate

    Joined:
    Apr 6, 2019
    Posts:
    1
    Hello @PhilSA
    First thanks for the awesome asset it works great :)
    I have a question/issue regarding the physics mover and actually putting just a rigidbody on the platform, so the setup is normal platform with physics mover and example moving platform . and have a cube with rigidbody on it (it's not child to the platform)
    i noticed that the cube moves a bit with the platform especially if the speed is low but i didn't find any part in the code that do this.and the problem is that the moving of the cube isn't accurate and i have my own system to handle passengers on platforms or even cube on top of a cube so i don't want the physics mover to move this cube.but i can't find where to stop it or even how is it working to modify if possible xD
    Thanks :)
     
  12. Sanyol

    Sanyol

    Joined:
    Jan 28, 2013
    Posts:
    24
    Thank you @PhilSA ! I will make sure to write a review in near future :)
     
    PhilSA likes this.
  13. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    In your LateUpdate, do you raycast from Motor.Transform.position? I would suggest doing this since all other positions (Motor.TransientPosition, rigidbody position, etc...) are only updated in FixedUpdate

    Here's the interpolation code in KinematicCharacterSystem. As you can see, all it affects is the actual Transform position/rotation:
     
  14. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    This happens because moving platforms are kinematic rigidbodies moving with MovePosition(). When a kinematic rigidbody moves with MovePosition, it takes friction into account, and so it drags any dynamic rigidbody sitting on top along with it.

    To prevent this, you'll need to edit the sources of KCC. But I'll add this as an option in the next release (I hadn't thought about this use case yet)

    The fix you need to do is in KinematicCharacterSystem.PostSimulationInterpolationUpdate()
    At the end of that function, we have a for loop that moves all movers with MovePosition and MoveRotation. Replace these two lines with simply moving with .position and .rotation and it'll do the trick:
     
  15. adouce

    adouce

    Joined:
    Feb 19, 2019
    Posts:
    6
    I am pretty sure the issue is with the movers actually, not with the starting point of the raycast is not the issue. I took three videos to explain :

    First one is what i want, the red circle follows the character but doesn't jump with him :
    https://gyazo.com/6e72a0573836e960bfbccf171cf03346

    Second one is when the character rides a mover. The red circle jitters, and doesn't properly follow the ground :
    https://gyazo.com/75b8ae4e49f0efd5f25c510574a43ac7
    Same issue, different point of view :
    https://gyazo.com/cef93f259c2acca7715bb135de9c4994


    So far I'm using :
    Code (CSharp):
    1.     private void LateUpdate()
    2.     {
    3.         if (Physics.Raycast(playerTransform.position + playerTransform.rotation * new Vector3(0,1,0), //  Motor.Capsule.center,
    4.                             -playerTransform.up,
    5.                             out RaycastHit hit,
    6.                             SpellMaxGroundDistance,
    7.                             SpellGroundLayer,
    8.                             QueryTriggerInteraction.Ignore))
    9.         {
    10.             transform.rotation = Quaternion.LookRotation(Vector3.ProjectOnPlane(playerTransform.forward, hit.normal), hit.normal);
    11.             transform.position = hit.point + hit.normal * SpellGroundDistance;
    12.         }
    13.     }
    Edit : Ok I might have got it. At the end of CustomInterpolationUpdate(), you call mover.Transform.SetPositionAndRotation(...). So the transform of the mover is updated, but not its collider. So, when I cast a ray against the collider during LateUpdate, I collide against the old position of the collider.

    Edit2 : During FixedUpdate, you call mover.Transform.SetPositionAndRotation(...) then call Physics.SyncTransforms(). However, during Update, you also call mover.Transform.SetPositionAndRotation(...), but you do not call Physics.SyncTransforms(). Because of that, the collider is not updated when LateUpdate arrives.

    Judging from this thread, I guess having only one SyncTransforms is intentional. I could fix my problem by setting autoSyncTransforms to true, or by calling Physics.SyncTrasnforms() again at the end of CustomInterpolationUpdate(). What do you think about it ?
     
    Last edited: May 8, 2019
  16. RiseBasti

    RiseBasti

    Joined:
    Nov 4, 2018
    Posts:
    33
    Hello

    I have a nooby answer for the collision with an object that has an trigger collider on it.

    The ontriggerenter function doesn't get the collision with the player.

    Code on my Trigger Object:

    Code (CSharp):
    1.     private void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.gameObject.tag == "Player")
    4.         {
    5.             //Do something
    6.         }
    7.     }
    How do i have to handle something like this with this controller and shouldn't the controller be detected by the trigger because of its capsule collider?

    Ty :)
     
  17. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Despite the controller supposedly not needing a rigidbody for movement now, you still need one for triggers, as far as I know.
     
    RiseBasti likes this.
  18. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    That's right. Or; you could put a kinematic rigidbody on the trigger if you prefer
     
    Last edited: May 8, 2019
    RiseBasti likes this.
  19. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    That makes sense. This is probably what's happening.

    I suggest starting with putting a Physics.SyncTrasnforms() at the end of CustomInterpolationUpdate like you said (it's much less costly than autoSyncTransforms). If that fixes it I will add an option somewhere to call it automatically in the next release
     
  20. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Fun story:
    I accidentally implemented "strafing"/"b-hopping" without even realizing it last night while working on fixing air movement in the example character. It just turns out that the solution I found to the problem of limiting max air movement speed while still preserving momentum is apparently the exact same thing that causes strafing in oldschool FPSs

    Here is me jumping forward at full speed in a straight line:
    https://gyazo.com/4d42a5bf27ad69c2f504e652515cba24.mp4

    And here is me with the same air acceleration, but doing some b-hopping (I exaggerated the accel value to make the strafing boost super obvious):
    https://gyazo.com/c410f6fb8fe22f6e79e82b61347070f9.mp4

    Here's the top-down visualisation of how the velocity vector (in cyan) increases with strafing (starts at the top)


    This'll be part of the next update. And for those who don't want strafing, reducing air acceleration values and increasing drag gets rid of it

    ========================
    EDIT:
    Well dang, I just found out even "surfing" works! (although it's much easier here than it is in CS, so it might need some work)
    https://i.gyazo.com/cdc9bffe669cff4ea697fdea7db2912c.mp4

    This too will become an option you can toggle
     
    Last edited: May 9, 2019
  21. adouce

    adouce

    Joined:
    Feb 19, 2019
    Posts:
    6
    It does fix it.
    I removed SyncTransforms from Simulate, and changed that part in System (lines 13, 14, and 28) :

    Code (CSharp):
    1. private void FixedUpdate()
    2. {
    3.     if (AutoSimulation)
    4.     {
    5.         float deltaTime = Time.deltaTime;
    6.         if (Interpolate)
    7.         {
    8.             PreSimulationInterpolationUpdate(deltaTime);
    9.         }
    10.  
    11.         Simulate(deltaTime, CharacterMotors, CharacterMotors.Count, PhysicsMovers, PhysicsMovers.Count);
    12.  
    13.         if (!Interpolate)
    14.             Physics.SyncTransforms();
    15.  
    16.         if (Interpolate)
    17.         {
    18.             PostSimulationInterpolationUpdate(deltaTime);
    19.         }
    20.     }
    21. }
    22.  
    23. private void Update()
    24. {
    25.     if (Interpolate)
    26.     {
    27.         CustomInterpolationUpdate();
    28.         Physics.SyncTransforms();
    29.     }
    30. }

    However, I don't really know how necessary it is to have a SyncTransform during FixedUpdate. I swapped it from FixedUpdate to Update, and everything seems to work fine. Thoughts ?
     
    Last edited: May 9, 2019
  22. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I'll have to test just to be sure, but I'd say you can probably remove the FixedUpdate one yeah
     
  23. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    Would this asset be suitable for a space game where the player needs to walk around the interior of a moving spaceship? This would be similar to the moving platform in your example except also with the gravity/rotation of the controller matching the orientation of the spaceship. The spaceship would also be more complex than a simple platform and consist of multiple game objects (with mesh colliders) in a hierarchy.
     
  24. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    This should work, yes. Here's an example:
    https://i.gyazo.com/19c924fccd59a4f2d133e2c3220d9e94.mp4
    https://i.gyazo.com/393afba915027c3e225bc7cf57779679.mp4

    Here I am walking on an object that's:
    • rotating
    • translating back and forth at about 1000 m/s (event if the video capture doesn't show that very well)
    • is made out of several separate mesh colliders
    • changes my character's gravity/up vector as it rotates
    But keep in mind this will not work if your "spaceship" is a non-kinematic rigidbody. Your spaceship will have to be a kinematic rigidbody and its movements will have to be controlled via a "PhysicsMover" script, which is part of KCC. Walking on regular rigidbodies driven by forces sorta works but it's nowhere near as robust as this
     
    Last edited: May 11, 2019
    bonzaiferroni likes this.
  25. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    Thanks for the reply! It really does sound like it would fit my project, and probably many others in the future.
     
  26. CptKen

    CptKen

    Joined:
    May 30, 2017
    Posts:
    216
    Hi,

    Since the controller is kinematic, is it possible to simulate multiple time steps in the future within a single frame?

    I am developing an animation system (motion matching) that relies on future motion predictions and I'm looking for a controller that can add collision prediction so that I can test anticipated stops. i.e. character doesn't run straight into a wall but rather stops just before hitting it.

    Thanks
     
  27. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    That is possible, yes. This function lets you simulate a "frame" with any deltaTime and with any given list of characters, similarly to how Physics.Simulate() works


    ("motors" are the characters and "movers" are basically the moving platform controllers)
     
  28. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    I have a followup to the "spaceship game" question, although I understand if this is out of the scope of questions that you'd prefer to answer. So far it has worked beautifully, the one part that I haven't figured out is how to correct the character's rotation based on the rotation of the platform.

    Here is a gif of what is happening:


    The platform is rotating around its origin, and the character's position changes correctly according to the rotation. However, in a spaceship simulation you'd expect the character's rotation to change based on the ship's rotation. For example, if the character is looking outward from the center you'd expect that relative orientation to remain constant as the ship changes it's rotation.

    Is there a straightforward way to address this issue? I'm using classes almost identical to the example scripts (
    MyCharacterController
    ,
    MyPlayer
    , etc.). My naive idea is to have the character class be "aware" of the rotation of the platform it is on and change its rotation based on the platform's rotation delta over the last frame (within my implementation of
    ICharacterController.UpdateRotation()
    ).

    EDIT:

    My proposed solution seemed to do the trick. However, I've run into some other issues that were only apparent after solving that one, so there may be some issue with my solution or there might just be a more general issue.

    The rotation of my character seems to lag slightly behind that of the ship, it is most observable in first person mode:



    As you can see the rotation of the platform seems to sway from the perspective of the player, when what I really need is 1:1 synchronization. I've tried adjusting all the various sharpness settings to no avail.

    Movement around a platform seems pretty accurate even when it is changing rotation, but I noticed that when I jump it doesn't come down in the same spot, it seems to throw the character away from the origin as if by centrifugal force.

    The behavior that I'm looking for is something identical a situation where the character is parented to the spaceship and moving around in local space. Is this possible with KCC?
     
    Last edited: May 14, 2019
  29. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Couldn't find any other way to answer than with a huge wall of text :D

    Using the default ExampleCharacterController, if you set the Orientation Method to "Towards Movement", the character rotates properly with platforms. It also rotates properly if you put no code whatsoever in UpdateRotation.
    https://i.gyazo.com/d53d2d26434db460d63d181114dde74c.mp4

    What's probably happening in your case is that your UpdateRotation() code tells your character to always face the camera direction.... meaning that any rotation that was made from the moving platform will be undone as soon as the character updates its rotation.

    You got part of the solution right: you need to keep track of how much the current platform is rotating. But you'll need to make the camera itself rotate with the platform; not the character. Basically, at the very beginning of the camera's update, make the "PlanarRotation" rotate by however much the current moving platform has rotated this frame. Making the camera rotate will in turn make your character rotate, because your character just orients itself to wherever the camera is pointing

    It sounds like the kind of thing that happens when the gravity vector you set to your character in its UpdateRotation (the one that is used to determine your new "up" direction) is always one frame late. I did a little modification of ExampleMovingPlatform that makes the character reorient itself, just to illustrate how you should do this:

    Notice that if you use "transform.up" to set the gravity vector, it'll still be the outdated rotation of the platform. What you must use is "goalRotation * Vector3.up"

    This is possible through a feature that is not super well documented: KinematicCharacterMotor.AttachedRigidbodyOverride

    By default, when a Motor is grounded on a PhysicsMover, it sets its "AttachedRigidbody" to that internally, which is what handles the "parenting" logic of PhysicsMovers. But if you need that parenting to always be there even when not grounded on the PhysicsMover, simply set "AttachedRigidbodyOverride" to that PhysicsMover manually. This overrides the built-in AttachedRigidbody detection, and It'll only stop parenting once you reset "AttachedRigidbodyOverride" to null manually
     
    Last edited: May 15, 2019
    bonzaiferroni likes this.
  30. DPunK

    DPunK

    Joined:
    May 15, 2019
    Posts:
    25
    I just bought this asset and went thought the code in the character example. I think I understand how to apply this to my project and transition from using Unity's character controller.

    Right now I have a character that can fly - In this state the mouse allows to rotate around x and y as opposed to just around Y like when grounded. The problem I had with unity's controller is that it cannot rotate at all and will always point up while the character's mesh is rotated around to match flight and speed (it's horizontal like superman's flight at high speeds). This resulted in the character being blocked from passing through spaces.
    I understand this assest only works with a capsule collider so I can't scale the capsule down and add other colliders to it (arms,legs,etc.) but how will I go about at least rotating it to match. I assume if I rotate the object on which the script sits I will have to account for the fact that the motor's up is now the forward by which I want to move it. Is that the way to go?

    Another issue is when character is laying on the ground. Simply is scaling it down will not represent the character's length when on the ground. If I rotate the entire object I will need to change all animations so rotation comes from the GameObject and through script.

    Any help will be much appreciated

    Edit: I've found a question regarding a different shaped collider here and saw a suggestion to used more colliders.In my case I assume in a flight or laying down state I will need to shrink the collider to a shpere (So it's in the center of the character) and add 2 more shpere colliders: One as a child of the legs and one as a child of the head/torso. Then I just need to let the Motor know about their collisions, right?
     
    Last edited: May 15, 2019
  31. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    Thank you so much! You were spot on, I was setting gravity using the transform's current rotation instead of the goal rotation, updating that fixed the "sway".

    AttachedRigidbodyOverride has helped a lot but there were still some issues. It worked exactly as expected while the gravity vector is constant (e.g., when the platform is rotating around the y axis). I still saw drift for rotations that would change the gravity vector (around the z or x axis).

    In addition, I discovered there was also a problem directional jumping. The desired behavior is that a jump in any direction would land exactly where you'd expect if the platform weren't rotating, but I was getting some massive drift.

    I solved these issues by updating velocity and input vectors of the controller/motor within the platform's UpdateMovement implementation:

    Code (CSharp):
    1.     public void UpdateMovement(out Vector3 goalPosition, out Quaternion goalRotation, float deltaTime)
    2.     {
    3.         goalPosition = transform.position + MovementVector * deltaTime;
    4.         var oldRotation = transform.rotation;
    5.         goalRotation = Quaternion.Euler(RotationVector * Mathf.Sin(Time.time)) * oldRotation;
    6.    
    7.         // update controller gravity
    8.         Controller.Gravity = goalRotation * Vector3.down * GravityStrength;
    9.  
    10.         // update movement vectors
    11.         var delta = Quaternion.Inverse(oldRotation) * goalRotation;
    12.         Controller.Motor.BaseVelocity = delta * Controller.Motor.BaseVelocity;
    13.         Controller.UpdateInputRotation(delta);
    14.     }
    This seems to completely solve the issue. Will assigning a value to Controller.Motor.BaseVelocity cause issues?

    Edit: I've run into another issue during stress testing that I think is outside the scope of my code. There seems to be some jitter to the character's position when standing at the extremities of a large platform that is rotating very rapidly:



    The position jitter gets worse the further away from the origin point of the platform. It appears to be some kind of interpolation issue. Any ideas on fixing this?

    I apologize for the never-ending stream of questions, hopefully this can be useful to any other customers who wish to use it the same way.

    Edit 2: Ok I think I've come up with a fix for the new issue. I set
    KinematicCharacterSystem.Interpolate to false. This seems to completely remove that jitter. Is this how you would solve that problem? This would seem to sacrifice some smoothness of movement in relation to other objects so if there is another way to fix the problem I'm all ears!
     
    Last edited: May 16, 2019
  32. Silly_Rollo

    Silly_Rollo

    Joined:
    Dec 21, 2012
    Posts:
    501
    How'd you suggest doing a grappling hook with your controller? If the hook is a normal Unity physics object make it a 'platform' the controller sticks to or keep using GetVelocityForMovePosition as the hook moves around?
     
  33. DPunK

    DPunK

    Joined:
    May 15, 2019
    Posts:
    25
    Maybe someone can help me with this noobish issue i'm having.
    I have my own camera that follows and rotates around the player:

    Code (CSharp):
    1.  rotY += Input.GetAxis("Mouse X");
    2.         rotX += Input.GetAxis("Mouse Y");
    3.         Quaternion rot = Quaternion.Euler(rotX, rotY, 0);
    4.  
    5.         transform.position = target.position + rot * (new Vector3(0,0,1));
    6.         transform.LookAt(target);
    In the ExampleCharacterController, in the SetInput() instead of getting the ExampleCamera's rotation I pass down my own. It's the only change from the original code but when moving it makes the forward go right and the left go forward. Debug showed a difference in the roations of the two cameras:
    ExampleCamera rotation: (0.3, 0.1, 0.0, 0.9)
    CustomCamera rotation: (0.0, 0.4, 0.0, 0.9)

    So i'm guessing the difference comes from the way I calculate my custom camera's rotation achieving a similar behaviour to the original camera but only superficially. Can someone point to what i'm missing or what correction should I do in the controller when recieving my custom rotation?
     
  34. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    If your character controller's UpdateRotation(), you'll be able to tell which rotation you want your character to have. The ExampleCharacterController has an example of this where it rotates the capsule's up direction based on gravity direction

    I recommend setting new rotations in UpdateRotation() instead of modifying the transform directly. Otherwise your changes might get overwritten by the internal character code

    Laying-on-ground collisions handling can get pretty complex depending on what you need. What I recommend is this:

    Here the green circle is the KCC capsule shrunk down to a sphere, and the blue rectangle is a box collider (child of KCC capsule) covering the rest of the body. The box collider's job would be:
    • Detect all collisions with colliders other than the KCC capsule
    • Find out how much it has to move in order to solve collision, using ComputePenetration
    • Make your characterController aware of that decollision vector found in the previous step, and make it move by that vector in order to decollide
     
  35. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    This is fine. The only reason why I discourage people from using it is because if you don't update velocity in UpdateVelocity, the GroundingStatus will always be one frame late. But in your case you don't need that

    And yes, "rotating" your character's velocity along with your platform (like you did) is the solution to this problem. The drifting was caused because your initial jump impulse (let's say (0,1,0)) kept going in that initial direction even though your gravity changed mid-flight. Hence why you started drifting

    Ok this might get pretty complex

    If you disable interpolation, your perceived character movement framerate is now limited to whatever your FixedUpdate rate is (50fps by default). I personally think it would be worth trying to preserve interpolation, especially on PC where people might want to play at 144fps

    It's possible that the jitter could be due to the way you solved the previous issue of making the camera rotate with the platform. If you made your camera rotate during the character's or physicsMover's updates, then it'll rotate only on FixedUpdates, so without interpolation. Also, if you did make your camera rotate on Update() but used the platform's rigidbody.rotation or mover.TransientRotation in order to determine the rotation delta.... it'll also skip interpolation because those are only updated in FixedUpdate

    The solution is: Update your camera rotation from moving platform's rotation delta on Update, but use the mover.transform.rotation to calculate that delta from frame to frame (because interpolation affects only the transforms; not the rigidbodies)
     
    Last edited: May 17, 2019
  36. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I would definitely suggest the "GetVelocityForMovePosition" approach, and not the moving platform approach. You can also try using Motor.MovePosition() if you don't feel like handling this in UpdateVelocity()
     
  37. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I think you just got your "rotY" and "rotX" mixed up :D
     
  38. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Just figured out a clean and simple way to make KCC stand perfectly on a dynamic rigidbody:


    Here are the steps:
    1. Create a MoverController that has a reference to a dynamic rigidbody, and make it just copy the rigidbody's position and/or rotation:
      Code (CSharp):
      1. public class DynamicPhysicsMover : MonoBehaviour, IMoverController
      2. {
      3.     public PhysicsMover Mover;
      4.     public Rigidbody DynamicBody;
      5.  
      6.     private void Start()
      7.     {
      8.         Mover.MoverController = this;
      9.     }
      10.  
      11.     public void UpdateMovement(out Vector3 goalPosition, out Quaternion goalRotation, float deltaTime)
      12.     {
      13.         goalPosition = DynamicBody.position;
      14.         goalRotation = Quaternion.identity;
      15.     }
      16. }
    2. Make "DynamicRigidbody" be a separate gameobject that's a duplicate of your initial mover collider, except it is a non-kinematic rigidbody (with no PhysicsMover script on it)
    3. Make "DynamicRigidbody" ignore collisions with its PhysicsMover and with the character standing on it (either with Physics.IgnoreCollisions or with layers)
    And now you have a dynamic rigidbody that you can perfectly stand on. Useful for standing on cars, rolling logs, etc.....

    I'll see about packaging/documenting this in a future release. Support has been crazy due to the madness sale but things should calm down now that that's over, and I'll have more time to actually work on an update!
     
    Last edited: May 17, 2019
    JohnyBroo, renem, echolink and 7 others like this.
  39. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    After some debugging, I still haven't found the exact cause of my glitching through walls in corners issue. But, I'm thinking it may be related to the same issue that causes slow falling in corners and the ability to glide up corners by applying forward velocity. The movement projection only accounting for one slope at a time may be allowing the final projection to push the character into walls.

    One thing I have noticed is that KinematicCharacterMotor.InternalCharacterMove() is usually called from a different place right when it happens. It's called after the "// Project movement against current overlaps" comment rather than after the "// Sweep the desired movement to detect collisions" comment. So, that does imply that it's being pushed into something. This specifically seems to be called when glitching through a corner made from 3 colliders. There is one place I can consistently glitch through where it doesn't get called: a corner formed by 2 colliders rather than 3.
     
  40. DPunK

    DPunK

    Joined:
    May 15, 2019
    Posts:
    25
    I should have pointed out this is not a mistake :)
    The rotation in the X axis is handled by the mouse up and down movement (Axis Y) - Maybe I need to find a clearer way to name these. But indeed I was switching the two in the PlayerCharacterInputs :mad:
    So now movement is right!

    Now the only issue is that rotating the camera and character is out of sync. Camera rotates slower than the player so I believe it's the result of my cam's rotation being different than the example rotation so I need to either fix it or account of it.

    My camera and the Example camera both point in the same way yet the rotations they give off in quaternion are differernt.

    Here is the full SetInput() code:

    Code (CSharp):
    1. // Move and look inputs
    2.         _moveInputVector = Camera1.transform.right * inputs.MoveAxisForward + Camera1.transform.forward * inputs.MoveAxisRight;
    3.         float magnitude = _moveInputVector.magnitude;
    4.         _moveInputVector = Vector3.ProjectOnPlane(_moveInputVector, Motor.CharacterUp) * magnitude;
    5.  
    6.  
    7.         // Calculate camera direction and rotation on the character plane
    8.         Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(Camera1.transform.rotation * Vector3.forward, Motor.CharacterUp).normalized;
    9.         if (cameraPlanarDirection.sqrMagnitude == 0f)
    10.         {
    11.             cameraPlanarDirection = Vector3.ProjectOnPlane(Camera1.transform.rotation * Vector3.up, Motor.CharacterUp).normalized;
    12.         }
    13.         Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
    14.  
    15.         _moveInputVector = cameraPlanarRotation * _moveInputVector;
    16.  
    17.         switch (OrientationMethod)
    18.         {
    19.             case OrientationMethod.TowardsCamera:
    20.                 _lookInputVector = cameraPlanarDirection;
    21.                 break;
    22.             case OrientationMethod.TowardsMovement:
    23.                 _lookInputVector = _moveInputVector.normalized;
    24.                 break;
    25.         }
    26.  
    27.         //Set Max Speed
    28.         MaxStableMoveSpeed = inputs.Speed;
    And here is the behavior it results (Always pressing forward only moving camera): gif6.gif
     
    Last edited: May 17, 2019
  41. DPunK

    DPunK

    Joined:
    May 15, 2019
    Posts:
    25
    Still curious what caused this but for now I got it fixed by doing the projection myself:
    Code (CSharp):
    1. Vector3 cameraFlatDirection = Vector3.ProjectOnPlane(Camera1.transform.forward, Motor.CharacterUp);
    2.         Vector3 cameraRight = Vector3.Cross(cameraFlatDirection, Motor.CharacterUp) *-1;
    3.  
    4.         _moveInputVector = cameraFlatDirection * inputs.MoveAxisForward;
    5.         _moveInputVector += cameraRight * inputs.MoveAxisRight;
     
  42. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    This is actually how I have it. I update the change in the platform's rotation right before I call OrbitCamera.UpdateWithInput(), all within MyPlayer.Update(). I am tracking the delta using Platform.transform.rotation. So I think the issue must be elsewhere. Also, if you look at the gif I posted, it appears to be an issue with the character's position relative to the platform, not an issue with the camera's rotation relative to the platform. Notice how the player's distance to the edge is what is jittery. Is it possible that the interpolation is being handled differently for the character vs. the platform?

    Here's my code in case it helps:

    Code (CSharp):
    1. public class MyPlayer
    2. {
    3.     private void Update()
    4.     {
    5.         if (Input.GetMouseButtonDown(0))
    6.         {
    7.             Cursor.lockState = CursorLockMode.Locked;
    8.         }
    9.  
    10.         // calling from within Update()
    11.         HandlePlatformRotation();
    12.         HandleCameraInput();
    13.         HandleCharacterInput();
    14.     }
    15.  
    16.     private void HandlePlatformRotation()
    17.     {
    18.         // find the amount rotated since last tick
    19.         var rotation = Platform.transform.rotation;
    20.         var delta = Quaternion.Inverse(_lastRotation) * rotation;
    21.         _lastRotation = rotation;
    22.      
    23.         // isolate rotation around platform's local y axis
    24.         delta = rotation * delta * Quaternion.Inverse(rotation);
    25.         // adjust camera rotation
    26.         OrbitCamera.UpdatePlatformRotation(delta);
    27.         // adjust character velocities
    28.         Character.UpdatePlatformRotation(delta);
    29.     }
    30. }
    31.  
    32. public class MyCharacterController
    33. {
    34.     public void UpdatePlatformRotation(Quaternion delta)
    35.     {
    36.         _moveInputVector = delta * _moveInputVector;
    37.         Motor.BaseVelocity = delta * Motor.BaseVelocity;
    38.     }
    39. }
    40.  
    41. public class MyCharacterCamera
    42. {
    43.     public void UpdatePlatformRotation(Quaternion platformDelta)
    44.     {
    45.         PlanarDirection = platformDelta * PlanarDirection;
    46.     }
    47. }
    48.  
    49.  
     
  43. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    The "// Project movement against current overlaps" part is for when we are already overlapping with something before we start moving the character with its velocity. It tries to make sure that whatever our velocity is right now, it will be projected on current overlaps so that it cannot go in that direction

    Basically, if you are going through something, it would make sens that this method gets called

    But I can send you a WIP KinematicCharacterMotor that has a fix for the air-moving-against-corner bug, and see if that solves it
     
  44. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    oh, you're right. I will try doing the rotate-camera-with-platform on my side as well so that I can test this out in practice. I'll get back to you on this
     
    angelonit likes this.
  45. bonzaiferroni

    bonzaiferroni

    Joined:
    May 26, 2016
    Posts:
    30
    If it helps at all, I have an empty project with only KCC imported and the minimum amount of code needed to reproduce this issue. It's only noticeable at the edge of very large platforms (the one in my gif has a radius of 100 units).
     
  46. TomatoLamp

    TomatoLamp

    Joined:
    Feb 8, 2013
    Posts:
    8
    I've been using the "Max Stable Denivelation Angle" to allow the controller to launch off of slopes but when I bring the motor's slider down to 1, it also forces the player to stop at the bottom of ramps where they "reconnect" with the ground.

    I was able to replicate this in the "playground" scene. It's harder to notice there, but you should see the same behavior when walking down a slope onto the ground. It seems to be a small reset in velocity but perhaps it is some kind of interference from another setting on the motor?

    EDIT: After adopting your "orient rotation to ground" addition - I no longer have this issue. I'm also wondering if it was simply a performance hiccup in the first place or perhaps I've stared at it too long!
     
    Last edited: May 23, 2019
  47. LezCT

    LezCT

    Joined:
    Nov 15, 2014
    Posts:
    55
    I wonder if the system also has mass for each KCC?
    To avoid pushing KCC with higher mass... Or maybe I'm just missing something?
     
  48. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Characters don't have a built-in notion of mass, but you can add one in your custom character controller. So in your OnMovementHit(), if you hit another character, you could add a force to it based on the difference between your mass and their mass
     
    LezCT likes this.
  49. PedroHN

    PedroHN

    Joined:
    Dec 8, 2012
    Posts:
    4
    Hi! Thanks again for the great asset!

    I'm having some trouble applying rotation to my character. That is, I want to apply both rotation from my inputs and from the root motion at the same time.

    I have put this in my UpdateRotation:

    Code (CSharp):
    1. currentRotation = Quaternion.LookRotation(_lerpLookDir, Motor.CharacterUp);
    2. currentRotation *= _rootMotionRotationDelta;
    The character rotates with the input like I want, and moves one step of the rootMotionRotationDelta every frame, but then it seems to reset the rotation update when I set the input-rotation.

    I am calculating the input direction in the Update loop and getting the _rootMotionRotationDelta in the OnAnimatorMove.

    Might be a bit of a basic question, but any help would be greatly appreciated!
     
  50. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    There are two things I would suggest trying:
    • When you remove your rotation from input and leave only the rootmotion active, is the rootMotion working?
    • Instead of "currentRotation *= _rootMotionRotationDelta;", try "currentRotation = _rootMotionRotationDelta * currentRotation;"