Search Unity

[Released] Kinematic Character Controller

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

  1. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    @Lex Thank you for your comment. That's a good point! I'll try just syncing positions myself and see if it works well enough! :D
     
  2. CaptainMurphy

    CaptainMurphy

    Joined:
    Jul 15, 2014
    Posts:
    746
    I have never had good luck trying to sync client side motion to each other client. I have made every project do a single master controller and then just sync position/rotation to the clients and have the client send their inputs 5 times a second. That has always seemed to work quite well, you just aren't going to have a super-twitch shooter speed out of it.
     
  3. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    @CaptainMurphy
    My game is a twitch shooter (Quake 3 Arena like). But only will support 6 players max, so perhaps I can get away with input to server and syncing position on clients by updating more frequently since I have a smaller player count.
     
  4. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    Just an update in case it helps anyone else. My primary issue was that I did not have "Interpolation" checked in my KinematicCharacterSystem inspector. Having that checked resolved the jumping jerk issue, but then client characters for my Host were frozen at position 0,0. The reason was that I was setting "HasOwnerShip = true" for the client that belonged with that character, when in reality the "Host / Server" needs that property true for all characters. You then can assign "IsLocal" on the character to which a client belongs.

    Hope this is helpful to anyone else
     
    JustASloth13 likes this.
  5. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    187
    You mean [this] right ? What do you think about it, how does it compare to KCC? Also considering [Physix] as a KCC replacement but ECM has been supported for 2 years which I know I really want.
     
  6. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    When I walk off of a ledge with ledge handling enabled, it's quite slow to fall. Example:


    Is there a way to make ledge handling more aggressive, so that you slide down ledges at the same speed as sliding down steep slopes?

    Also, I prefer character controllers to walk straight off of ledges, as if the bottom of their colliders were flat, so that there isn't a dip while walking off. This is especially important when the player is expected to jump at the edge of the ledge for maximum distance. Dipping down for a moment throws off the coyote time balance. If such an option isn't already implemented, consider this a suggestion.

    And, finally, I have prop objects that the player should be able to collide with but always slide on. With my previous controller, I assigned these objects to a slope layer and prevented grounding and enabled gravity when only standing on a slope (allowing players to remain grounded as long as they're at least partially standing on a non-slope object). I didn't see a built-in way to do this in the kinematic controller, and I consider it an essential feature.

    Other than these issues, however, I've so far been quite impressed with the controller. Awesome work!
     
  7. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    an update:

    sorry for being very absent lately everyone. I have been completely unable to find free time for this project and it will have to remain this way for another 3-4 weeks. Once that is over I'll come back and answer as much stuff as I can
     
  8. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    353
    @PhilSA
    Thanks for giving us a brief update, glad to know you are still alive!
     
  9. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    The IsColliderValidForCollisions function on the ExampleCharacterController always returns true. This is due to the function immediately returning true if IgnoredColliders.Count is greater than 0.

    To fix this, replace the entire contents of the function with the following:
    Code (CSharp):
    1. return !IgnoredColliders.Contains(coll);
     
  10. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    187
    Happy to see you here!
     
  11. Guacamolay

    Guacamolay

    Joined:
    Jun 24, 2013
    Posts:
    63
    No problem, glad to see you back on the project, it really is a fantastic controller :D
     
  12. Vincent454

    Vincent454

    Joined:
    Oct 26, 2014
    Posts:
    167
    Awesome, great to see you back!!
     
  13. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    If I jump against a steep slope while applying a forward velocity, the motor seems to redirect the velocity upward. Does anyone have an idea of how to prevent this?

    Here's an example GIF showing the walkable slopes, the usual behavior while charge jumping against a wall, and the excessive height from charge jumping against a steep slope. The jump velocity in all cases is the same, and I've confirmed, by printing a Debug.Log, that only one jump is occurring (ruling out the possibility of the velocity being applied more than once).
     
  14. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Also, by charging (applying a forward velocity) into this gap and then jumping (with a pause between jumps), I can force the character into this gap under the labeled test slopes. The motor here has a capsule radius of 0.375 and a capsule height of 0.75.
     
  15. Guacamolay

    Guacamolay

    Joined:
    Jun 24, 2013
    Posts:
    63
    Is Safe Movement set to true in the Kinematic Motor script? This prevents the "tunneling" behavior which may fix this issue

    I have experienced this too - when I am jumping forward and hit a ledge, the controller jumps upwards. I think what is happening is the controller projects the current velocity in the direction of the surface it just hit. Unfortunately I haven't found a solution for this yet, but hopefully someone else might have a fix
     
  16. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Oh yeah, that fixes it! Thanks!

    I've confirmed through logging that the controller isn't responsible for the high jumping against steep slopes, because it only redirects velocity while stably grounded. So, my guess is that it's the motor doing the redirection in much the same way as how you can slide against walls while walking into them. It's important for that, of course, but it totally breaks jump balancing.
     
  17. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    The way I solved the jumping against steep slopes thing in a previous controller was to simply prevent charging (the forward velocity) from being applied while ground is detected but too steep. In theory, Motor.GroundingStatus.FoundAnyGround should be the "found any ground, steep or otherwise" component of that check. But, it only seems to ever be true while sliding down slopes rather than jumping against them.

    In fact, the example controller makes use of FoundAnyGround to prevent movement input enabling sliding up slopes in a theoretically even more elegant manner. It starts with the following comment:
    Code (CSharp):
    1. // Prevent climbing on un-stable slopes with air movement
    However, even with GroundDetectionExtraDistance set to 1, FoundAnyGround just never returns true while jumping up these steep slopes. So, there's never a chance to catch it and prevent the high jumping. If there were, it would be a simple matter of using the same code that prevents movement input from climbing up steep slopes, but with the charging (forward) velocity instead of the velocity from movement input.

    Edit: by moving the jump velocity application code above the ground and air velocity code, I was able to get FoundAnyGround to be true once at the start of a jump against a steep slope. But, using the prevent climbing code there still wasn't enough to prevent the rest of the high jump. Also, I forgot to mention that I'm using a modified ExampleCharacterController, for context.
     
    Last edited: Nov 20, 2018
  18. Guacamolay

    Guacamolay

    Joined:
    Jun 24, 2013
    Posts:
    63
    Yes, I think the redirection is done in the motor script. I've attached the below image showing the change in velocity (red lines) over time as I jump and hit the edge of the slope. It seems to redirect the velocity of the motor using the ground normal that registers when the controller hits the edge of the platform. Unfortunately this pops the controller up into the air, without losing any velocity, so if the controller is travelling fast, it can shoot it up quite high. I'm not sure what the best solution is to avoid this problem!
     

    Attached Files:

    Last edited: Nov 21, 2018
  19. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    With safe movement enabled (to fix tunneling), I get stuck while walking into the corner of this test terrain:

    This doesn't happen with safe movement disabled, but safe movement is required for my use.
     
  20. Guacamolay

    Guacamolay

    Joined:
    Jun 24, 2013
    Posts:
    63
    Is that plane level with the ground or above it? If it's above the ground, what is your step height on your controller?

    Also in this case your kind of walking into the side of a plane rather than a proper collider. This isn't something that will be happening in your final game I imagine? It might not necessarily be an important issue to solve. It can be easy to get bogged down trying to solve every conceivable edge case, but it might not be something that is needed for the final game.
     
  21. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    This is in the example scene. It is raised very slightly, probably to avoid z-fighting. The max step height is 0.5. Although the step height should really be used in this case, it does only seem to occur while colliding with the thin edge of that concave collider. So, perhaps it's something that wouldn't be encountered in normal usage.
     
  22. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    I solved the extra high jumps against slopes while applying a forward velocity to a satisfactory degree by basically copying everything from the ground movement section except the input bit and applying it to the state (e.g., charging) velocity, in addition to gravity. If the current state has its own target velocity, it goes through that sequence. Otherwise, it uses the normal ground and air code.

    As a result, the state velocity is now treated as a target velocity that is reached through acceleration. The targetMovementVelocity is the sum of the state's velocity (usually toward the character's forward vector), flattened against the virtual wall created by the double cross product (from the hit ground normal and character up vector); and the currentVelocity, projected onto the character's up vector. With the up/down velocity preserved, the acceleration only modifies the velocity laterally. And, I only flatten the required delta velocity against the Gravity plane via ProjectOnPlane when Motor.GroundingStatus.IsStableOnGround is true (to facilitate aerial states that require custom vertical velocity).

    Here's a GIF showing the fixed charge jumping behavior:
     
    Last edited: Nov 24, 2018
    Alvarezmd90, Kin0min and Roy927 like this.
  23. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Hey there,
    I've seen some negative reviews about some errors in 2018 version of Unity. I want to know if they are fixable by ourselves or not ?
     
  24. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    According to another review, they're easily fixed. Review quote:

    Also, for anyone using older versions, there were some errors in 2017.4.2f2 when in play mode with a prefab instance selected in the scene. I'm assuming that had something to do with the recent prefab system changes. I fixed it by simply creating a new prefab from the offending game object. You can break the prefab instance and delete the prefab afterward if you don't actually want the prefab itself.
     
    a-t-hellboy likes this.
  25. ChainsawFilms

    ChainsawFilms

    Joined:
    May 28, 2016
    Posts:
    18
    I've hit a problem with this asset. When you are on a planet and you jump straight up, the planet moves under you, you're not bringing the rotational velocity of the planet with you. Traditionally this would simply be solved by making the character a child of the planet but that causes this controller to get all jittery.

    Does anyone have advice? I've tried getting the angular velocity of the rotating planet and adding it to my character when he jumps but that doesn't give the effect I'm after (which is basically jumping on a planet should handle the same way as if you are on a standard terrain).

    Thank you.
     
  26. kindingerlek

    kindingerlek

    Joined:
    Jul 7, 2015
    Posts:
    10

    Actually I had this behaviour too and I suggested the Phil to disable it by default. In general, the safe movement isn't really necessary, besides it has an extra performance cost and also can cause weird behaviours, like get stucked.

    If you need the Safe Movement, my suggestion to you, is make a box collider (or another one) in the area that needs this most precise movement (eg, Tunnels), and make it read when CharacterController get enter, to set 'Save Movement' as true. In same way, when exit, false.
     
    andreiagmu likes this.
  27. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Interesting suggestion. I definitely prefer safe movement over performance here, since I'm only using the controller for the player character, which is the single most important and potentially bug-exploitable object in the game. So, I might do the opposite: disable safe movement in critical areas if I find that the player tends to get stuck in them. Although, if performance becomes an issue and there aren't any other systems more ripe for optimization, I might consider reversing that decision.

    In either case, that's a useful suggestion to keep in mind. Thanks!
     
    andreiagmu likes this.
  28. Streamfall

    Streamfall

    Joined:
    Aug 8, 2011
    Posts:
    43
    Hello Philippe,
    Does this plugin support Mecanim and IK gracefully?
     
  29. Vincent454

    Vincent454

    Joined:
    Oct 26, 2014
    Posts:
    167
    Yeah, my player gets stuck on terrain quite often randomly when having safe movement enabled
     
  30. DrEvil

    DrEvil

    Joined:
    Aug 11, 2012
    Posts:
    22
    There's a bug in the block of code commented with // Detect blocking corners

    Here is the issue

    https://imgur.com/a/kbOAS3F

    The first few jumps are with no lateral input, just the jump. The later jumps that are bugged are when applying input 'into' the corner and also jumping.

    The issue is this block in KinematicCharacterMotor

    Code (CSharp):
    1.  
    2. else if (sweepState == MovementSweepState.AfterFirstHit)
    3.                 {
    4.                     // Detect blocking corners
    5.                     if (Vector3.Dot(previousObstructionNormal, remainingMovementDirection) < 0f)
    6.                     {
    7.                         Vector3 cornerVector = Vector3.Cross(previousObstructionNormal, obstructionNormal).normalized;
    8.                         remainingMovement = Vector3.Project(remainingMovement, cornerVector);
    9.                         remainingMovementDirection = remainingMovement.normalized;
    10.                         remainingMovementMagnitude = remainingMovement.magnitude;
    11.                         resultingMovementMagnitude = (remainingMovementMagnitude / remainingMagnitudeBeforeProj) * resultingMovementMagnitude;
    12.  
    13.                         sweepState = MovementSweepState.FoundBlockingCrease;
    14.                     }
    15.                 }
    16.  
    Code (CSharp):
    1. if (sweepState == MovementSweepState.FoundBlockingCrease)
    2.             {
    3.                 remainingMovementMagnitude = 0f;
    4.                 resultingMovementMagnitude = 0f;
    5.                
    6.                 sweepState = MovementSweepState.FoundBlockingCorner;
    7.             }
    The interesting thing, is that it doesn't happen in every corner.

    If I understand correctly, a 'blocking crease' is just a situation where there is more than 1 obstruction whose normal will clip the movement direction(checked by the dot product)

    The thing that doesn't make sense to me is why if a 3rd obstruction calls the function, it is simply assumed that it is a blocking corner. No normal check, no nothing.

    After extensive logging and debugging, what I've found is that jumping 'into' most corners often has more than 2 sweep iterations made, but the corners that don't exhibit this issue are corners where the 2 corner walls are perfectly vertical, such that the lateral velocity is completely clipped, and the third sweep iteration ends up hitting no obstruction. The glitchy corners has one of the hit faces non perfectly vertical, such that the projection onto that normal doesn't zero out the velocity in that direction entirely. This leaves later iterations of the sweep to simply assume it's a blocking corner and zero out the motion.

    It appears to work properly if I get rid of the conditional that assumes it's a blocking corner if it was previously a blocking crease, and also get rid of the else after the if (sweepState == MovementSweepState.Initial), so that every sweep iteration will just clip the velocity. I'm concerned though whether this trades one problem for another that isn't immediately obvious, so can anyone explain the purpose of this code as far as the assumptions it was making about the blocking corners?
     
  31. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Hmm, I may have misunderstood your instructions, but I only seem to experience that short-circuited jump into corners after making those modifications.

    What I do experience, however, is slow falling when accelerating toward a forward+down velocity into a corner. Example:
     
    Alvarezmd90 likes this.
  32. DrEvil

    DrEvil

    Joined:
    Aug 11, 2012
    Posts:
    22
    I suspect it's very geometry specific, because in the situations where this is breaking, one of the walls that is being detected in that code is not perfectly vertical. It might take some super fine toying with the slope of the wall to reproduce it. A majority of situations(in this voxel game at least), have perfectly vertical walls, so it doesn't end up doing a 3rd iteration of this solve loop.

    here's the deltas just to make sure you made the same changes
    https://imgur.com/a/DAFJdaf
     
  33. DrEvil

    DrEvil

    Joined:
    Aug 11, 2012
    Posts:
    22
    If you still can't repro it I can save out the mesh that is exhibiting the issue if that would help.
     
  34. DrEvil

    DrEvil

    Joined:
    Aug 11, 2012
    Posts:
    22

    Attached Files:

  35. Guacamolay

    Guacamolay

    Joined:
    Jun 24, 2013
    Posts:
    63
    Are you using Mesh Colliders or Box Colliders? Generally Mesh Colliders are much more expensive and less accurate than the primitive shape colliders. I'm not sure if it's feasible to swap out the colliders to box ones in your case, but it could fix this issue and might improve performance too
     
  36. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    There was some shader channel count error when importing your files into 2017.4.2f2, and neither the mesh nor the model were functional. So, I can't confirm if I experience the issue with that geometry.

    But, after making the changes from your diff screenshot, I didn't see any change in behavior (positive or negative) while testing it out in the example scene. So, at the very least, the code change doesn't seem to break anything immediately obvious.
     
  37. DrEvil

    DrEvil

    Joined:
    Aug 11, 2012
    Posts:
    22
  38. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    The import was successful with that version. Seems pretty stable, though; no hitches when jumping while pushing into a corner here, with my controller. And, although my controller is modified, I haven't changed the motor at all. So, it might be caused by specific settings or controller velocity calculations.
     
  39. Alvarezmd90

    Alvarezmd90

    Joined:
    Jul 21, 2016
    Posts:
    151
    Does anyone know how to fix the ladder? When I stand on the ground it immediately detaches or can't go up on it. When I jump on it, it does work fine. Also, how about free climbing. I'd pay 200 bucks for that if it came as an addition to this controller.
     
  40. owen_proto

    owen_proto

    Joined:
    Mar 18, 2018
    Posts:
    118
    I'm also looking for a solution for this.
     
  41. owen_proto

    owen_proto

    Joined:
    Mar 18, 2018
    Posts:
    118
    I've found a remedy for the planet moving under you while you are in mid air. If you are building off of/modifying the controller that is in the demo scene like I am, make sure that "Preserve Attached Rigidbody Momentum" is selected in the Kinematic Character Motor script, and in the controller under Air movement you have to set Drag to 0. This could have a big effect on the way your controller handles while in mid air. I haven't played around with it much yet, but this may cause your character to go flying through the air farther than you may like under some circumstances. If you are trying to make a controller to traverse rotating planets you may need to trigger adding back air drag in the translation update if your character is moving too far or fast.

    Edit: It seems as though this doesn't completely solve the problem. If your planet is rotating at a reasonably slow speed, the effect of the planet moving under you isn't even noticeable. For example I tested this on a planet with a minimum radius of 1000 with a full rotation taking 30 minutes. This was no problem. If I speed up the rotation to happen in 60 seconds the problem becomes noticeable even with no air drag in the controller as implemented in the demo.

    I'm not sure if this is an issue with the calculations in the motor script or the implementation of the controller. When I dig into it I'll report what I find.
     
    Last edited: Dec 9, 2018
  42. deiterate

    deiterate

    Joined:
    Jul 10, 2015
    Posts:
    9
    To fix the ladder example scene, I had to adjust the Ladder Segment Bottom Y parameter to approximately 0.527 for all the broken ladders. Additionally, if you change the character capsule height to 1.5, it works with the Ladder Segment Bottom Y parameter 0.3 default value. Basically, the ladder demo implementation and it's Ladder Segment Bottom Y parameter is definitely affected by the character capsule height in some way, but I haven't delved into the demo implementation to figure out why yet.
     
    Alvarezmd90 and halley like this.
  43. Alvarezmd90

    Alvarezmd90

    Joined:
    Jul 21, 2016
    Posts:
    151
    Hm.. I just tried fiddling around with it but I only made it worse. xD

    I have made Link being able to swim in all four directions but I cannot make him detect an ledge above him. Need to look into the controller some more.. I also want to be able to force the player onto the highest point of the water surface instead of him falling in and staying underwater.
     
    andreiagmu likes this.
  44. Bubsavvy

    Bubsavvy

    Joined:
    Sep 18, 2017
    Posts:
    48
    Hey @PhilSA. Good to hear your back. :D Your plugin has been monumental with helping fixing certain issues with character physics for our game. Just wanted to mention that, if anyone else is interested as much as I am, we were wondering if you could open source your plugin on a public git repo or something along the lines of that so everyone can help out if need be with certain parts of the project. It would also serve as a good issue tracker for people using the tool. I know there is plenty of developers that would be willing to pitch in fine tuning the plugin. This could also serve as a documentation hub where you could detail use cases of your api.

    Sincerely,

    Troll House Games
     
    Alvarezmd90 likes this.
  45. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Hew there,

    How can I change incorrect Lerp in UpdateVelocity to correct one ? I mean It's not linear actually and I want to make it linearly.

    Edit: I fixed it with MoveTowards.

    Now I have another question. How can I remove slippery effect when changing direction from forward strafe to forward in high speed ?
     
    Last edited: Dec 17, 2018
  46. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Turns out, the motor's "safe movement" option isn't so safe. Enabled or not, walking into the step of this concave mesh results in no longer being considered on stable ground. But, annoying as that is, it's not the unsafe part. Next, if safe movement is enabled, simply waiting results in falling through the rock. With safe movement disabled, there's a bit of jittering, but the character doesn't fall through.
     
  47. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Any idea ?
     
  48. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Haven't experienced anything I would call a slippery effect. So, I'm not sure what you're referring to.
     
  49. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    @OhiraKyou I changed Lerp function in UpdateVelocity example to MoveTowards because actually that line of code doesn't have linear behavior. So when I change direction from forward to backward in high speed, character slides on the ground until direction is changed. So I think I should change my MoveToward from linear to exponential but not sure if it is good for animations too. (Animations should sync with speed). What do you think ?
     
    Alvarezmd90 likes this.
  50. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    @a-t-hellboy,

    Ah, in that case, the sliding you're experiencing is simply due to your MoveToward speed not scaling with the difference between your current and target velocity (or not scaling sharply enough). While you could calculate a multiplier to apply to your speed so that it moves toward the target velocity faster when farther away, what you're looking to do is actually what the currentVelocity Lerp is doing already.

    Lerp, by definition, linearly interpolates from one value to another. But, you will only observe linear interpolation over more than one update when the current and target value remain constant in every update. The non-linear behavior you observe is largely due to the current velocity changing (toward the target velocity) every update, making the interpolation speed a percentage of the delta velocity. As the current velocity closes in on the target velocity, the same percentage will yield smaller deltas. This is useful, as it allows us to automatically scale how much velocity we apply each update so that changing from one velocity to another feels consistent, even when the current and target velocities are not.

    So, ultimately, I suggest simply tweaking the relevant movement sharpness property, which is used to calculate the delta velocity percent to apply each update. 15 was about right for the stably grounded movement sharpness in my case. You can get a similar icy effect by setting the sharpness to something lower, like 1. Much like in your MoveToward example, this results in a per-update velocity application that does not scale with the required delta velocity sharply enough for quick turns.
     
    Alvarezmd90 likes this.