Search Unity

[Released] Kinematic Character Controller

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

  1. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I think it's just best to wait and see how the new one turns out, it's been a while! don't want to derail...
     
  2. Dan2013

    Dan2013

    Joined:
    May 24, 2013
    Posts:
    200
    I think we should ask some Unity guys to give some underlying details for this question.
     
  3. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    Hey, I've got a question regarding jumping and air controls.
    (disclaimer, my "max air move speed" has been set to 5 instead of 10)

    The issue I think I have is how "air move speed" is handled. When moving at max speed and releasing input when jumping I'll go farther than I would if I was holding forward while jumping, I want the opposite(common in many platformers, that if you hold forward while jumping you'll go a little farther since it'll add to the jump distance). I can even jump forward at full speed, release controls, and half way through if I apply forward input again my speed will rapidly decrease essentially stopping the jump instead of boosting it a little farther.

    I think it has something to do with the fact that if I apply movement while mid-air it'll update my velocity, and I think the issue is that this causes it to use the air-move speed, which being half of regular move speed, seems like it throws out the velocity I had and uses this new one (which is shorter of course) which I think causes the speed decrease.

    This is where I'm stuck, I feel that there's a simple solution I'm missing to preserve velocity or add air-move so you go a farther instead of shorter distance when jumping + air-moving. However what's been getting in my way is that I also want it so that if you quickly hold backwards after jumping forwards at max speed, the player will reduce speed, and even move backwards to about where the jump started (sort of a jump-regret grace period that makes platforming a bit more forgiving) or if they are in mid-arc of the jump and hold backwards, they'll essentially cancel out the speed and fall down about where they held it(plus a little for smoothing of course)

    I hope this made sense, I can supply images or videos of the effect I want to emulate if needed, If anyone could push me in the right direction it'd be much appreciated. Thanks!
     
  4. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    yes, this is an issue I recently became aware of while making a game jam game using KCC (see "SkyRunners" in my signature). I did not have time to find a fix then, but I intend to start looking at this pretty soon

    Code (CSharp):
    1. // Air movement
    2.                         else
    3.                         {
    4.                             // Add move input
    5.                             if (_moveInputVector.sqrMagnitude > 0f)
    6.                             {
    7.                                 targetMovementVelocity = _moveInputVector * MaxAirMoveSpeed;
    8.  
    9.                                 // Prevent climbing on un-stable slopes with air movement
    10.                                 if (Motor.GroundingStatus.FoundAnyGround)
    11.                                 {
    12.                                     Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
    13.                                     targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
    14.                                 }
    15.  
    16.                                 Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity);
    17.                                 currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
    18.                             }
    19.  
    20.                             // Gravity
    21.                             currentVelocity += Gravity * deltaTime;
    22.  
    23.                             // Drag
    24.                             currentVelocity *= (1f / (1f + (Drag * deltaTime)));
    25.                         }

    The issue is basically that for air movement code in ExampleCharacterController, I establish a "targetMovementVelocity" that is based on MaxAirMoveSpeed, and then I make whatever velocity we currently have move towards that value at a rate of "AirAccelerationSpeed". So in short; if you have MaxAirMoveSpeed == 0, pressing forward inputs while in air will result in you stopping mid-air, because the calculated targetMovementVelocity will be Vector3.zero.



    I've found that this algorithm works very well for smooth-but-responsive ground movement that doesn't take forever to make direction changes, but for air movement it makes no sense.

    _______________________________________________________________________

    EDIT:
    Well, turns out I tried a quick solution and it works really well. Find the place in ExampleCharacterController.UpdateVelocity where there's a "// Air Movement" comment, and make the content of the "else" look like this:
    Code (CSharp):
    1.  
    2.                         // Air movement
    3.                         else
    4.                         {
    5.                             // Add move input
    6.                             if (_moveInputVector.sqrMagnitude > 0f)
    7.                             {
    8.                                 currentVelocity += _moveInputVector * AirAccelerationSpeed * deltaTime;
    9.                             }
    10.  
    11.                             // Gravity
    12.                             currentVelocity += Gravity * deltaTime;
    13.  
    14.                             // Drag
    15.                             currentVelocity *= (1f / (1f + (Drag * deltaTime)));
    16.                         }

    This'll come by default in future versions. Just note that "MaxAirMoveSpeed" isn't used anymore; it's just AirAccelerationSpeed now
     
    Last edited: Mar 24, 2019
    Vincent454, Zhialus and Shturmovik like this.
  5. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    Ahh, yes, thank you very much. That's the sort of simple solution I was envisioning but couldn't get to work in practice.

    You say to replace the content of 'else' with this new code you provided; did you leave out everything in "// Prevent climbing on un-stable slopes with air movement" and the calculations beneath it with "Vector3 velocityDiff" because it's simply not relevant to this specific topic, or are those sections going to be integrated with this new way of handling air movement?

    The answer might be obvious, but those calculations are a bit above my current understanding so I'm not sure whether they're still necessary, and if they are, how they would blend together with the new changes you provided. Thanks for your time.
     
  6. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    oh, right. I forgot about that. Here's the final code:
    Code (CSharp):
    1.  
    2.                         // Air movement
    3.                         else
    4.                         {
    5.                             // Add move input
    6.                             if (_moveInputVector.sqrMagnitude > 0f)
    7.                             {
    8.                                 Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
    9.  
    10.                                 // Prevent air movement from making you move up steep sloped walls
    11.                                 if (Motor.GroundingStatus.FoundAnyGround)
    12.                                 {
    13.                                     Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
    14.                                     addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
    15.                                 }
    16.  
    17.                                 currentVelocity += addedVelocity;
    18.                             }
    19.  
    20.                             // Gravity
    21.                             currentVelocity += Gravity * deltaTime;
    22.  
    23.                             // Drag
    24.                             currentVelocity *= (1f / (1f + (Drag * deltaTime)));
    25.                         }
     
    Zhialus likes this.
  7. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    Thank you very much!
    It's hard to find an asset creator that produces both excellent quality and that's so responsive and active in the community, your efforts don't go unnoticed, keep up the great work!
    ____

    EDIT: After trying it out it works great with adding the extra movement, but removes the other effect I was trying to emulate, the "post-jump regret grace period" where very briefly after jumping you're able to reverse yourself to nearly where you started giving players another chance to line up the jump if they were unsure. Have you got any rough suggestions on how to go about this?

    My old controller, before swapping to yours, had a sloppy method of calculating the direction of the velocity relative to the direction of the jump and then boosting / inhibiting the amount of air control you'd receive based on that (allowing me to boost it if they jumped forward and hit back, but limit it while going diagonally so they can't abuse the system) but that involved a huge amount of testing and tweaking numbers.

    I attempted having a short period like your jump grace time in which air-movement will use the old code since this feature worked in that version for the reasons we talked about, but it simply led to the jump feeling much less responsive and generally "off."
    ______

    EDIT-EDIT: Also, with the current version it seems that the longer you fall the faster you'll be able to fly off in any direction since I think the air acceleration speed compounds? not sure if a simple clamp would fix that or if it needs to be tweaked slightly in a different way
     
    Last edited: Mar 25, 2019
    PhilSA likes this.
  8. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    I managed to find a way to get this to work by re-adding a MaxAirMoveSpeed and then applying this to the currentVelocity with a smoothDamp using the AirAccelerationSpeed as it's timer. I also added a line to the jump code that sets a variable upon jumping to keep track of what the currentVelocity was when you jumped.

    Using that I was able to add appropriate Mathf.Clamp's onto the currentVelocity to make sure that the air-movement didn't compound past the value I wanted it to(+3 or -3 in any direction, but since currentVelocity takes into account horizontal movement while jumping, that's why I keep track of what the velocity was when I jumped, since if I jumped with a currentVelocity.x of 5, I would want the currentVelocity.x + air-movement to Clamp at 8 instead of 3)

    HOWEVER, now I've encountered a new problem, when you stand still and jump(meaning that air-movement is clamped at +3 or -3 in all directions) that works fine. BUT, when you walk off a ledge (since you're not grounded) it also Clamps air-movement at 3, and I get stuck for some reason. It drops current velocity to 0, and I'm not able to increase it on that specific axis plus or minus, even though it's supposed to be Clamped at 3 not 0. I was able to mildly solve this by adding a 0.1 to the MaxStableDistanceFromLedge, I'm confused about this interaction.

    Outside of the previous strange interaction with ledges, the new issue is that if I have a move speed of 5 and walk off a ledge, my currentVelocity is immediately Clamped to 3 which is jarring. Is there a way I can preserve my movement velocity in a decaying over time manor when walking off a ledge? I still want the max air-movement to be 3, but maybe when walking off a ledge specifically I can smooth the Clamp from my move speed down to the air-move speed?
     
  9. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I'm back on this issue now. I'll admit it's a bit difficult for me to understand exactly what you just described, but your ledge instant-clamp problem sounds like it would be hard to solve without re-thinking the air movement algorithm. But now I have a new version of air movement ready. Do you think something like this behaves the way you'd expect? (notice MaxAirMoveSpeed is back)

    Code (CSharp):
    1.  
    2.                         // Air movement
    3.                         else
    4.                         {
    5.                             // Add move input
    6.                             if (_moveInputVector.sqrMagnitude > 0f)
    7.                             {
    8.                                 Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
    9.  
    10.                                 // Prevent air movement from making you move up steep sloped walls
    11.                                 if (Motor.GroundingStatus.FoundAnyGround)
    12.                                 {
    13.                                     Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
    14.                                     addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
    15.                                 }
    16.  
    17.                                 // Limit air movement from inputs to a certain maximum, without limiting the total air move speed from momentum, gravity or other forces
    18.                                 Vector3 resultingVelOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity + addedVelocity, Motor.CharacterUp);
    19.                                 if(resultingVelOnInputsPlane.magnitude > MaxAirMoveSpeed)
    20.                                 {
    21.                                     addedVelocity = Vector3.zero;
    22.                                 }
    23.                                 else
    24.                                 {
    25.                                     Vector3 velOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity, Motor.CharacterUp);
    26.                                     resultingVelOnInputsPlane = Vector3.ClampMagnitude(resultingVelOnInputsPlane, MaxAirMoveSpeed);
    27.                                     addedVelocity = resultingVelOnInputsPlane - velOnInputsPlane;
    28.                                 }
    29.  
    30.                                 currentVelocity += addedVelocity;
    31.                             }
    32.  
    33.                             // Gravity
    34.                             currentVelocity += Gravity * deltaTime;
    35.  
    36.                             // Drag
    37.                             currentVelocity *= (1f / (1f + (Drag * deltaTime)));
    38.                         }

    The only real addition here is the chunk of code before "currentVelocity += addedVelocity". It's basically the same velocity handling as the previous snippets, but with a "MaxAirMoveSpeed" handling. It allows for "additive" air movement, but the movement resulting from inputs will be limited to a certain maximum. That way you can have a stronger acceleration to let you air-move back to where you started your jump in case you changed your mind, but you won't be able to reach ridiculous speeds
     
    Last edited: Mar 30, 2019
  10. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    Yup, that does work how I would expect in regards to jumping forward and being able to immediately move backwards when applying input. What's weird is how it works with jumping combined with air-moving.

    With yours, If I start at (0,0,0) and I jump with a velocity that will put me at (5,0,0) when I land if I don't do anything, unless I have the MaxAirMoveSpeed set ABOVE 5 it doesn't seem that I'm able to go past (5,0,0) if I air move while jumping. If I set it above 5, I'll be able to travel the same distance if I simply jump without moving, and then air-move the whole way. I'm confused by this since it doesn't seem to work additively with the jump even though it should?

    The version I created works in that If I start at (0,0,0) and I jump with a velocity that will put me at (5,0,0) when I land, and my Air-move speed is "3," if I were to hold input during the jump, it'll place me roughly at (8,0,0). Also, since I'm using clamps, if I jump with that same velocity and hold in the opposite direction, it'll quickly negate the jump velocity(due to a quick acceleration time I have set) but still cap at 3 units moved per second, meaning I'll be able to end up at about where I started if I'm quick, or fall straight down where I am if I use it somewhere in the middle of the jump. Hopefully that makes sense.

    Capture.jpg
    Here's a picture of the effect I'm looking for. I was able to achieve this using my ludicrous clamping method.
    I also managed to retain my velocity when walking off ledges by adding another variable to my clamps. It adds your current velocity to the clamp when leaving a ledge, and smooths it down until it reaches the normal air-move clamp so the transition from moving at full speed to only being able to move at air-move speed isn't so abrupt.

    Here's the code that I've got working.
    project on planes might improve it, but I don't know how to use them yet. I don't want to ask more of you than I have, so I won't ask you to fix my code / make it better, but maybe try feeling out the differences between what you've got currently and what mine does and implement what I'm doing in a better way if you like it

    (notice: The "jumpVelocityFlat.x & .z" that I use is simply set to the currentVelocity.x & z right after "ForceUnground" in the velocity handling section of the standard jump code)

    Code (CSharp):
    1.                     // Air movement
    2.                     else
    3.                     {
    4.                         // Add move input                      I forget why I added this, maybe remnants of testing that was never deleted, not sure if necessary
    5.                         if (_moveInputVector.sqrMagnitude > 0f && !Motor.GroundingStatus.IsStableOnGround && !Motor.GroundingStatus.FoundAnyGround)
    6.                         {
    7.                             Vector3 addedVelocity = _moveInputVector * MaxAirMoveSpeed;
    8.  
    9.                             // Prevent air movement from making you move up steep sloped walls
    10.                             if (Motor.GroundingStatus.FoundAnyGround)
    11.                             {
    12.                                 Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
    13.                                 addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
    14.                             }
    15.  
    16.                             // Smooths from current velocity to goal velocity
    17.                             currentVelocity.x = Mathf.SmoothDamp(currentVelocity.x, currentVelocity.x + addedVelocity.x, ref airMoveRefVelocity, AirAccelerationSpeed);
    18.                             currentVelocity.z = Mathf.SmoothDamp(currentVelocity.z, currentVelocity.z + addedVelocity.z, ref airMoveRefVelocity2, AirAccelerationSpeed);
    19.  
    20.                             // Clamps velocity when airborn to MaxAirMoveSpeed
    21.                             /// Also accounts for the velocity from a jump, This way the air-movement is additive always adding its exact amount from you're current velocity
    22.                             if (!Motor.GroundingStatus.IsStableOnGround && !Motor.GroundingStatus.FoundAnyGround)
    23.                             {
    24.                                 if (jumpVelocityFlat.x > 0)
    25.                                 {
    26.                                     currentVelocity.x = Mathf.Clamp(currentVelocity.x, -(Mathf.Abs(addedVelocity.x)), (Mathf.Abs(jumpVelocityFlat.x) + Mathf.Abs(addedVelocity.x)));
    27.                                 }
    28.                                 else if (jumpVelocityFlat.x < 0)
    29.                                 {
    30.                                     currentVelocity.x = Mathf.Clamp(currentVelocity.x, -(Mathf.Abs(jumpVelocityFlat.x) + Mathf.Abs(addedVelocity.x)), Mathf.Abs(addedVelocity.x));
    31.                                 }
    32.                                 else
    33.                                 {
    34.                                     currentVelocity.x = Mathf.Clamp(currentVelocity.x, -(Mathf.Abs(addedVelocity.x) + Mathf.Abs(ledgeVelocity.x)), Mathf.Abs(addedVelocity.x) + Mathf.Abs(ledgeVelocity.x));
    35.                                 }
    36.                             }                                            
    37.  
    38.                             if(!Motor.GroundingStatus.IsStableOnGround && !Motor.GroundingStatus.FoundAnyGround)
    39.                             {
    40.                                 if (jumpVelocityFlat.z > 0)
    41.                                 {
    42.                                     currentVelocity.z = Mathf.Clamp(currentVelocity.z, -(Mathf.Abs(addedVelocity.z)), (Mathf.Abs(jumpVelocityFlat.z) + Mathf.Abs(addedVelocity.z)));
    43.                                 }
    44.                                 else if (jumpVelocityFlat.z < 0)
    45.                                 {
    46.                                     currentVelocity.z = Mathf.Clamp(currentVelocity.z, -(Mathf.Abs(jumpVelocityFlat.z) + Mathf.Abs(addedVelocity.z)), Mathf.Abs(addedVelocity.z));
    47.                                 }
    48.                                 else
    49.                                 {
    50.                                     currentVelocity.z = Mathf.Clamp(currentVelocity.z, -(Mathf.Abs(addedVelocity.z) + Mathf.Abs(ledgeVelocity.z)), Mathf.Abs(addedVelocity.z) + Mathf.Abs(ledgeVelocity.z));
    51.                                 }
    52.                             }
    53.                        
    54.                         }
    55.  
    56.                         // Adjust velocity clamps to retain velocity for a determined amount of time when running off ledges
    57.                         ledgeVelocity.x = Mathf.SmoothDamp(ledgeVelocity.x, 0, ref ledgeSmoothRef, offLedgeClampDeceleration);
    58.                         ledgeVelocity.z = Mathf.SmoothDamp(ledgeVelocity.z, 0, ref ledgeSmoothRef2, offLedgeClampDeceleration);
    59.  
    60.                         // Gravity
    61.                         currentVelocity += Gravity * deltaTime;
    62.  
    63.                         // Clamps gravity at max value, might want to change maximum incase of other effects higher than a jump
    64.                         currentVelocity.y = Mathf.Clamp(currentVelocity.y, terminalVelocity, JumpSpeed);
    65.  
    66.                         // Drag
    67.                         currentVelocity *= (1f / (1f + (Drag * deltaTime)));                    
    68.                     }
     
  11. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I tried the test with the code I posted above:


    It seems to be doing what you asked (?). Red lines represent landing points
    I think the only issue in your test was the values. The problem of being "able to travel the same distance if I simply jump without moving" is probably due to you having an air move acceleration that's too strong. In short:
    • MaxAirMoveSpeed: This should be higher than your "MaxStableMoveSpeed" if you want your air jumps to possibly go faster than regular running. It represents the maximum total speed that you can reach with the help of inputs
    • AirAccelerationSpeed: Reduce this if you don't want your stationary jump to go as far as your running jump
    • Drag: Increase this if you want your character to
     
    Zhialus likes this.
  12. kholera

    kholera

    Joined:
    Mar 6, 2014
    Posts:
    9
    Hi @PhilSA,

    I purchased the package recently as I was very impressed with how robust the features are compared to my early attempts. However, I have noticed going through the examples that some prefabs are missing on import. For example, the "OrbitalCamera" prefab is not in the Assets folder at all, and appears as a Missing Prefab in the example scene in question. I am using Unity 2018.2.20f1, and imported to an existing project. Is this a known issue that can occur? Thanks for your help.
     
  13. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Hi, could you specify which scene(s) contain the missing OrbitCamera?

    I did get rid of that prefab a few versions back, but I thought I removed/replaced it everywhere
     
  14. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Heads up everyone; v3.1.0 will land on the store soon and contains a small architectural change that affects the way you make custom CCs. BaseCharacterController and BaseMoverController have been converted to interfaces. But don't worry; the conversion process is short & painless.

    First post of the thread contains the details in Release Notes and Upgrade Guide
     
    Last edited: Apr 2, 2019
  15. Zhialus

    Zhialus

    Joined:
    Jan 3, 2019
    Posts:
    16
    Ahh, yes, I see whats happening. I was using your values how I was using mine, in that my MaxAirMoveSpeed was functioning as an addition to my move speed, having you point out that it represents the total speed makes more sense.

    As far as the Acceleration you were correct there as well with it being due to a high value, but without it, the player is unable to negate the velocity of a forward jump fast enough for the "change your mind" mechanic. Which is what led me to the clamps since then I could have a high acceleration to negate the jump quickly, but still cap the distance they are able to travel to a slow speed.

    Also, having MaxAirMoveSpeed be additive instead of the totality of move speed means that when falling for a long period of time the player can still only move slowly compared to setting it above move speed allowing them to travel faster in the air(given they've fallen long enough for the AirAcceleration to reach its end).

    I'm realizing the list of criteria we've set for our jumping might have conflicting desires in functionality, but I feel there must be a way. I wonder if there is some possible way to integrate the two codes we've written, is there a deeper reason that you used MaxAirMoveSpeed as a total move speed instead of an addition to move speed, or that you avoided clamps? You understand the back-end of your code more than I so I trust your coding choices more as mine might cause issues with determinism or other interactions I haven't yet found while simply jumping back and forth haha.
     
  16. Zeffi

    Zeffi

    Joined:
    Nov 18, 2017
    Posts:
    24
    Looking forward to v3.1! You've done a really neat asset, well worth the money. I'm running it in my own update cycle (so physics only run in "active" game states) and it works like a charm once I figured out the kinks (had to add my own call for the regular update too, but that's np) :)

    I have only a small question, perhaps you can direct me where to go for that:
    Currently, a moving platform moving into the player/other characters causes the player/other objects to be pushed out. I'd like to cause a "squish" instead in some situation.

    To detect this, and write my handling for such cases, would using the overlapResult struct array (in _overlaps, which I CAN apparently access via Overlaps) be a good idea? Ie, something like:

    1. If an object canBeSquished, check if the overlapResults contained the collider of an Object that canSquishCharacters
    2. If an object is detected, store it and check again next frame
    3. If it happens for x frames (based on delta time, not framecount ofc), squish

    Or is this generally not safe, since the script tends to be too strict in such cases?

    It's probably possible to also check for multiple frames if a squishable character is in the movement direction of something that can squish, but since your script already handles the overlaps, it seems best to first see if I can add to the script, rather than add even more capsulecasts/overlap calls to each update.

    I'm asking, instead of messing around right away, since I assume I am not the first person to ponder this use case, and I rather ask first rather than run off on a fool's errand :) Sorry if this is a silly question.


    (Some position correction is great, and I want to keep this, but I'd like to handle cases where a moving platform is moving into the player/enemies from above continuously causes the player to be ported out, as it happens currently if I test it in the "sandbox" scene.
    This would let me do traps and the like, or let the player cause a boulder to drop on a foe)
     
  17. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    So I'm slightly concerned about upgrading. Mainly in any changes that might involve math changes in movement logic or deprecated methods we are depending on. Anything stand out as potentially problematic? Just checking...
     
  18. kholera

    kholera

    Joined:
    Mar 6, 2014
    Posts:
    9
    Hello again. I took a screenshot of the instance. This is in Walkthrough Scene 1. It appears to be an issue in several of the Walkthrough scenes however. Perhaps I grabbed an old version by mistake?

    walkthrough-scene-1.png
     
  19. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    It sounds like you had the scene from a previous version and then updated KCC to a newer version. I'd suggest deleting the KinematicCharacterController folder entirely and reimporting the latest version
     
    Last edited: Apr 3, 2019
  20. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Here's what you need to know:
    • The only real "math change" in the core components is that some bugs were fixed with step-handling and snapping on ledges, and also "ForceUnground" takes a time to stay ungrounded as parameter (and this is not a framerate-dependant problem since the character operates on a FixedUpdate)
    • Air movement handling did change, but that's only part of the example CC. You can still keep your own velocity-handling code without problems
    • There are no deprecated methods in this update, only “HandleSimulatedRigidbodyInteraction” and “HandleMovementProjection” that have been moved to the KinematicCharacterMotor class. These were previously virtual methods in BaseCharacterController, but you can still override them by creating a class that inherits from KinematicCharacterMotor
    All in all, I think there is no risk in upgrading to 3.1.0

    This makes me realize, though.... I should probably make it so that ForceUnground() at least forces the next update to unground even if you give it 0f as the time parameter. That way you'd have maximum determinism. It's a very minor issue that probably won't affect anyone unless they're making a deterministic online game, but I'll add it to the next update
     
    Last edited: Apr 3, 2019
  21. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Great thanks for the reply. And keep up the good work good to see you had some time again for this project. One of my all time favorite assets that has always just worked.
     
    PhilSA likes this.
  22. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Um, apparently my v3.1.0 failed to upload because the store says "0 bytes" in package size and downloads don't work.

    Apologies for the inconvenience. I've re-uploaded and the package should be coming soon!
     
  23. E_Urban

    E_Urban

    Joined:
    Sep 16, 2014
    Posts:
    8
    Ah that explains why I haven't been able to download it!
     
  24. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Yeah, that's how I would expect this to work. Or, with a parameterless version of the function.
     
  25. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    What I'm having trouble understanding is this:
    1. You've previously mentioned that a problem of high acceleration is that you can basically travel just as far with a "stationary jump + air move" as with a "running jump + air move"
    2. But you also want to be able to cancel-out the distance of a "running jump + air move" by air-moving back to the initial jump spot if you need to
    I feel like you can't have these two requirements coexist together...
    • Case #1 requires that your air move/accel speed to be slow if you don't want a stationary jump to let you move as far as a running jump
    • Case #2 would require your air move/accel speed to be fast if you want it to be able to cancel out all the velocity of a running jump
    Maybe what you need is this:
    • Low MaxAirMoveSpeed
    • High AirAcceleration
    • add a forward velocity impulse on jump through script, instead of relying on air movement to give you that extra "running jump" speed?
    That way your running jumps will go further than you could ever go with a stationary jumps (due to the jump forward impulse), you'll be able to do the "change of mind" thing (due to high acceleration), and you won't be able to travel way too fast in-air (due to low MaxAirMoveSpeed)

    I think working with total speed just gives you more power. Working with a speed "additive to ground speed" would not let you do anything more than the total speed approach, but it would be more awkward to handle cases where you want your max air move speed to be smaller than your ground move speed (because then you'd need to work with negative values). Also maybe you want your max air move speed to be a fixed value and not have to change it every time you change ground move speed

    Axis-wise clamping as in what you do in your code would not be an all-purpose solution, because it always assumes the default "up" direction. So if you try air-moving around the planet in the demo scene, you'll probably find out that there are problems. It also means your "diagonal" speeds will be greater than the limits you imposed, because the magnitude of the (1,0,0) vector is smaller than the magnitude of the (1,0,1) vector, even if each axis has a max of 1. Plus, I realize that this is not at all a convincing argument on my part, but working with specific axis like this is something that has come to trigger my spider-senses over the years. I've very often gone in that direction in the past only to realize that there are edge cases where this causes problems, or that it limits the versatility of the code too much

    _____________________________

    EDIT!
    I've actually found out there was a problem with my code too. It made "turning back" impossible once we were going faster than the MaxAirMoveSpeed. Here's the corrected code:

    Code (CSharp):
    1.  
    2.                         // Air movement
    3.                         else
    4.                         {
    5.                             // Add move input
    6.                             if (_moveInputVector.sqrMagnitude > 0f)
    7.                             {
    8.                                 Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
    9.  
    10.                                 // Prevent air movement from making you move up steep sloped walls
    11.                                 if (Motor.GroundingStatus.FoundAnyGround)
    12.                                 {
    13.                                     Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
    14.                                     addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
    15.                                 }
    16.  
    17.                                 // Limit air movement from inputs to a certain maximum, without limiting the total air move speed from momentum, gravity or other forces
    18.                                 Vector3 resultingVelOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity + addedVelocity, Motor.CharacterUp);
    19.                                 if(resultingVelOnInputsPlane.magnitude > MaxAirMoveSpeed && Vector3.Dot(_moveInputVector, resultingVelOnInputsPlane) >= 0f)
    20.                                 {
    21.                                     addedVelocity = Vector3.zero;
    22.                                 }
    23.                                 else
    24.                                 {
    25.                                     Vector3 velOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity, Motor.CharacterUp);
    26.                                     Vector3 clampedResultingVelOnInputsPlane = Vector3.ClampMagnitude(resultingVelOnInputsPlane, MaxAirMoveSpeed);
    27.                                     addedVelocity = clampedResultingVelOnInputsPlane - velOnInputsPlane;
    28.                                 }
    29.  
    30.                                 currentVelocity += addedVelocity;
    31.                             }
    32.  
    33.                             // Gravity
    34.                             currentVelocity += Gravity * deltaTime;
    35.  
    36.                             // Drag
    37.                             currentVelocity *= (1f / (1f + (Drag * deltaTime)));
    38.                         }

    I'll take care of updating v3.1.0 with this fix since I need to re-upload it anyway


    _____________________________

    EDIT 2

    Now I found a new problem with moving sideways. I think I'll have to take my time a bit more and test this properly

    /LongestPostEver
     
    Last edited: Apr 3, 2019
  26. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    My suggested way of detecting this would be through the "OnDiscreteCollisionDetected(Collider hitCollider);"
    This is a rough equivalent of "OnCollisionStay" for rigidbodies.

    So if the "hitCollider" can squish and "hitCollider.attachedRigidbody.Velocity" is going against you, then you can consider yourself squished
     
    Zeffi likes this.
  27. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Was the gliding into corners slow falling issue ever fixed? For reference, the last version I have is the latest from before your long break.

    I could also glide up corner slopes that I otherwise wouldn't be able to walk up due to steepness. This is probably because the velocity projection only takes into account a single slope at a time. So, it flickers between slopes when in a corner. And, when you're allowed to move laterally along one slope, but you're also touching other slopes, the lateral velocity from the last can push you up the first.

    Example slow fall:
     
  28. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I must've missed/forgotten about that one. Just tested it and it's not fixed: https://i.gyazo.com/251907d716220c98c95e1c03ef6db9a9.mp4

    I will add it to my todo list
     
    dadude123 likes this.
  29. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Awesome, thanks! While testing fixes for that, maybe also try testing gliding forcefully into two slopes that are angled, but not enough to allow walking up them. The force from moving across one slope can push you up the second. And, I have a feeling the two issues are related. So, any fix that targets the falling issue will probably need to account for the gliding up slopes issue as well.
     
    PhilSA likes this.
  30. Zeffi

    Zeffi

    Joined:
    Nov 18, 2017
    Posts:
    24
    Thank you! This seems a more fruitful way than my idea. :)
     
  31. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    I'm guessing if you're using this for a 2D game, it doesn't seem like rotating the controller is optional, so you would want to rotate everything by 90 degrees, rework all of the code to use Y axis instead of Z axis, and abandon the 2D scene view option? Seems worth it to get this going for my use case, just curious if there's a smarter work-around before I over-commit.
     
  32. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I wouldn't recommend this for a 2D game since KCC has to use the 3D physics colliders (not compatible with 2D physics). But KCC does support constraining movement to a plane for "2.5D" games though
     
  33. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    Yeah it's kind of 2.5D/3D. I'm going for this effect that zelda has done before:
    Managed to get my character 45 degrees to the ground by just orienting towards gravity with Y/Z gravity and everything is working great

    Except for when jumping and moving forward/backward because of the new capsule rotation is facing 45 degrees towards the ground one side and outward for the opposite direction so I'll do a small jump forward or giant jump backward. I've been trying a bunch of things like rotating the input/velocity/direction back to compensate for the orienting towards gravity, but haven't had much luck. Any chance you could help or point me in the right direction? Can this be done for instance in the ExampleCharacterController, or perhaps the KinematicCharacterMotor like the InternalMoveCharacterPosition?
    Appreciate any help, thanks.
     
    Last edited: Apr 4, 2019
  34. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    Just parent the mesh to the controller and rotate that instead of the whole thing. Don't be afraid of using the hierarchy to compose complex objects from simple objects.
     
  35. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    tenor.gif
     
    andreiagmu, ethanicus, Raseru and 2 others like this.
  36. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    @OhiraKyou 's suggestion of just rotating the child mesh instead of the capsule would be the way to go
     
  37. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    That was initially what I was trying, but there's some problems that come with it. The Kinematic collider is now not parallel with the walls so it now doesn't interact with these 45 degree walls properly (not able to get close to the backside of these walls for one), one solution is I just make it a sphere and forget the top half of the character. The other issue is that the jump and gravity still needs to be 45 degrees (which the other method fixed both of these) for it to make sense for an orthogonal camera in a setting like this. I can modify this when not grounded, doesn't seem to land in the exact spot, but can try messing with it some more.

    Edit: Continued with the whole thing being rotated, had a lot more luck getting this going by using CharacterUp and a true 90 degree up, and using either one or the other for each scenario and is working well so far, just one issue to go. Thanks for the help.
     
    Last edited: Apr 5, 2019
  38. kholera

    kholera

    Joined:
    Mar 6, 2014
    Posts:
    9
    Hello again, I realized the problem was that my version of Unity was pre-2018.3, and I was not getting the proper files as a result. Strange thing, but I updated my version and now I appear to have everything.

    There is one issue I have found, however. The walkthrough PDF appears to still have references to OrbitCamera. I'm wondering if it is somehow still out of date. Was the walkthrough PDF updated to reflect changes? If so, I may just have to figure out why importing does not give me the updated file.
     
  39. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Walkthrough doc is indeed out of date, thanks for pointing it out

    In the meantime, just replace "OrbitCamera" with "ExampleCharacterCamera"
     
  40. DanielSnd

    DanielSnd

    Joined:
    Sep 4, 2013
    Posts:
    382
    I'm having a weird issue since I updated to 2018.3

    I have part of my world around the center of the scene (Vector3(0,0,0)) and part of it that I teleport to on occasion is around Vector3(-800,0,-800).

    Sometimes, not all the time, and usually after I played for a little while when I teleport to around Vector3(-800,0,-800) I'm not detecting collisions at all. My character falls through colliders.

    After fiddling around with it a little bit I discovered that if the collider has a kinematic rigidbody on it my collisions will still be detected and Kinematic Character Controller can stand on it. So I added kinematic rigidbodies to my walls and ground colliders around that area. But There are a lot of other colliders and I didn't want to have to add rigidbodies to everything as that sounds like it could be a performance issue later on.

    Did anyone else encounter any similar issues? Any suggestions on what I could do?
     
  41. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Not sure, but here's an idea:

    In "Project Settings > Physics > Broadphase Type", are you using "Sweep And Prune" or "Multibox Pruning"?

    If it's Multibox Pruning, you need to make sure the "World Bounds" settings right under are big enough to encompass your world
     
  42. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Update on this: I've figured out what the issue is and I'm working on a solution. The fix will be part of the next update. Shouldn't take long
     
    dadude123 likes this.
  43. DanielSnd

    DanielSnd

    Joined:
    Sep 4, 2013
    Posts:
    382
    It was using Sweep and Prune Broadphase, I changed the world bounds extent to 20148,250,2048 now, though. Hopefully that'll fix it, thanks.
     
  44. adouce

    adouce

    Joined:
    Feb 19, 2019
    Posts:
    6
    Hello and thanks for your great work !

    I wondered, what does Motor.GroundingStatus.SnappingPrevented precisely represent ?

    Especially in this part :
    Code (CSharp):
    1. if (currentVelocityMagnitude > 0f && Motor.GroundingStatus.SnappingPrevented) // Keskecé ?
    2. {
    3.     // Take the normal from where we're coming from
    4.     Vector3 groundPointToCharacter = Motor.TransientPosition - Motor.GroundingStatus.GroundPoint;
    5.     if (Vector3.Dot(currentVelocity, groundPointToCharacter) >= 0f)
    6.     {
    7.         effectiveGroundNormal = Motor.GroundingStatus.OuterGroundNormal;
    8.     }
    9.     else
    10.     {
    11.         effectiveGroundNormal = Motor.GroundingStatus.InnerGroundNormal;
    12.     }
    13. }
     
  45. DanielSnd

    DanielSnd

    Joined:
    Sep 4, 2013
    Posts:
    382
    That did not fix it :(
     
  46. ChainsawFilms

    ChainsawFilms

    Joined:
    May 28, 2016
    Posts:
    18
    Hello. I am looking to make impact sounds when running into objects etc. I'm after the collision speed, which with a rigid collision you get with collision.relativeVelocity.magnitude but I'm not sure the best way to do it with this controller. Thank you.
     
  47. OhiraKyou

    OhiraKyou

    Joined:
    Mar 27, 2012
    Posts:
    259
    I'm using Sweep And Prune as well and still glide downward slowly against corners.

    Also, while moving against cracks between a few scaled mesh colliders, in builds of the game (only in builds; not in the editor), I get ejected out, often on the opposite side of the meshes. To see if it was fixed in 3.1.1 of the controller package, I ported it to Unity 2017 (by converting instances of the C# 7 out and default keyword usage to their more verbose versions), and I was still ejected.

    Here are four examples:


    In the example below, I jump between a rock and a wall 3 times—getting ejected out each time—before the GIF loops.

     
  48. transat

    transat

    Joined:
    May 5, 2018
    Posts:
    779
    @PhilSA Does KCC currently work with the preview input system?
     
  49. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I think you should be very aware KCC is a coded asset, that is you want to be a competent programmer before buying it. If you are asking about input it means your expectation was this is some sort of drag and drop thing. It is not.
     
    Vincent454 likes this.
  50. transat

    transat

    Joined:
    May 5, 2018
    Posts:
    779
    Thanks @hippocoder, I'm a reasonably competent programmer but if an integration already exists to simplify the setup process then i prefer that! I was asking because @PhilSA mentioned something in the thread for Unity's experimental third person controller that implied KCC could integrate well with both that and the preview input system. I realise this is all preview stuff and hence unsupported, by the way - just enquiring!