Search Unity

Character Controller Pro

Discussion in 'Assets and Asset Store' started by lightbug14, Jan 15, 2020.

  1. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    Hi,

    I'm tring to make "sliding" slopes.
    The character must be able to climb slopes, but with a force going down (while moving it'll slow him, and if he doesn't move, he will slide down)
    I tried messing with the slopes parameters, but it can only be climbable/not climbable in the end.

    Do you have any idea how I could achieve that?
    Thanks for your help!
     
  2. d3x7er

    d3x7er

    Joined:
    Jun 23, 2018
    Posts:
    40
    Can you help me with 2 questions I have that i couldn't fix myself.

    1. I am trying to switch to the New Input System but I am currently getting these warnings in the console and no inputs are working:
    upload_2021-8-1_15-54-41.png

    What i did was:
    - Install the New Input System Package
    - Download the CharacterActions
    - Create the Input System Handler Script and put it where my Character Actor is.
    That's all but I guess i am missing something because it isn't responding to any keys.

    upload_2021-8-1_15-56-7.png

    2. Can you explain a bit how can I disable different keys for movement. Here is what my case is:
    I am using the default NormalMovement script which does to job for me, but in my case I have 2D character in 3D world so I am using the "Character Body 3D" and would like to move this character only left and right. so W and S or top and bot arrows should not work. And not only that but i would like to bind them for something different than movement.
    The thing is I am not sure what is the most "elegant" way to do it, because I would like to not mess with the NormalMovement script or any other of the default scripts when I want to change what a key does or disable/enable it. Can you point me to what is the best way to do that?
     
  3. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Hi,
    The character from the demo slides if the surface is unstable (slope < slopeLimit). This doesn't mean your own logic (if you have one) should do the exact same thing. Stability defines how things should work internally (CharacterActor), especially regarding unstable grounds and "bad steps".
    That being said, if you want to achieve a mario-like behaviour, then you can define your custom stability definition. Do this:
    1. Increase the slope limit (CharacterActor). This will allow you to climb "any" slope (well, not exactly any, you will be limited to the max allowed value).
    2. Create your own slide logic on top (using a custom state, you can copy paste the one from the demo if you want)

    You wll end up with three different "zones":
    1) Stable Character + Stable movement
    slope <= customSlopeLimit (<slopeLimit).

    2) Stable Character + Unstable movement
    slope > customSlopeLimit (<slopeLimit) && slope < slopeLimit
    Here is where you can simulate the slide. You can use whatever condition you want.

    3) Unstable Character + Unstable movement
    slope > slopeLimit
    Same as 2)


    Just out of curiosity, What happened when you try to change the slopeLimit in runtime?

    Those messages come from the old input manager. My guess is that you didn't change the Human input type of custom (?).

    I've updated this page (sorry! i forgot to mention the brain component, it is mentioned in the "Fundamentals" section):
    https://lightbug14.gitbook.io/ccp/how-to.../implementation/use-a-custom-input-handler

    What you are trying to achieve here puts in evidence one of the many limitations of v1.x.x actions :(. Initially (since 1.0.0) most actions-based features were built with 3D movement in mind (a Vector2). So changing movement from Vector2 to float will break some things, and by break i refer to "Implementation" components, not just Demo stuff (which is not important).

    From the player POV this shouldn't be a problem. You can always ignore the Y component of a Vector2 composite (Movement in this case) by adding a scale Vector2 processor:
    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Processors.html#scale-vector-2

    This also allows you to use W/S/Up/Down for other things as well.
    From the AI POV this can be ugly, because you can say "movement.y = something". Still, you can ignore the y component from the state (by not using it). If you implement your own gameplay logic (which is recommended always) this shouldn't be a problem at all.

    So, for now i would recommend to use the processor (input actions).
     
    Last edited: Aug 2, 2021
  4. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    for anyone interested in making slippery slopes, here is what I ended up using:

    Code (CSharp):
    1. using UnityEngine;
    2. using Lightbug.CharacterControllerPro.Core;
    3. using Lightbug.CharacterControllerPro.Demo;
    4.  
    5. public class PlayerMovement : NormalMovement
    6. {
    7.     [Space(20)]
    8.     [SerializeField] HardInputHandler inputHandler;
    9.     [SerializeField] float minSlipperySlope = 30;
    10.     [SerializeField] float slipperyPower = 100;
    11.  
    12.     public override void UpdateBehaviour(float dt)
    13.     {
    14.         base.UpdateBehaviour(dt);
    15.  
    16.         if (CharacterActor.CurrentState == CharacterActorState.StableGrounded && CharacterActor.GroundSlopeAngle > minSlipperySlope && !inputHandler.Moving)
    17.         {
    18.             CharacterActor.Velocity += CharacterActor.GroundStableNormal * slipperyPower * dt;
    19.         }
    20.     }
    21. }
    The character only slips if he's not moving (represented by inputHandler.Moving).
    minSlipperySlope: minimum angle at which the character will slide
    slipperyPower: speed of slipping

    With small modifications, it would be easy to only slip on certain surfaces.

    The trick is that I was initially using the same code than ProcessGravity. But when the character is grounded, the Y force is just canceled. So I ended up using the normal of the slope instead of just applying a gravity and letting the engine handling it.
    Using the normal, you automatically have faster slopes when the angle is higher.
    If you find a more elegant solution, I'd be glad to hear it!
     
    lightbug14 likes this.
  5. d3x7er

    d3x7er

    Joined:
    Jun 23, 2018
    Posts:
    40
    lightbug14 likes this.
  6. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Oh you are right! I forgot about the vertical velocity. The normal as part of the velocity is a good idea.Thanks for sharing that.
     
  7. Bluelight413

    Bluelight413

    Joined:
    Feb 8, 2018
    Posts:
    8
    I copied the states from Character Controller Pro\Demo\Scripts\States into another folder, so that I could modify them without them being overwritten if I update CCP.

    I tried attaching the copied states to the character in a copy of the 3D Scene, removed the originals, and tested the scene. The Normal Movement works as expected, but the character no longer dashes when I press 'F'. I tested this with both the original Dash State script and the copy attached. It seems that states aren't properly transitioning when a copy of the working Normal Movement is in the place of the original.

    It seems that being in a different folder is causing this issue. I tried creating a copy of Normal Movement in the same folder, attaching it to the character, and setting the Dash script to enqueue a transition to the copy instead of the original. Sure enough, the dash worked as normal.

    What needs to be changed to allow these copies to work when they're in a different folder? My best guess would be that I have to change the file path in the the "AddComponentMenu" attributes.
    upload_2021-8-6_21-3-50.png
    However, there isn't a folder named "Character" in the Demo folder.
     
  8. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Hi @Bluelight413

    That's good.

    If i cut all the states from the demo (+ the DemoSceneManager as well, there is a dependency with NormalMovement there) and paste them outside CCP's folder (e.g. Assets/), everything still works. I would recommend to do this before anything else, that way you can be 100% sure there is nothing weird going on.

    The state machine will find all the states included within the character hierarchy (under the root GO).
    Code (CSharp):
    1. CharacterState[] statesArray = CharacterActor.GetComponentsInChildren<CharacterState>();
    When the transition needs to happen, the FSM will check if X state is contained inside this container.

    My guess is that the "Dash" component is not part of your character
    . Make sure that all the states involved are contained under the root GO (the "character"). I like to add them to the "States" game object.

    Also, be careful with the copies, especially when there is an AddComponentMenu attribute assigned to more than one class. For example, if you have two different MonoBehaviours (e.g. "Dash" and CustomDash) with the same "AddComponentMenu" attribute, then you will be allowed to add only one of those components (from the menu of course).


    That path refers to the "add component" menu (not a "real" path).
    upload_2021-8-9_17-29-2.png
     
    Bluelight413 likes this.
  9. Bluelight413

    Bluelight413

    Joined:
    Feb 8, 2018
    Posts:
    8
    Thank you, I copied the DemoSceneManager and now everything is working!
     
    lightbug14 likes this.
  10. LazyVol4onok

    LazyVol4onok

    Joined:
    Oct 13, 2015
    Posts:
    4
    Hello! I have question about this asset. This asset doesn't have bunny-hopping, right? So, will it be easy to modify code to add it or not?
     
  11. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Hi,
    The demo locomotion state doesn't implement bunny-hopping (BH). I understand that this feature takes advantage of the diagonal velocity (by adding velocity while strafing), right?. There is also friction involved, i think.
    If so, implementing this should be 100% possible (vector math).


    Well, it depends, Do you know the math behind BH? If so, you'll probably need to re-write (or re-implement) "planar movement" (WASD) from zero. Don't worry, the planar movement logic is very straightforward (far from ideal tbh). Internally the locomotion state sets a target velocity and then a "MoveTowards" does the rest (moving from current to target velocity). This works as acceleration + friction all in one, however, i'm not sure if this is going to work well with BH.

    I will try my best to implement this, i'll post the results + implementation here.
     
    Last edited: Sep 2, 2021
  12. Broudy001

    Broudy001

    Joined:
    Feb 12, 2020
    Posts:
    72
    @lightbug14 have you tried using CCP and following a spline? or have any hints on how I could implement it? I have Dreamteck splines. Essentially what I want to do is have the character in a normal 3d world, but they move forwards and backwards along the spline for movement, but I still want things like falling, sliding, and moving platforms. I'm assuming I can set the position of the player, but don't know how I would include the moving platforms etc in that.

    thanks in advance.
     
  13. robingerster

    robingerster

    Joined:
    May 21, 2020
    Posts:
    2
    @lightbug14 Hey I really love your asset and had no issues so far. Except when I try to use Photon. If I add an PhotonView to the Demo Character that is just a capsule as well as a PhotonTransformView the character wont be synced. I will be able to move both at once on one screen since I haven synced the CharacterBrain yet - but more importantly the character position will not update on the other screen. Do you have a basic guide or just some tipps on how to setup photon with your asset?
     
  14. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    You probably need to use a PhotonRigidbodyView component as well.
    https://doc-api.photonengine.com/en/pun/v2/class_photon_1_1_pun_1_1_photon_rigidbody_view.html

    I'm a little more familiar with Mirror.

    Hi,
    This controller relies a lot on my custom interpolation for some (visual) features. If the problem persists, try to disable interpolation (CharacterActor --> interpolate actor).

    Hi Broudy,
    No I haven't, sorry :(

    I guess it is all about getting the closest point to the character, and then modifying the position after the simulation. This should act as some sort of spatial constraint.
     
  15. RSolids

    RSolids

    Joined:
    May 19, 2021
    Posts:
    22
    I messed around with splines and this controller for a bit. I had to "turn off" some things on the controller while setting the position/rotation of the controller. I'm not entirely sure how you would fall and follow a spline at the same time or what that would even look like. So, I'm assuming I'm misunderstanding you. Can you give a more concrete example of what "for a moment" means?
     
  16. Broudy001

    Broudy001

    Joined:
    Feb 12, 2020
    Posts:
    72
    I'm ideally trying to get the player to follow the X and z coordinates of the spline, I've been able to get it working to an extent, but when I add in acceleration into the movement the player tends to go off course a fair bit.

    I'm using dreamteck splines, and getting a world point 1 world unit ahead of the current position, then rotating the player in that direction, then applying my movement, which works fine till I jump or fall then it looks in the right direction but moves it the direction it was in when I left the ground.
     
  17. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Version 1.3.7 should be available now :) [Release notes]


    Quick note: HitInfo, HitInfoFilter and CollisionInfo were converted from regular structs into readonly structs. This basically means these structs are now immutable, their fields cannot be modified after instantiation (a.k.a after using the "new" keyword) in any way. The reason behind this decision is that big structs (structs > 16B) are usually bad for performance, especially if you pass them over and over again (the entire data is copied).

    How this affects you?
    If you are not using CCP's collision methods (e.g. CharacterActor.PhysicsComponent.Raycast( ...) ), then you shouldn't worry about this at all.

    On the other hand, if for some reason you are performing queries using CCP's collision methods, then you will probably need to modify your code just a little bit. For example:
    Before:
    Code (CSharp):
    1.  
    2. ...
    3. HitInfoFilter filter = new HitInfoFilter();
    4. filter.ignoreRigidbodies = true;
    5.  
    6. // Passed by value ---> the struct will be copied.
    7. SomeMethod( filter );
    8. ...
    9.  
    10. // Let's say you have a method that use this "filter" as a parameter
    11. bool SomeMethod( HitInfoFilter filter )
    12. {
    13.        //...
    14. }
    15.  
    and after:
    Code (CSharp):
    1.  
    2. ...
    3. // The constructor must provide ways to initialize those fields.
    4. HitInfoFilter filter = new HitInfoFilter( layerMask , true , true );
    5.  
    6.  
    7. // Passed by reference, no need to add the "in" keyword in this particular case
    8. SomeMethod( filter );
    9. ...
    10.  
    11. // Let's say you have a method that use this "filter" as a parameter
    12. bool SomeMethod( in HitInfoFilter filter ) //<--- it is recommended to use the "in" parameter
    13. {
    14.        //...
    15. }
    16.  

    If you are having issues with this please let me know.
     
    Last edited: Sep 5, 2021
    Arthur-A and Broudy001 like this.
  18. RSolids

    RSolids

    Joined:
    May 19, 2021
    Posts:
    22
    I'm just brainstorming. I'm probably not understanding the situation. It might be helpful to know what your spline looks like.

    I would think that following a spline would be a different state than the example NormalMovement state. So, jumping is going to be different than the jumping in NormalMovement. In NormalMovement, jumping just makes you go up. If you're already moving (in the direction you're facing) on x and z then it will keep on going that way while jumping--even if it makes your character move away (on x and z) from the spline when you land.

    You are wanting to be able to jump away from the spline, but come back to it. So, I would think you would need to do something like figure out how far you want to move in a frame (adding velocity to your position), then project that desired spot on to the spline.

    The first thing I'd try, I guess, would be:
    If walking, project the CCP position + walkSpeed on the spline.
    If jumping, project the CCP position + jumpDistance on the spline.

    Then I'd decide if I just wanted to walk+lerp and jump+slerp to that point, or try to figure out something cooler like one of the ballistics formulas for making something move in a arch to a particular point.

    Either way I would make a new state. When I did my spline experiments it was in a new state. I had a trigger collider set when to got close enough to the spline, and it put CCP into that state.
     
  19. Broudy001

    Broudy001

    Joined:
    Feb 12, 2020
    Posts:
    72

    Thanks for the input that makes sense. I'm using my own states. I was originally using different states for Movement/jump/fall etc, today I moved all those components back into the default movement state I've made its working much closer to what I wanted to do.

    I'm currently updating the rotation first, then updating the character planar velocity to move along the characteractor.forward direction. It looks a little funny when you jump and follow this line around a sharp corner, but when its in actual levels there won't be sharp corners like I have it my test map.
     
  20. RSolids

    RSolids

    Joined:
    May 19, 2021
    Posts:
    22
    I'm glad you got something working! Honestly, I'd like to see how it jumps around corners sometime. It sounds interesting :)

    Have a good one
     
    Broudy001 likes this.
  21. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    Hi !

    Is there any way to disable all collisions temporarily ? (like a ghost)
    Thanks
     
  22. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
  23. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    Broudy001 and lightbug14 like this.
  24. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    Just updated from 1.3.6 to 1.3.7 and it's caused a strange issue. I'm using my own up orientation code, but it references characterActor.Up for it's calculations. My game uses dynamic gravity and it was working on surfaces of all angles with the controls being mapped correctly. Now, it works fully as expected when on a surface with an upwards orientation, but the left and right are flipped when upside down. Forwards and backwards still work though.

    I'm going to have a proper attempt at fixing it later, so it may be something janky I have done that just happened to work before, but I have a feeling it's something to do with the character actor itself.

    Is there anything immediately obvious that has changed in this version that could cause this?
     
  25. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Maybe, i'm not entirely sure. In 1.3.6, the InputMovementReference property was calculated every time you call it (inside FixedUpdate). This wasn't ideal for performance, so i changed that. Now this reference is updated once before the state machine update (which makes sense).

    Questions:
    1) Do you use the state machine input reference as your movement reference?
    (For example: CharacterStateController.InputMovementReference)
    2) Are you updating the orientation before the state machine FixedUpdate? How often do you update this orientation?
     
  26. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23

    So I fixed the problem.
    To answer your questions. 1) Yes, I do. I'm using an external object as the movement reference. 2) The object updates it's position and rotation every FixedUpdate.

    The problem was to do with how I was setting the object's rotation. Previously I was setting the transform.forward and transform.right manually. This has worked up until now. Now it bugs out when upside down, but setting the rotation with Quaternion.LookRotation fixed it perfectly.

    Not really sure if it's a Unity quirk or something (perhaps otherwise innocuous) in this version of CCP. Regardless, it's all fixed. Thanks.
     
    lightbug14 likes this.
  27. RafaelGuimaraesBarbosa

    RafaelGuimaraesBarbosa

    Joined:
    Dec 14, 2019
    Posts:
    15
    I found a bug, when ground is destruct the player float, he doesn't fall.
    this error appears

    NullReferenceException: Object reference not set to an instance of an object
    Lightbug.CharacterControllerPro.Core.CharacterActor.get_GroundPosition () (at Assets/Character Controller Pro/Core/Scripts/Character/CharacterActor.cs:509)
    Lightbug.CharacterControllerPro.Core.CharacterActor.SetDynamicGroundData (UnityEngine.Vector3 position) (at Assets/Character Controller Pro/Core/Scripts/Character/CharacterActor.cs:1869)
    Lightbug.CharacterControllerPro.Core.CharacterActor.HandlePosition (System.Single dt) (at Assets/Character Controller Pro/Core/Scripts/Character/CharacterActor.cs:1911)
    Lightbug.CharacterControllerPro.Core.CharacterActor.PreSimulationUpdate (System.Single dt) (at Assets/Character Controller Pro/Core/Scripts/Character/CharacterActor.cs:1473)
    Lightbug.CharacterControllerPro.Core.PhysicsActor.FixedUpdate () (at Assets/Character Controller Pro/Core/Scripts/Character/PhysicsActor.cs:333)

    It seems that in get_GroundPosition the rigid body reference is lost
     
    lightbug14 likes this.
  28. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    +1 for this issue.

    It rarely happens in my game, but have noticed this on occasion. Not really sure how to isolate it, since it happens so infrequently.
     
  29. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Thanks for sharing that. At least you figured it out.
    I still don't get why using forward and right was even possible ... I'll look into this.
    The recommended way to handle forward, up and right is by using the actor's properties.
    Unlike Unity's interpolation, CCP's interpolation doesn't get reset if the Transform becomes "dirty". In other words, modifying the Transform "shouldn't" do anything (although the execution order matters). When interpolation is enabled, the transform acts just as a visual component, meaning that the rigidbody data is what really matters. For instance, changing the position/rotation using the move/rotate tool during play mode wasn't possible in 1.3.4 . In order to overcome this, i have to "Teleport" the character (= update those interpolation targets) every time the transform becomes "dirty". Teleport does reset the interpolation target.

    Thanks for reporting that! Indeed, the ground has been destroyed but the property is trying to access its rigidbody.

    It should be pretty easy to fix. I have one question: When does your script (destroyer) run? After the simulation (OnCollision/TriggerXXX)? Before (FixedUpdate)? Before the actor FU (e.g. a state)? I'm interested in the execution order, this could potentially fix other issues as well.
     
  30. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    Just to clarify with the first bit, I was setting the transform.right and transform.forward of the external reference object, not the character actor itself.

    I'm still confused as to why it worked before and doesn't now, but as mentioned Quaternion.LookRotation fixes this.

    As for platforms that disappear, some of mine get disabled in Update, some others in FixedUpdate. Not actually sure if only one type can trigger the bug.
     
  31. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Ohh, sorry i'm dumb :D . Yeah, that makes more sense.

    That also confuses me. Assigning a new rotation to the reference will end up modifying its Transform (forward, right and up as well).
    By the way, this is what forward, right and up do internally:
    Code (CSharp):
    1. // The red axis of the transform in world space.
    2. public Vector3 right { get { return rotation * Vector3.right; } set { rotation = Quaternion.FromToRotation(Vector3.right, value); } }
    3.  
    4. // The green axis of the transform in world space.
    5. public Vector3 up { get { return rotation * Vector3.up; } set { rotation = Quaternion.FromToRotation(Vector3.up, value); } }
    6.  
    7. // The blue axis of the transform in world space.
    8. public Vector3 forward { get { return rotation * Vector3.forward; } set { rotation = Quaternion.LookRotation(value); } }
     
  32. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    Hi,

    How would you pause the character?
    I tried using Time.deltaTime but it obviously has other elements paused (like ui) so it's a no go.
    I tried Physics.autoSimulation = false but it has weird effects when it's resume.
    Is there an easy way?
    Thanks!
     
  33. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Hi @titoasty
    ATM there is no built-in pause functionality (CharacterActor).

    Are you sure it was delta time and not time scale? Well, pausing a game normally involves a time scale = 0. Don't worry, you can use the "unscaled time" update mode. From the documentation:
    "This is typically used when animating the UI while the game is paused."
     
  34. titoasty

    titoasty

    Joined:
    Dec 2, 2018
    Posts:
    25
    I changed my code to be able to use timeScale=0.
    Initially, I wanted to make a pause but to keep some elements moving, so freezing only certain parts (including character, but keep decors flowing in the wind for example).
    I tried messing with the character code to replace Time.deltaTime/timeScale to use a custom class but I still had issues to I gave up.

    FYI, here is the class I tried working on:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Assets.Character_Controller_Pro.Core.Scripts.Utilities
    4. {
    5.     public class CharacterTime : MonoBehaviour
    6.     {
    7.         public static CharacterTime Instance
    8.         {
    9.             get; private set;
    10.         }
    11.  
    12.         void Start()
    13.         {
    14.             Instance = this;
    15.         }
    16.  
    17.         public virtual float timeScale { get => Time.timeScale; }
    18.         public virtual float deltaTime { get => Time.deltaTime; }
    19.         public virtual float time { get => CharacterTimeGlobal.time; }
    20.     }
    21.  
    22.     public class CharacterTimeGlobal
    23.     {
    24.         public static float timeScale { get => CharacterTime.Instance.timeScale; }
    25.         public static float time { get => CharacterTime.Instance.time; }
    26.         public static float deltaTime { get => CharacterTime.Instance.deltaTime; }
    27.     }
    28. }
    Then you simply had to add a game object with a script inherited from CharacterTime and override the needed time functions.

    (like this for example: )
    Code (CSharp):
    1. using Assets.Character_Controller_Pro.Core.Scripts.Utilities;
    2.  
    3. public class CustomCharacterTime : CharacterTime
    4. {
    5.     public override float timeScale { get => GameTime.timeScale; }
    6.     public override float deltaTime { get => GameTime.deltaTime; }
    7.     public override float time { get => GameTime.time; }
    8. }
    (GameTime is a basic class mimic of Time but with no impact on Time.timeScale)

    And then in the character controller pro code, changing Time.deltaTime/timeScale to CharacterTimeGlobal.deltaTime/timeScale and so on.
    There still was some issues, I probably think it could have been from my GameTime custom class and/or with coroutines not being paused.
    Nevermind, I solved my issue another way, but I think it could probably be a nice addition. But tricky! :)
     
  35. dylannorth

    dylannorth

    Joined:
    Dec 26, 2015
    Posts:
    9
    Hey lightbug, I'm just wondering is there any reason CharacterStateController is a sealed class? I have previously just made changes to it directly to add support for an additional set of attack states that transition independently from the movement states but I think it would be nice if I could override it to add my additional behaviour without modifying the original class, for now I think I'll just make the methods virtual and unseal the class to break out my added code
     
  36. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    I think I figured out a fix for this. It's more of a hack. In theory the previous issue should only show up for one frame when a platform disappears, so this might cause janky results, but my game can tolerate it.

    In CharacterActor.cs, find the GroundPosition and GroundRotation properties. Change them to this:

    Code (CSharp):
    1.     public Vector3 GroundPosition
    2.     {
    3.         get
    4.         {
    5.             return Is2D ?
    6.             new Vector3 (
    7.                 GroundCollider2D.attachedRigidbody.position.x ,
    8.                 GroundCollider2D.attachedRigidbody.position.y ,
    9.                 GroundTransform.position.z) :
    10.                 (GroundCollider3D.attachedRigidbody != null ? GroundCollider3D.attachedRigidbody.position : Position);
    11.         }
    12.     }
    13.  
    14.     public Quaternion GroundRotation
    15.     {
    16.         get
    17.         {
    18.             return Is2D ?
    19.                 Quaternion.Euler( 0f , 0f , GroundCollider2D.attachedRigidbody.rotation ) :
    20.                 (GroundCollider3D.attachedRigidbody != null ? GroundCollider3D.attachedRigidbody.rotation : Rotation);
    21.         }
    22.     }
    I just made a null check and return the character's position and rotation. Not changed the 2D part since I don't use that.

    @lightbug14 , do you have any thoughts about this?
     
    Last edited: Sep 22, 2021
  37. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Nice trick, thanks for sharing that.

    Thanks for the suggestion, you are the first one to point that out. There is no specific reason for that "sealed" tbh. It would be nice to know which methods are you overriding.


    Thanks for taking the time to propose a fix for this.
    Note that you are returning "Position" and "Rotation" which are character (rigidbody) properties. If the ground rigidbody is null (for whatever reason) it would be better to return the GroundTransform position/rotation instead.

    Code (CSharp):
    1.  
    2.         public Vector3 GroundPosition
    3.         {
    4.             get
    5.             {
    6.  
    7.                 if (Is2D)
    8.                 {
    9.                     if (GroundCollider2D.attachedRigidbody != null)
    10.                         return new Vector3(
    11.                             GroundCollider2D.attachedRigidbody.position.x,
    12.                             GroundCollider2D.attachedRigidbody.position.y,
    13.                             GroundTransform.position.z
    14.                          );
    15.                 }
    16.                 else
    17.                 {
    18.                     if (GroundCollider3D.attachedRigidbody != null)
    19.                         return GroundCollider3D.attachedRigidbody.position;
    20.                  
    21.                 }
    22.  
    23.                 // Fallback to this
    24.                 return GroundTransform.position;
    25.             }
    26.         }
    27.  
    28.         public Quaternion GroundRotation
    29.         {
    30.             get
    31.             {
    32.                 if (Is2D)
    33.                 {
    34.                     if (GroundCollider2D.attachedRigidbody != null)
    35.                         return Quaternion.Euler(0f, 0f, GroundCollider2D.attachedRigidbody.rotation);
    36.                 }
    37.                 else
    38.                 {
    39.                     if (GroundCollider3D.attachedRigidbody != null)
    40.                         return GroundCollider3D.attachedRigidbody.rotation;
    41.  
    42.                 }
    43.  
    44.                 // Fallback to this
    45.                 return GroundTransform.rotation;
    46.             }
    47.         }
    I'm not saying this is the fix (in fact i didn't test this), but at least it shoud do the trick for now.
     
  38. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    Thanks a lot for this. Yours sounds like a better solution. I've not noticed any problems with my hacky fix thus far, but it was hard to trigger the bug on purpose. Definitely going to keep your code and try that too.
     
  39. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    What is the recommended (if any) way to force a state transition? I see that CharacterStateController.EnqueueTransition() only works inside the current states CheckExitTransition() call. This is fine for most things, but if I want to force a transition into a specific state without caring what state the character is already in, is there an easy way to do that?
     
  40. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Unfortunately, this is not possible. In theory, a state transition should be triggered based on pre-defined "inputs" (e.g. Animator's parameters, CCP's CheckExitTransition conditions, etc). So, having an "outsider" that's capable of forcing a transition shouldn't be allowed (in theory). That being said, i understand that this could be super useful. In fact, Mecanim allows this by using Animator.Play/Crossfade.

    I will consider it (1.3.8).
     
    Last edited: Sep 24, 2021
  41. Broudy001

    Broudy001

    Joined:
    Feb 12, 2020
    Posts:
    72
    I usually do this by having a base state which includes this catch all transition, then I inherit all other states from it, ensuring that I include the base.CheckExitTransition() in any inherited methods, not perfect, but works for me.
     
  42. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    That makes total sense. I won't hold my breath, but propose a compromise. Could there be a similar public method PushStateToQueue(CharacterState state) that adds a state into the queue, then uses all the same existing state enter/exit transition logic?

    Again, this isn't a hard request. My current work around is to have a variable containing the next state and a bool used as a trigger. Then just check for the bool in the states CheckExitTransitions()
    It's a little hacky, but allows me to keep the meat of my attack system outside of the CCP derived states.

    If anyone wants to see the game I'm making (using Character Controller Pro as the base controller), check my instagram: https://www.instagram.com/p/CULypTDqCjH/?utm_source=ig_web_copy_link This post shows the first version of said hacks being used to force the character into the dash state from an outside "attack object".
     
  43. dylannorth

    dylannorth

    Joined:
    Dec 26, 2015
    Posts:
    9
    I override Start and FixedUpdate in order to track an additional set of "Attack" states in their own queue, just so that I can handle transitions to/from the movement Character States (Dash/Normal/Ledge/etc) at the same time as I'm dealing with transitioning to/from Attack States (Light/Heavy/Special/etc). In concept I could/maybe should be tracking those Attack states with a completely different State controller, but for now it's a convenience factor of all State handling being bundled together.

    But also maybe I'm thinking about it wrong and all States should be managed under a singular queue, whether movement or attack based or not
     
    Last edited: Sep 24, 2021
  44. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    That was the first thing that came to mind :). By doing that your state is still responsible for that transition.

    Oh, forget about what i said before (i assumed you wanted to force instantly a change of states). That should be possible right now since EnqueueTransition is public, you'd only need a reference to the CSC component. If you push state "X" before CSC's FixedUpdate (default execution order = 0), then that state "X" should be added to the queue.
    I remember now... Back then when i was making this (almost two years ago) i thought about allowing external components to push states into the queue. This is why there is only one queue. At first (before releasing this version of the CSC), only states were allowed to define transitions by manipulating their own queue.

    Very cool! I really like the graphics/aesthetics.One question, Are you using the dash as a knockback?
     
  45. Arthur-A

    Arthur-A

    Joined:
    Mar 17, 2018
    Posts:
    10
    Hey @lightbug14, first of all thank you for a great character controller! I like it a lot and I has already saved me a lot of hours.

    I'm working on my ladder climbing script. When the player is near the ladder and presses action key, I move the CharacterActor to the starting position on the ladder by using Lerp:

    Code (CSharp):
    1. CharacterActor.Position = Vector3.Lerp(CharacterActor.Position, _targetPosition, _transitionToClimbingLerpSpeed * dt);
    However the movement isn't smooth and jittery as you can see on the attached gif. Is that because when modifying CharacterActor.Position the interpolation stops?

    Is there a way to move the CharacterActor from it's current position to target position smoothly?

    Any advice would be greatly appreciated.

    Thank you.

    jitter.gif
     
  46. bunnybreaker

    bunnybreaker

    Joined:
    Dec 10, 2013
    Posts:
    23
    Not using the dash for any kind of knock back, just the homing attack for now. Using it for knockback isn't a bad idea though :p
     
  47. Arthur-A

    Arthur-A

    Joined:
    Mar 17, 2018
    Posts:
    10
    Actually, never mind. I've found the solution, lol.
    I'm just calculating Vector3 from Character to a target position and assigning it as Character's velocity.
     
  48. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    447
    Sorry @Arthur-A i missed your message.

    Yes, calling Position/Rotation will automatically set an internal flag.

    I was going to suggest that :)
    Using CharacterActor.RigidbodyComponent.Move(target) should give you the same result.
    Code (CSharp):
    1. public void Move( Vector3 position )
    2.     {
    3.         if( IsKinematic )
    4.             Interpolate( position );
    5.         else  
    6.             Velocity = ( position - Position ) / Time.deltaTime;  //<----
    7.     }
    8.  
    That makes sense. I think you are talking about "concurrent state machines". See this link:
    https://gameprogrammingpatterns.com/state.html#concurrent-state-machines

    You can have two state controller working at the same time (on one character) independently.
    Things to consider:
    1) A state controller will not only register all the available states within the hierarchy as valid states, but also it will accept only one of each type (e.g. one NormalMovement, one Dash, etc). So, both state controllers must be mutually exclusive. If you have movement states vs combat states this is no problem.
    2) Having multiple states (at the same time) with their own runtime animator controller will cause issues (when assigning them to the Animator).


    I think the best way to handle this is by using multiple FSM for different things (movement, combat, health, etc).

    This will be improved for v2.
     
    Arthur-A likes this.
  49. Tenzho

    Tenzho

    Joined:
    Feb 15, 2015
    Posts:
    4
    Hi @lightbug14 , just purchase the Character Controller Pro via the unity's mega bundle. I've tried many Character controller assets and this is the best one! I'm currently using it along side with your other asset "Grab it". It's working great but I've encounter a problem where if a grab the rigidbody while standing on top of it, I can move along with it. Is there anyway to disable the grab when I'm standing on top of the rigidbody?
     

    Attached Files:

  50. Tenzho

    Tenzho

    Joined:
    Feb 15, 2015
    Posts:
    4
    I am also trying to integrate the unity asset Rewired with the CCP so that it will work with both mouse / keyboard and joysticks interchangeably. Basically I'm using the default UnityInputHandler that comes with CCP and follow this documentation from Rewired to override the Unity Input System to Rewired:
    https://guavaman.com/projects/rewired/docs/UnityInputOverride.html

    I managed to map every action buttons to rewired as I think the rewired script merely replace the Input.GetButton & Input.GetAxis with the Rewired Input. But I am not sure why only the Axes for "Camera X" and "Camera Y" is the only ones unable to override to Rewired.

    Is the camera / mouse movements getting its Input from another script? Otherwise is there anyway to manually map the Camera X and Camera Y onto the right joystick?