Super Character Controller

Note: This project is now deprecated.

Heads up I don’t post on this blog anymore. Can catch me at my new website or Twitter.

Custom Character Controller built from scratch for Unity. Fulfills all common character controller functions such as collision detection and pushback, slope limiting and collider ignoring. New features include the ability to rotate the controller to any angle, sophisticated ground detection, ability to clamp the character to surfaces, and detailed collision response messages. All functions are fully exposed and editable. Also includes the SuperStateMachine, a finite state machine designed to interact with the controller.

GitHub repository of the project to download or contribute to

Note: The GitHub repo is brand new, and is the first open-source project I’ve maintained. For those more experienced than me at this, any suggestions on how to improve it are welcomed.

Example Unity Project containing demo scene (same project as on GitHub)

Unity package containing essential code (.unitypackage file)

Just a blue man in a technicolour world

Just a blue man in a technicolour world


2.0.0: Added a BSPTree to replace RPGMesh, as well as new grounding techniques and recursive collision detection | Erik Ross
Added support for the CapsuleCollider primitive collider | Moodie
1.1.0: Added support for a fixed timestep and moving platforms | Erik Ross
1.0.2: Multiple optimizations | iivo_k
1.0.1: Fixed issue where ignoring colliders didn’t properly work | Erik Ross
1.0.0: Release | Erik Ross

For a more detailed changelog, open the README in the package.


Uses code from fholm, BitBarrelMedia, and UnityGems. Detailed referencing can be found within the README file of the package.

271 thoughts on “Super Character Controller

  1. Pingback: Custom Character Controller in Unity: Part 4 – First Draft | Roystan Ross

  2. Pingback: Custom Character Controller in Unity: Part 5 – Release 1.0.0 | Roystan Ross

  3. I really like the idea behind this controller, but when I try to use it, the character almost always clips through whatever ground I use, even in your demo. I reinstalled unity and have tried the download multiple times with no change. Any ideas?

    • Hey j,

      Does the controller just immediately drop through the ground when you push play? The controller has a main issue where if the delta time between frames is too greater, it will clip through objects during movement. (I bring up this problem in post #3, in the second half.) When you push play in Unity, the time it takes to load everything and begin the play mode is part of the delta time, which means the first frame can execute over a period of 10 seconds (as opposed to something normal like 1/30th of a second), for example, and if the character’s gravity says to move him 10 meters every second, he’ll teleport 100 meters down. As a temporary solution, you can push pause before pushing play, making sure that everything is loaded before the demo starts.

      If this isn’t the issue, could you post a screenshot of the problem and when it happens? I downloaded the package to be sure so it’s working fine on my end.


      • Hi Erik, same here, project loads fine, the character is over the ground, then when I press any direction buton (wasd), it fells trough the ground.
        the console gives a red error:
        “A game object can only be in one layer. The layer needs to be in the range [0…31] UnityEngine.GameObject:set_layer(Int32) ”
        and points to line 257 in mono develop.
        if I just jump it doesn’t fell trought the ground but the console reports the same error.
        Anyway thanks for sharing the code is great.

        • Hey roger,
          So I downloaded the project and ran it, and it worked fine. This confirmed that the issue was most likely not in the code and rather in the project configuration somewhere. The Super Character Controller only really has one thing configured in the project: there’s a custom layer named TempCast that is used to temporarily place objects so that we can run physics functions against them. In the project, User Layer 9 is named ‘TempCast’. I deleted this layer and ran the code and got the exact same error as you two. The controller kind of stuttered and fell through the ground and sent out the same error messages. It seems likely that for whatever reason the project isn’t properly importing the Tags and Layers configuration file. What version of Unity are you using? I’m on 4.5.4f1.

          In any case, your Tags and Layers should look like this:

          If this is the error I’ll try to look into a solution to make sure the project imports properly in the future.

          Thanks for the feedback!

  4. So far so good, however I notice an odd issue. In the testing zone, when i attempt to jump onto a sharp slope, the controller hangs on the fall and idle transition and wont stop jumping on the slope until i fall off it to one side. Is there any fix for this?

    • Hey TeeJay,
      This issue has to do with the IsGrounded function (in the PlayerMachine demo character) and not directly with the SuperCharacterController. I wrote a PM to a contributor who found the same issue, and it was as follows (note that I reference the “Mario machine,” which is my MarioMachine.cs file I am writing for my Super Mario 64 HD project:

      …As I discovered while building the Mario machine, detecting ground is a bit more complex than just checking if there’s anything solid at x distance below you. Here’s an example of what I mean.

      The top pictures are the desired behaviour. When we’re standing right on the edge of a ledge, we could it as “not grounded.” When we’re on a solid surface we are grounded. When we’re standing on a slope, we count it as grounded (typically we also check that the slope angle does not exceed some value). The issue here is that since we detect ground through a spherecast that returns only a single point of contact, you’ll notice that when we are standing on the slope and the ledge our controller is both times contacting at his ‘edge’.

      To resolve this in my Mario machine I have a more complex IsGrounded function that defines whether we’re standing on the ‘edge’ of our controller as how far the point of contact is from the origin of our controller. So on a flat surface it is 0, while in the ledge image I drew it’s about 80% from the center. Then, I build a ratio that lets you be ‘grounded’ further from your origin depending on the angle of the slope you’re standing on.

      Sorry if it’s a bit confusing, it’s a topic I found pretty interesting and was defs planning to write about it sometime, since it took me a bit to get right! Anyways, this relates to the slope issue. I drew the slope picture on the bottom of the image. The reason he keeps swapping between idle and fall is that he keeps ‘climbing’ onto the ledge. The problem is once he’s climbed on to it, he’s standing right on the edge of the controller and is counted as not grounded, so he gets kicked off. And the vicious cycle repeats. It’s something that’s fixed in my mario machine, but I only made a solution that solves it to the degree I needed, so it’s not the most general fix.

      Sorry if I don’t have a direct fix for you, since it’s exam week over here for me. Once I start working on the Mario project and clean up it’s code a bit I’ll swap in Mario’s IsGrounded function and upload it. This is kind of making a pretty good case to relegate some of the more common character functions (grounding, etc) into a utility class or an abstract class or something. Hope this points you in the right direction.

  5. Hello Erik, I’m doing my own character controller for a project and google send me to your blog. I find some things very interestings and i was trying the demo while i detected a very weird behaviour. I uploaded a video with it. I stopped pushing any button about second 9 of the video and it keeps trying to go onto that bump. Thank you for your work.

    • Hey Luis,
      The problem has to do with the IsGrounded function in the PlayerMachine (and not directly with the SuperCharacterController). The one I initially implemented was fairly simple and pretty much just detected if the player was on flat ground or falling. For more complex cases more complex code is needed, which I describe in the comment above.

      For my Mario controller I have a more advanced grounding function, which I’ve added to the PlayerMachine code (aptly named IsGroundedAdvanced) to solve the problem. I’ve updated the Example Project link above with the new code.

      Thanks for posting the detailed bug video too, since it not only helps me but makes it easier for others to quickly see any issues!

      • Well, with the new project i can walk up that bump, and i not supposed to. I fix it in the old project in a very easy way, and for me it’s working ok, just as i wanted, but i don’t know if it can broke another thing. Mi solution it’s just add this code to the PlayerMachine:

        void Fall_ExitState()

        • That will also work. How you code the PlayerMachine is up to you and depends on your needs for your specific project, as the PlayerMachine was not intended to be a universal solution. Another way to prevent the player from walking up slopes would be to change the SlopeLimit parameter in the SuperCollisionType script attached to the ground objects (reduce it to 30 and he won’t be able to walk up the bump)

          • Sorry if i’m nagging, but with the new Advanced function you can have the same problem too. I’ll try to explain it and what i think it’s the real reason. Forgive my english, as it’s not my mother language.

            If you set SuperCollision values in the Advanced project as:
            Stand Angle: 45
            Slope Limit: 60
            Slide Angle: 45
            Slide Continue Angle: 45

            It will do the same as in the video again. Trying to climb and falling all the time without pressing any key.

            Now imagine you are trying to climb that in front of you, when you approach the place you have forward force, and forward acceleration. Then you start to climb, and change to fall state. In that state a vertical force is added, so know you have force forward and down. The down force in the ramp is decomposed into two forces: down and back, and that’s why you fall down that ramp to the beginning. But the back force are done by the Physic engine (not sure about this) and not stored in the moveDirection, so this force is not really giving you momentum. If you fall down a ramp you should have some momentum and go a little farther of the ramp until friction stops you. And as far as i can remember Mario 64 does that, when you fall a ramp it slides with the butt a little far.

            Here as the moveDirection is not changed back because of the fall, when you go back to idle again you still have some force forward and you try to climb up again without pressing any key.

            I’m working on it, trying to figure out how to fix that, and already made some changes to the code to make it work as i want to. I’ll send you the final result, so you can see it.


            • Hey,

              Keep StandAngle at 80. Use the settings:
              StandAngle: 80
              SlopeLimit: 30
              SlideAngle: 30
              SlideContinueAngle: 30

              StandAngle represents the angle of the ground at a maximum that the ProbeGround function will register it as ground. Although “walls” are typically 90 degrees in games, you usually don’t want your player to be able to stand on walls that are close to 90 degrees (hence why I set it to 80).

              This isn’t so much a bug as something you’ll have to implement. You’re mostly correct about how sliding works in Mario64. I’d recommend adding a “Slide” state to represent when you are “standing” on ground that is greater than a certain value, and then when in that state set the player’s moveDirection to be angled down the slope. What kind of behaviour you want depends on what kind of game you’re making of course.

              And don’t worry about your English, it’s still better than lots of native English speakers on the internet 😛

  6. Hello Erik.
    I’m using your controller solution (the state machine is really a nice idea) for my 2d platformer, but i’m getting this problem that i really can’t resolve by myself since i’m not used with physics API.

    Basically my game doesn’t have an “unique” terrain like your demo but its rather made of blocks (just like in the old 2d mario games).
    In my game i have some enemies and characters controlled by AI scripts (made with your superstatemachine) that moves through the level with this simple scheme: if they walks and they face a precipice they keep walking and then fall (like the green koopas), when they are grounded again they restarts walking and if they face a wall they just changes their direction.
    Oh and some of them can jump to climb one block.

    The big problem is that when they walks sometimes they just “slow down”, and sometime even totally stop (while the state is still walkRight/Left) when they are on a border between a block and his next, in a completely random manner (sometimes it happens with a block and sometimes with another), and when they stops sometimes they even falls through ’em, even if there is no physical space between one block and another (and the enemies colliders wouldn’t theorically let this anyway).

    By going step by step i’ve isolated the case: after having suspected of the Pushback void i realised that in truth it happens only after the character falls once: after that it starts to act buggy. Sometimes if i do click on an object in the scene inspector they starts again to act ghost and they falls over, making me suspect that there is some kind of bug/weakness between every frame.

    Do you know why does that happen? Many thanks in advance and regards

    • Yeah, the state machine is awesome! I wish I could take credit for it (UnityGems made the original) but I’ve started to use it for virtually everything (doors, switches, elevators).

      Are you using the box collider primitive on your Blocks? I was working today and noticed some weird issues with box colliders in my Mario build…so I’ll need to investigate if there’s an issue with how collision with box colliders is resolved. Try swapping it to a mesh collider (with the cube mesh filter) and see if that chnages anything.

      Could you post a pic or video of what’s happening for clarity if the above solutions don’t work?

      • Hello
        I tried your solution and it worked even worse (the controller can’t detect ground at all even with mesh renderers and the characters just falls). Anyway it wouldn’t have worked since i use sprite renderers for animations and mesh renderers doesn’t supports ’em.

        Anyway i looked at your posts and i think it’s the same problem the guy who PMd you had: it looks like the controller, even if theorically grounded, thinks he’s ungrounded when on an edge, even if there are two colliders attached. I think it has to do with the sphere used as feet: since the physics uses only 1 point of the sphere to determine if grounded there will be a moment when it falls in situations like those (i think we’ll manage to land on mars when someone will invent an efficent controller that can use box colliders and all the rest for physics)

        By basing on that, correct me if i’m wrong, but i think that the controller logic is like “ok: so here it is the collider where i am right now and it works like my ground. So when i am at his limit, there is nothing else right?”, but it ignores if there is another one attached right next to it. It looks like a very small stick that could fit between extremely small fissures.
        I tried to extend the colliders of the blocks but it doesn’t work (it acts even worse).

        What have you done exactly in your IsGroundedAdvanced solution? I’m interested in it since, if i can understand well, you managed to avoid this problem

        Another simple solution would be check the ground from two points, uh?

        BTW sorry but i’m a little noobish with wordpress and i don’t know how to post pics (but after my description you could easily imagine the scene)

        Thanks anyway for the time spent and regards again

          • Hi
            I wish it was that my problem it would have been easier to resolve! Anyway here it is my problem (sorry if it’s wireframe (and anyway i think it’s easier to see when a block ends and another starts. Here only one character moves so it’s quite easy to follow)

            PS: here i deselected the blocks by clicking on the inspector AND THEN it did what you saw, but as i said it happens in a quite random manner and most of the time it starts falling by himself

            PPS if you’re wondering the sphere colliders in the blocks edges are ignored by the characters by layer so that’s not the problem for sure

              • Is that with the default PlayerMachine packaged with the demo project? That’s hugely bizarre either way, thanks for posting the gif. If you’re able to post the project as a .zip file somewhere (google drive or dropbox) and post it here for PM it to me via my unity account, I can look in to it.

                • Hi
                  Yup it is. Anyway i created a demo of the character AI. Sorry but i can’t give to you the complete game for 2 reasons: 1st it’s too big, and 2nd it’s a finished project (after i correct this bug is in official beta testing phase), so i can’t let it get leaked/stolen (no offence. it’s just precaution).
                  So i made a demo version with paint made graphics, with only the necessary stuff in terms of resources and scripting.

                  I must warn you anyway: since this bug is quite random, it could work in a different manner than mine depending on multiple stuff that i can’t know. I checked and it looks like 8 times up of 10 the bug happens. the 9th and 10th time it requires 2-3 rounds to happen/ it doesn’t happen at all. Be sure to play the scene a couple of times to be sure. I’ll pm you in unity with the link as soon as it finish loading. In the meantime anyway, could you tell me exactly what you did with your advancedgrounded solution? Or at least the algorythm?


  7. Hey, I’ll give you a quick rundown. IsGroundedAdvanced makes use of the Ground object from the Super Character Controller, which is retrieved using ProbeGround(). Ground has three main properties, RaycastHits: Hit, NearHit, and FarHit. Hit is returned from a SphereCast downwards, while Near and Far are returned from raycasting at the two points on either end of the main Hit.point. This is done because when you run a SphereCast and it hits the “edge” of a mesh (where two polygons intersect) it doesn’t actually return the proper angle of either polygon, but rather an interpolation of the two angles. So NearHit is the point closest to the center of your controller, far is the point further (each on either side of Hit.point), each with the proper angle of the polygons.

    Anyways. So IsGroundedAdvanced does a few things: it first checks if you’re standing on ground that is flat enough to even be counted as “ground” and not a wall (I set this to 80 degrees normally). It then checks how far away the point is that you’re “standing” on from the center of your controller. I.e., standing on the very edge of a cliff would be ~95% from the center of the controller, but on a large flat plane the point would be directly under the center, of 0% from the center. Since for my project it wasn’t desirable to stand on the very edge of cliffs, if counts you as ungrounded if you’re just standing on the edge of a ledge.

    However, you’ll notice that as you stand on a slope, the “point” that you’re standing on is implicity further away from the center of the controller. Since I DO want to be able to detect ground on slopes up to 79 degrees (provided they’re not cliffs) I need to account for the fact that the point is going to be far from the center of the controller. So to define an acceptable distance from the center of the controller that is “grounded,” I use the angle that the controller is standing on.

    Kinda confusing but I’m tight on time today, normally I’d draw diagrams and whatnot. The picture I drew about for the PM should be helpful. For the full release of the SCC I plan to write up much more detailed documentation.


    • Hi.
      Ok i’ll look at it. Please let me know as soon as possible if you resolved the bug since as i said afther that we’re almost done and ready to go. And of course you can ask me anything about the project i sent you that is not clear.

      Still many many thanks for the help spent. Regards

  8. Pingback: Super Mario 64 HD – Release! | Roystan Ross

  9. I found an interesting rounding issue with the Transform.InverseTransformPoint() and TransformPoint() methods used in rpgMesh.ClosestPointOn(). The float returned from InverseTransformPoint() and TransformPoint() does not round properly (it’s a float after all), and the tiny inaccuracy was resulting in my character being elevated ever so slightly to where the next time the OverlapSphere did not collide. Rounding the vector right before it’s added to the player’s position fixed it nicely.

    My character’s starting position is (5.3, 0, 16.9), but the value returned from InverseTransformPoint() was (5.3, 16.9000015, .499994). A similar inaccuracy was returned from TransformPoint(), and those tiny bits were enough to move my player just outside where the OverlapSphere could reach the floor.

    Since Vector3s can’t be rounded by any included method, I had to write my own (I put it in SuperMath):
    public static Vector3 RoundVector3(Vector3 vector)
    int sigDigs = 4;
    vector.x = Round(vector.x, sigDigs);
    vector.y = Round(vector.y, sigDigs);
    vector.z = Round(vector.z, sigDigs);
    return vector;

    The Round() method being used there is also custom, since we don’t want to round floats to the nearest int, and since floats don’t have a Math or Mathf method for rounding to a certain number of digits.:
    public static float Round(float value, int digits)
    float mult = Mathf.Pow(10.0f, (float)digits);
    return Mathf.Round(value * mult) / mult;

    Nothing too special, but it did fix the problem.

    My concern is that this approach assumes that a value rounded to 4 significant digits is always more accurate than the non-rounded value – obviously not a valid assumption.

    • I just remembered, this is also with no gravity implemented yet, lol. With a gravity adjustment, it would force it back into the floor. That’s what programming at 2AM will do to you. (>ლ)

      Still, it is something interesting to think about.

      • That’s rather bizarre. An alternative would also be to just use the Transform.localToWorldMatrix and vice-versa and just apply the transformation like that. You could also just manually run the transformation but multiplying in the scale and rotation and then doing the translation to get a local point.

        Normally if you want your character to stand exactly on the ground, having clamping enabled is the best solution. For my Mario project, when Mario is in the “Idle” or “Run” state he doesn’t even have gravity being applied, he’s just locked to the floor and if he strays too far from the ground is swapped into the “Fall” state.

        Either way I’ll look into this sometime soon since I’m writing a replacement for the RPGMesh/TriangleTree using a BSP tree instead, hopefully to make it more efficient. Definitely a good tidbit to know though, thanks!

        • Clamping was enabled at the time, it just placed the character slightly in the wrong place, avoiding future “collisions” in the OverlapSphere.

          Looking forward to the update. 🙂

    • I should put an actual licensing statement in the code, but essentially it’s free to use and redistribute and can be used for anything provided you don’t resell it. This is the same license as all the ones used in the libraries in the code.

  10. Pingback: GAMERS! Want to play some Mario 64 in your Browser ? | Besian Sopa

  11. Pingback: Falcon Kick

  12. Pingback: Super Mario 64 Created In HD Using Unity | Nintendo News

  13. Pingback: 【期間限定?】ブラウザでプレー可能な「Super Mario 64 HD」が登場

  14. Is there any chance at all you could make some PlayMaker actions for this Super Character Controller, so I can use it in place of the standard Character Controller?

  15. Hi, nice work, I’m searching for a new Character Controller, but is it possible to rotate gravity, and walk on walls and things like that? I didn’t get the demo scene to work, I’ve got it working so far so I can run and jump (it’s 2D), but I need to walk on walls and the top

  16. Hey Roystan Ross,

    First of all I would like to tell you that your work is awesome! I love how neat the state machine is. I also have been looking into custom collision systems for unity for a while now and your method seems pretty solid. I am digging into your code and have a few questions I hope you can answer.

    1- Is there a reason that you are using 3 sphere’s to check for collisions instead of using a capsule cast?

    2- What is standing angle variable in the super collision type mean exactly and why do you need it?

    3- There is a bug in the collision system, I am not sure if you are aware of. If you go up the slope in the demo zone and you collide your controller on the side of the wall while you are on the slope and then move back down, the controller will stay up in the air moving along the wall instead of falling down on the slope. Here is a screenshot of what I am talking about:

    4- How would you deal with collision with dynamic A.I ? Would it be inside your super character controller ? For example, if you want to jump on a goomba head to kill him, would you write the logic independent of the super character controller ? Same goes for bumping into spikes etc.

    Sorry if my questions are not clear enough or too generic. Thanks a lot in advance and keep up the good work!


    • Hey Moodie, glad you like it. To answer your questions:

      1 – CapsuleCast ignores any objects that are inside the capsule at the origin. I expand a bit on it more in this post.

      2 & 3 – The idea is that slopes that are at an angle close to 90 degrees should be treated as a “wall” rather than a ground. For most controllers you typically won’t have them either standing on a slope of ~85-90 degrees, or even entering a sliding state on it. It’s used in the ProbeGround method, but it’s mildly broken right now (as you can see with that bug) but I’m working to implement a more robust, functional solution. Without having it your controller with constantly detect “ground” at walls that are around 90 degrees which can cause an array of issues.

      4 – It would be independent for the most part. The SCC is to deal with collisions from the controller against physical objects in the world and react TO them rather than react on them. So it’s job is to hit an object and then resolve the collision so that it doesn’t intersect it, whereas you’d want to right another script to deal with killing the goomba.

      The SCC does provide collision data for hitting physical objects, but for the goomba in my project since you can walk through him I did the collision detection in the MarioMachine class.

      • Hey Roystan,

        Thanks a lot for your reply. Regarding the MarioMachine class, it is not in the package available to download. I am guessing it used to be in the project that you had to take down. If there is any chance you can share that class with me it would be awesome. Other than that thank you so much for everything!


  17. hey erik, thank you so much for sharing your great efforts – everything works like a charm.
    we were wondering however why exactly you mostly used mesh colliders even in cases when a vanilla primitive collider from unity would have sufficed; did you run into any issues with those standard collision meshes that come with unity?

    otherwise keep up the good stuff, we really appreciate it!

    • I’m gonna assume you’re referring to either some instances where I used cube mesh colliders or some weird stuff I did with the cannon and Bob-omb Buddy’s colliders. For the former I think I was having an issue with the controller and was under the impression box colliders were causing a problem, and the latter was a simple hack that helped to push Mario away from the objects.

      If you’re asking about why I never used anything beyond Box and Sphere colliders, this is because they are the only primitive colliders currently supported by the SCC, since you need to write a method to calculate the nearest point on the surface of a collider for each collider type.

  18. It’s amazing what you’ve done here! It’s crazy how hard it is to find a decent character controller like this. I’ve noticed that if you have more than one object with the SuperCollisionType and RPGMesh scripts attached than things will get extremely buggy and the player will start falling through surfaces. I then gathered from your project that only the main terrain object should have the RPGMesh script. Mmm, but now I have a second object that is also “terrain-like” for my project that when I jump to, I clip through a lot near the slopes (it only has the SuperCollisionType script attached to it). Am I missing something? Again, thank you for sharing your work. It’s made my life a lot easier.

    • Oh and another question: Is it possible to interact with Unity’s physics engine with this setup? Since there are no RigidBodies I’m a bit lost.

      • Yes. You’ll need to add a separate collider (ideally a child of your main SCC object) for standard physics objects to collide with. In other words, the SCC collides with the world, while the world collides with a separate collider.

        When I upload a new version of the SCC I plan to include a slightly more extensive demo to show how the features are used, since it can be a bit confusing. Thanks for your comments!

    • You can have as many objects as you want (barring performance issues) with the SuperCollisionType and RPGMesh scripts attached. If it gets buggy with more than one object, something else must be causing the issue.

      Every object with a mesh collider (that you want the SCC to collide with) is REQUIRED to have the RPGMesh component attached.

      • I assumed the bugs were on my end. I’m using this unity extension modelling editor called Prototype which might be causing issues. It lets you do common polygon editing functions and then creates a mesh collider on the fly. Anyway, I’m looking at your TestingZone scene right now and the cube doesn’t have an RPGMesh script on it, but it collides just fine. Well, I’ll keep poking at it.

        • Yeah, only mesh colliders are required to have the RPGMesh attached. The RPGMesh script builds a triangle tree for the attached mesh collider that allows fast calculation of nearest points on the surface of the mesh.

          For box and sphere colliders, calculating a nearest point is very easy and requires no pre-computation.

  19. Attempting to open the sample project in Unity 4.6.2 gives a weird error (“Failed to load window layout. This can happen if layout contains custom windows and there are compile errors in the project.”), and nothing loads properly, not even the sample scene. The only compile error is within Unity’s internal code, somehow.

    What version should I be opening this project with? Or is there a new version of Unity that it does load properly in?

      • Alright, so now I have the demo working in Unity 5, though I’m running into what seems like a couple of really basic problems with it. To make these easier to manifest, don’t rotate the camera at all and use the keyboard to control (so you’re moving along one axis only).

        First: if I push against any vertical walls and jump, sometimes it works right (I jump and come back down) but a lot of the time I’ll get “stuck” in the wall, only moving up a tiny bit, at which point I can keep mashing the jump button and scoot up the wall. It seems to happen more often moving on the X axis (left to right) than on the Z.

        Second: if I jump while moving so that I run into a wall in midair, when I land it will often not trigger the “land” state, and so I’ll be stuck in the “jump” state until I move away from the wall. Even worse, if I enable VSync, trying to do this will often send me through the floor when I land. Again, this happens more often moving on the X axis than on the Z.

  20. Yeah, ProbeGroundRecursive is the grounding method. I’ve actually written a new ProbeGround method, since I’ve found that using recursive methods like the one above (either by reducing the radius or moving the origin position of the cast) can sometimes be unreliable.

    I’ll look into implementing that solution too, though, since it’s a bit simpler than what I have. For my new solution if the SphereCast encounters an angle greater than StandAngle (usually 85-90) I raycast down the slope contacted to get the “ground” that is touching the wall that was contacted. To ensure that ClampToGround works properly however, you need correctly adjust the hit.point and hit.distance to simulate a SphereCast.

    Anyways considering the number of comments I’ve received about this I definitely think I’ll write a post about it to try and filter all the discussion there (as well as to be a foundation point for the problem and motivation).

    Thanks again for the comments guys it really helps!

    • @jarrettbillingsley and Moodie, I’ve uploaded my current Skeleton project I’m developing the SCC in (the beta), and it has some new grounding stuff. It’s fairly complex but it does solve the majority of the issues (I believe!) that have been highlighted. If you end up opening it, I have some walls that are ~80 degrees (I coloured them blue) you can jump up against and properly react to. I also built a little ramp area (also in blue) to ensure the controller doesn’t get stuck there. I’m still developing it but I’m happy with the progress.

      Most of the new grounding stuff is as I described above, but I added in your suggestion Moodie to reduce the radius by Tolerance squared. This ensures that if (for whatever reason) the controller is slightly clipping into anything it doesn’t wreck havoc with the grounding. To fix the issue you described (ground clamping broken due to the change in radius) I wrote a method called “SimulateSphereCast.”

      • Just tried the new beta skeleton project and it works a lot better! None of the issues I had before.

        I did notice something weird in testing pushing against walls. It seems like it’s not zeroing the internal velocity when it collides with a wall. What I mean is if you push against a wall, then jump, then try to move away from the wall in midair, you can’t. But if you’re just against the wall normally, not pushing against it, jump and move away, you can. Also, if you push against a wall near a corner, jump, and move sideways past the corner, you start moving in the direction you were pushing, even though you’re not pushing in that direction at all.

        • This is correct. For the PlayerMachine script I provided, I tried to make it as simple as possible, just providing the bare essentials to demonstrate how the SCC is used. Zeroing out velocity based on collisions with objects is handled differently on a game-by-game basis (Mario 64 for example drops your speed to around 20% of maximum if you collide with a wall at a certain angle, otherwise collisions do not affect speed) and so I didn’t really bother adding it since it would increase complexity.

            • Hey! I have tried it and looks like everything is working as it should :). Thanks a lot for your efforts. I have some questions though but I need to find the time to formulate it and understand your new probe ground code a bit more. Will get back to you soon once I do that. Thanks again for your time!

  21. Hey Roystan,

    Thanks for your detailed post it was really helpful :). I very much appreciate it.

    For my game, the AI have capsule colliders attached since I am trying to avoid using mesh colliders as much as possible. So I wrote a function that calculates the contact point of a sphere vs Capsule collision and would like to share it :). I have tested it and it seems to be working fine! You can find it here:
    If you have any questions about it feel free to let me know.

    Thanks again, you have been a great help.


    • Great stuff Moodie! I put it in my local version of SuperCollider and added it to the main method, and it works great.

      I’m working on some other grounding related issues, once those are complete I’ll throw up a new beta build with it included. Since I cite every contributor, should I just put you under ‘Moodie?’

  22. We should get a forum setup for these discussions. Maybe a repository as well. It looks like there’s quite the community bubbling up to support this project.

    • Agreed. WordPress’s comment system outlived it’s usefulness months ago. And as much as I want this to be an open source project, it’s fairly tough to contribute in a meaningful way without a better system to discuss the problems. A repo would ideally solve this. I’ve used Git before for a Unity project in a team of 4 and it works fairly well, but I’ve never started an open-source project before, so I’d have to research beforehand to get the know-how. I’ll probably add a note on this page bringing up the desire to start a repo/forum to see how much interest it generates and see if anyone with experience could help get it off the ground…especially since there are an awful lot of tools to choose from.

  23. Just wanted to say your BSPTree already works a lot better than the old RPGMesh. I gave it a try in your beta upload as I’d been having trouble with RPGMesh not setting the bounds of a runtime combined mesh correctly (so IntersectsSphere returns false incorrectly). So far your BSPTree works perfectly every time. Looking good!

    • Hey Rollo, glad it’s working out for you. I haven’t thoroughly tested it yet, so hopefully it doesn’t have any major bugs. The algorithm for the partitioning plane is also extremely naive; it just recursively finds the center of the bounding box of a set of vertices and splits it in half on one of the three main axes…that being said, it did offer a pretty solid performance increase over RPGMesh in my tests, so I definitely want it to get to a polished state.

  24. Extremely flexible and full of so much win. Damn fine job dude.
    It would be awesome to see a 2D collider version of this system. (Because trying to mix and match 2D and 3D components is a nightmare.)

  25. Great work on this controller. In working with the latest code drop I have come across two areas in the controller that could be updated to prevent the Null Reference exception when you reach the end of the platform.

    The first is in the IsGrounded method. By adding a null check for primaryGround this eliminates the one area that causes the exception.

    if (primaryGround == null || primaryGround.distance > distance)
    return false;
    In the ProbeGround method where the system tries to set the SuperCollisionType col if you comment out that setting then this will eliminate the exception as well. From what I can see this variable is never referenced pass this point.

    • I added in the primaryGround check, thanks for catching that. For the SuperCollisionType col, I’m not sure which you’re referring to. There are two possible ways the value can be retrieved in ProbeGround (in the primary SphereCast, or should that fail in the fallback raycast) and in both sections it is set to the class property superCollisionType (which although is only used in the IsGrounded method within the class is used within the SCC as well as assumed to be used frequently by classes accessing the SCC, like the PlayerMachine).

      So far I’ve been making the assumption that there should always be some sort of ground below the player, and if not there’s been a problem. Even for things like bottomless pits it’s useful to know that the “ground” is very far away (a giant box collider can simulate this), but it would probably be more robust to just fill in a bunch of infinity values if ground cannot be found.

      • In going over the code for the second item I outlined and checking how I was setting up my character with the colliders I cannot repo what I first saw on the Super Collision Type.

        If I could ask a question. I have not tried to trace this yet but when my scene first starts if I do not move my character and just jump in place when the character lands he falls through the floor and get’s stuck about half his height in. This may be a issue with my model but I wanted to post it to see if you have seen this type of behavior.

  26. I’ve noticed a similar behavior, and it happens if I have a surface near and below the one the character is standing on.

    • Are both of you using the RPGMesh script on your mesh colliders? I had this issue before with RPGMesh and couldn’t properly trace it (it seemed to have something to do with the number of colliders in the scene, which I found bizarre as my Mario 64 project has a huge amount of mesh colliders). In any case I’ve been working on the BSPTree to get it up to speed (the current version that’s uploaded has some minor issues in it’s closest point resolution) so I’ll try to get that updated soon.

      • In my test project I am using the Sanctuary as the platform the player is interacting with. All items under Sanctuary have a mesh collider and a reference to the BSP script. I download the latest Super Character Controller BETA and started from there.

        • I’ve updated the beta project with my latest code, which on my end doesn’t have any issues. If the problem persists please let me know, it could be an error with the way the project’s configuration (layer manager, tags, etc) is being imported.

  27. Nice project.
    I was looking something like this.
    With “Super Character Controller V2 Beta Project” have you made it your demo of Super Mario?
    I want to test it with my own project with custom animations. When you have set our demo, you use apply root motion with animation or move all with SuperCharacterController?

  28. Really nice work. Was just wondering with version 1 to get the angle or collision type of the ground the player was standing on, we would use currentGround which was apart of the struct Ground. In version 2 currentGround has changed to SuperGround so how would I get the angle, collider type etc. now?

    • SuperGround has a few methods to handle retrieving various important data, like Norma(), PrimaryNormal(). A couple other things are accessible as properties, like the SuperCollisionType and Transform. Before I do a full release I’ll definitely need to do a thorough review to ensure everything important is accessible and easy to use.

  29. Hey guys, someone directed me to page regarding your projects etc. I’ve been working on a custom fsm and custom character system for a long time. These incorporate many features ie adjust collider direction/size, 360 movement, automated mecanim controller builder. Once I’ve had a chance to look over your unity stuff, hopefully I can offer some solutions and adjustments.

    • // Makes all characters rotate on the platform.
      void OnTriggerStay(Collider other) {
      if (other.GetComponent() != null){
      //other.transform.Rotate(rotdir * rotspeed*Time.fixedDeltaTime);

      rotdir and rotspeed should be grabbed from whatever code actually rotates the platform. I tend to just use a trigger because I have simple shapes, but you could probably devise a much more elegant solution by making the player check for rotating ground itself.

    • Way I did it is to make two new variables:
      private float rotateVelocity;
      private Vector3 lastEulerAngles;
      Add this to single update:
      if (isClamping && clampedTo != null && clampedTo.eulerAngles – lastEulerAngles !={
      velocity = (clampedTo.eulerAngles.y – lastEulerAngles.y) / Time.deltaTime;
      transform.RotateAround(clampedTo.transform.position, Vector3.up, rotateVelocity * Time.deltaTime);
      Change if(isClamping) in SingleUpdate to:
      if (isClamping){
      lastGroundPosition = clampedTo.position;
      lastEulerAngles = clampedTo.eulerAngles;

  30. A massive noob question…but how do I get this to work? I just attach the script “Super Character Controller” onto my player (which is just a plain capsule right now)? I keep getting this error (along with layer errors and an error about player not being grounded):

    NullReferenceException: Object reference not set to an instance of an object
    SuperCharacterController+SuperGround.PrimaryNormal () (at Assets/SuperCharacterController/Core/SuperCharacterController.cs:819)
    SuperCharacterController.SlopeLimit () (at Assets/SuperCharacterController/Core/SuperCharacterController.cs:236)
    SuperCharacterController.SingleUpdate () (at Assets/SuperCharacterController/Core/SuperCharacterController.cs:205)
    SuperCharacterController.Update () (at Assets/SuperCharacterController/Core/SuperCharacterController.cs:158)

  31. Thank you for all of this. The whole project is very inspiring.
    It gave me another great opportunity to study both unity & coding. Thank you.

  32. Nice project, the demo scenes are great. I noticed that the player never rotates to match the normal of the surface they were on, is this intentional? Your Mario project shows mario rotating so I’m assuming there is something going on. Could you explain?

    • In the Mario demo project the controller isn’t actually rotating to match the normal of surfaces below it, but rather the Mario model itself is the only one rotating (it’s for graphical effect only). Of course as the controller can be rotated, it would be possible to rotate it to match the normal of the surface, but for the Mario project this was unnecessary.

  33. Hello there, just wanted to say that you’ve done a great job with this controller so far. Also, thank you for sharing it! There are many people out there who work on prototypes and stuff but never upload them and just let them die, while everyone’s asking for the source.
    So, big up to you.

  34. Hey Roystan, thank you so much for posting this project and documenting it so thoroughly. It has been a great resource to help me learn some advanced coding techniques in Unity! I’ve been doing some experimenting and I’ve run into a sort of bug, or more likely the controllers limit and I was wondering if you had any thoughts on it?

    When I increase the scale of your spheredemolevel gameobject in Unity by 15 or more, the controller begins to glitch. I’ve posted a gif here: I was hoping you could explain what was going on? If you want to replicate my scene exactly, here is a picture of the setup: (This glitch is on the SpaceZone scene).

    I imagine the issue has something to do with either the mesh density related to the distance the controller checks for mesh vertices or it could be related to the distance of the Planet transform on the Gravity script.

    • Hey nocoast,

      For some reason the player’s own collider (a CapsuleCollider attached to the Art child of the main player object) was not properly assigned into the OwnCollider variable in the SuperCharacterController. The SCC having it’s own collider allows other objects to collide with it, but it’s essential to put it in the OwnCollider slot to ensure the SCC properly ignores it.

      I’ll push up a change to the GitHub and download section later today, thanks very much for the bug report.

  35. Hey Roystan,

    Had a chance to look at your latest grounding methods and they look great! Great Job. I have re-factored your code to suit my game and I have been running into a pushback issue. I tried reproducing the bug on your project and it looks like you have it too. Basically the controller can get stuck between two spheres and will jitter for while when stuck.

    Steps to reproduce:
    1- Set up two sphere objects with a relatively large scale. (8 for example)
    2- Keep a small space between them so the character cannot walk through
    3- Try to move the character through the small space
    4- Notice how the controller starts to jitter and may lose control over it. The controller might also go through the ground.

    Here is a picture to elaborate more on the setup:

    It feels like each sphere is trying to push the controller in a direction making the controller go bizarre. Maybe a recursive pushback method might solve this? Also the biggest issue for me is the fact that the controller goes through the ground and might escape the level. I believe there should be a check where you place the controller back on the ground after a pushback given the controller is grounded.

    Hope you can give your view on this matter :).

    Thank you very much for your time.


    • Hey Moodie, I was able to reproduce your error.

      The controller already does have a recurisve pushback method; you can modify the maximum number of recursions by setting the value “MaxPushbackIterations” (default 2). Increasing the iterations has a dubious effect on this error however…I set it to 10 and it actually increased the error, while setting it to 40 eliminated it. Either way 40 pushbacks is absurd and should never be necessary in a single frame (2 or 3 being a reasonable maximum) which means something is either wrong in the pushback method or in the grounding method.

      The controller should always be placed on solid ground at the end of the frame, if clamping is enabled. Although it’s reasonable to assume in extremely rare cases the controller will clip through the ground, this should not happen frequently and if it does it points to an error in design.

      I’ll try to look in to it sometime this week but either way feel free to open an issue on the GitHub.


  36. Hey Roystan,

    I’m considering switching out the default Unity CharacterController for SCC in the game I’m developing. The tests I’ve been doing so far look pretty promising, having the source code will be a big win (Unity’s CharacterController often does…. odd things!).

    Perhaps you can help me out with something that is stopping me from integrating it into my game though?

    I’ve been playing around in the TestZone scene and noticed that the movement speed is not constant. i.e. when the controller goes down a hill, the speed increases and when going uphill it decreases from the base walk speed. For my own sanity, I measured this in SuperCharacterController::SingleUpdate() with this line of code at the end of the function:

    Debug.Log(“SCC Speed: ” + ((transform.position – initialPosition).magnitude / Time.deltaTime));

    This gives a consistent 6 units/sec on flat terrain, but on a flat test plane (squashed cube primitive) rotated to 75 degrees, the speed going up is more like 1.5 units/sec and going down it can be in the mid twenties! I would expect that the controller out the box would move at 6 units/sec on all inclines that are walkable… not sure if this is a bug or a feature at this stage though? 🙂

    The feel of my game is very reliant on having set speeds for different slope types. I use an AnimationCurve to set a base speed multiplier at angles from -90 to +90 degrees. A practical use case:

    – Basic run speed on flat terrain is 5 units/sec.
    – When the character slides down a railing inclined at 15 degrees, he speeds up to 5.5 units/sec
    – When he slides down a railing inclined at 30 degrees he speeds up to 6.5 units/sec

    Is there anyway I can make this type of system work with SCC? I have taken a look at the code, but am still quite new to the system and haven’t had any luck finding anything relevant yet.



    • Hey Niall,

      What you’ve observed isn’t really specific to the SCC, but rather the implementation in the PlayerMachine. The reason this occurs is due to ground clamping, and before I get into it yes this problem is very easily rectified. What ground clamping is and the reasons for it’s existence are detailed in this post. So how does this affect a character’s speed? This is because clamping “adds” an extra downwards vector to the character’s position after movement has completed (for downwards slopes), and therefore adds extra velocity. (or displacement per frame). When ascending a slope, the controller clips into the slope (as he is moving planar to up vector), and then is pushed outside the slope. This tends to make him move slower than normal. For most pushbacking this is perfectly fine and actually desired behaviour, but for basic movement it can be annoying. The images below show in detail what I mean.

      To avoid this problem, you can set the player’s movement direction to match the normal of the ground he is standing on (SuperGround has two methods for this–PrimaryNormal and Normal). That way, both ground clamping and slope clipping are minimized. Ground clamping is still necessary for when you walk off slight slopes, but if you match your movement vector to the ground normal this is very minimal and will not greatly affect overall velocity. This is how I achieved it in my Super Mario 64 HD project, which also has Mario react differently based on different ground types.

      V is your controller’s movement vector, purple a is the clamping adjustment and orange a is the pushback adjustment. Below is shown a solution where the movement vector goes down a slope. To get this vector, take the Cross product of the ground’s normal (shown in green) and the controller’s Right normal (see an example of getting this Right vector in the LocalMovement() method of PlayerMachine).

      Whoof, that was a lot to go over. Hope this helps, and good luck on your project!


  37. Hey Erik,

    Its me again! Sorry to bother you but I have another Issue that I would like to report. It is kind of related to the previous issue I reported. The problem is that the push back function pushes the controller through the ground in specific scenarios that may be common in games.

    Steps to reproduce:

    1- Create an Inclined box collider as shown in the below image

    2- Move the controller under it as shown in the below image

    3- Move the controller into the collider making the top sphere collider with the box
    4- Watch how the box pushes the top sphere back hence pushing out the bottom sphere below the ground
    5- If you keep pushing against the box, the controller will eventually escape the level

    In your previous post you mentioned “The controller should always be placed on solid ground at the end of the frame, if clamping is enabled.” That is true but I believe the problem occurs before clamping since your code design is as follows:

    ProbeGround -> PushBack -> ProbeGround -> SlopeLimit -> ProbeGround -> ClampToGround

    So in the pushback function I assume the Physics.OverlapSphere checks for colliders starting from the feet to the head. Once it is checking for colliders overlapping the head the box will push back the controller below the ground and exit the PushBack method. The next step in design is the ProbeGround method which I think is the problem. The feet now is below the ground and upon spherecasting no ground will be found yielding to a null reference. I believe there should be some sort of check to place the controller back on the ground directly after pushing back.

    Let me know if I am mistaken since your the one who understands the code the most. I hope I can hear your take on this issue regardless and if you have any Idea on how to fix it.

    Thanks a lot for your time!

    • Hi Moodie, sorry for the extremely delayed reply. I’ve read through your report and was able to reproduce it, so I’ll have to look into a solution. Currently I’m tied up with a prototyping project I’m working on, but rest assured I’ll find time eventually!

      As always, thanks for your detailed and descriptive bug reports.


  38. Hey Ross,

    This time I come on a more positive note :). I have solved the two issues I have reported and I am finally pretty happy with the results.

    Sphere Issue
    What: If you have two sphere colliders with a small gap in between them, the player could lose control of the controller and clip through the ground.
    Why: This is happening because in the probe ground method the controller is detecting the edge of the sphere as ground and is trying to clamp on it. This with the pushback back on forth is creating an unwanted behaviour.
    My Solution: It is very important to diffrentiate walkable grounds and obstacles. You did a very good job with the stand angle and slope limit. But I also went a step further and made my ProbeGround function test against only walkable layers, and the PushBack function against pushback layers. Pushback layers will contain walkable + obstacles, while walkable will only contain walkable ground. Setting the spheres to obstacles solves the above problem and works nicely. The only problem what if they were not obstacles but walkable ground? I think this issue should be a restriction to the design team and it should be designed around it since it is not that common.

    Slanted Wall Issue
    What: If you have a slanted wall that creates this shape “>” with the below as a ground, the above collider could push the controller out of the ground.
    Why: Because in the pushback function, the last pushback is applied to the head clipping the character through the ground.
    My Solution: I have reveresed my check and I always start with the head and end with the feet. Yes this means the head will clip through the wall on top but that is acceptable. It is very important to make sure that the controller NEVER clips through the ground. Clipping SLIGHTLY through walls is fine and it happens in most if not all triple A games anyways.

    1- To fix the slanted wall Issue I have switched from using foreach to for loop which I highly recommend since foreach loops creates an instance of an IEnumerabe on the mem stack each loop which is bad for the memory.
    2- In your code you are creating new instances of classes every frame which I believe is also bad for memory. In my code I have changed those to structs instead of classes, and I added one more variable “isValid”. In your resetGround function instead of setting everything to null which is very dangerous due to null reference exceptions all I do is set to isValid = false. I set back isValid = true if grounds where detected in the probeGround method. This is also useful because if you do not find any ground this frame instead of having a null reference you will still have data about the previous ground. For example if currentground does not exist instead of having the player escape the level you can teleport him back to the last valid position.
    3- In your simulateSphereCast function I really do not understand why you have an extra raycast there. The system is already a bit expensive with all the raycast and I think you can get away with that one. I have wrote my own simulateSphereCast which returns a RaycastHit instead of a bool. I integrated into your code first and seems to be working fine. Some changes will have to be made though so I cannot give you just the functions. However I would like to share my test class. All you need to do is attached this script to an Empty gameobject and then place this Empty gameobject above a box and you can see the results by rotating that box in editor mode in the scene due to the OnDrawGizmos() function. Here is a link to the class:

    I am still working on optimizing the code since I plan to use this for all agents in game (AI plus character) and I need to be able to support a lot of agents at the same time. If anything significant comes up I will let you know. For now I would like to thank you for all the work you did! 🙂


    • Hey Moodie, I saw this when you posted it and finally got time to sit down and read it. I’ll reply to each part in turn for clarity.

      Sphere Issue
      My Solution: It is very important to diffrentiate walkable…

      I really like this solution, since it allows for flexibility if needed, but is also non-intrusive if the designer does not want to make use of it.

      Slanted Wall Issue
      My Solution: I have reveresed my check and I always start with the head…

      I also really like this idea, since it’s a simple solution from this conclusion,

      Yes this means the head will clip through the wall on top but that is acceptable.

      While is entirely correct! As well, clipping through a wall above is often mitigated by code that forces the player to crouch or duck (or something along those lines) and this solution fully supports and endorses that.

      1 – Agreed.
      2 – I’m assuming you’re referring to the GroundHit class, which yes should be a struct (as it is for the most part immutable and is only used for a short period of time)

      For example if currentground does not exist instead of having the player escape the level you can teleport him back to the last valid position.


      3 – Haven’t thoroughly read this, will sit down again soon and update my answers on the subject. I haven’t looked at the SimRaycast code for about 4 months, so I’ll need to remember why I had that raycast!

      If you’re looking for optimizations and are feeling ambitious, you could look into optimizating the BSP Tree construction method, which currently is a pretty naive implementation (although seems to be sound). For your changes feel free to fork off a branch from the GitHub repo and submit it as a merge request when you feel it’s ready.

      In any case, superb work on this! Very clear and thorough explanations, and overall really great additions! Thanks very much for the support and as always best of luck on your project.

    • Hi Moodie,

      Looks like you have made some really great changes/additions to the controller, things that I will likely need in my own game. Not going through the ground under any circumstances is my #1 priority and having surfaces marked as walkable is something that I already do in my current implementation (with Unity’s built in CC).

      I am just about to start implementing SCC into my game and would love to be able to grab your changes from the get go so I second erikroystanross’s request for you to fork it and submit it as a merge request. If it’s not quite ready for that, I’d also be open to you just sending me a zip with the source for me to prod about in 🙂



      • Hey there,

        The reason for not uploading my changes on GIT is mainly because my class structure is different than what Erick has. I have took what I thought is best for my game and what I need from Ericks class only and wrote my own class with a different structure. The core implementation though is technically the same. Hence uploading my changes will take some time to make sure everything works fine with Ericks structure which I do not have at the moment :(.

        Hence what I can do, which will be much faster, is create a new scene in the project with my implementation of Ericks controller. Please note that my structure could still be improved to make it more systematic. For now though its working fine for what I need and will make changes depending on how my prototype progresses.

        I will try to have it online in a day time as I also need to fiddle around to see how GIT works since I am used to SVN.

        Feel free to ask me any questions regarding my setup.


        • So I have added my implementation on GitHub and requested for a pull request. I am not sure how this works exactly but I think Erick will have to approve of my request before the change is live. It would be nice if you can let me know if it worked out.

          Also FYI, my implementation does not include moving platforms since I do not have that in my game and might not have all the features Erick is offering as it is optimized towards my needs.


          • Hi Erik/Moodie,

            Did this stuff ever make it into mainline or did Moodie’s project ever end up online? I will be looking at reimplementing my character controller soon.



            • Moodie pushed a separate folder to the Git repo with some scripts containing his modifications, in the Scripts/Moodie folder.

              I’m currently working on adding TerrainCollider support, but after that is done I’ll probably look into integrating some of these changes in the master controller.

  39. greetings Ross

    I really liked your work and I wish to congratulate and thank you for it. Speaking as the problem I have a mesh designed purposely for the stage and have not gotten the player remains and act upon it, always runs through my mesh is deafult layer has mesh collider, BSP Tree and Super Collision Type, but I can not get it to work, do you have any idea that I needed to make it work? Thank you

    • Hey there,

      Make sure to have a layer named “TempCast” in your project since the system uses a layer by that name temporarily for detecting collisions. If that is not the issue can you be more elaborate on the problem and what errors you are getting.


      • Hey there,

        The project contains the TempCast layer and when I play the character in the scene through the mesh and the error is displayed [SuperCharacterComponent]: No ground was found below the player; level player has escaped.

        It also shows the error in the following lines of code
        SuperGround: ProbeGround (Vector3, Int32) (at Assets / SuperCharacter / SuperCharacterController / Core / SuperCharacterController.cs: 721)
        SuperCharacterController: ProbeGround (Int32) (at Assets / SuperCharacter / SuperCharacterController / Core / SuperCharacterController.cs: 226)
        SuperCharacterController: SingleUpdate () (at Assets / SuperCharacter / SuperCharacterController / Core / SuperCharacterController.cs: 202)
        SuperCharacterController: Update () (at Assets / SuperCharacter / SuperCharacterController / Core / SuperCharacterController.cs: 158)

        But the character in the scenario works testzone the ground by default.

        ¡Thanks for reply!

  40. Hey Erik,

    I have added a test case to the project under Scenes->Moodie->Test. I have simply duplicated your scene and just added two cubes that have a moving script attached to them with one cube moving faster than the other. The case I would like you to see is that if a moving obstacle is moving too fast, the controller will break! If you load up the scene and stand in the path of the slow moving cube the behaviour is what you would expect. Now if you move to the other cube the cube would pass straight through the controller and in some cases the controller would fall through the ground. The reason for this is the fact that the system is based of moving the controller to the closest point on a collider. Since the moving collider is moving very fast the controller would end up in the middle of the collider where the closest point will either be on the bottom/top instead of the side of the cube. So basically there will be some cases where the closest point on a collider is not always the position the controller needs to move towards.

    I know that depending on the game/design this scenario can be avoided but it just got me thinking that the core of the pushback function(Push to the closest point) may behave unnaturally in some scenarios. For example an enemy that has a fast charging attack or fast moving traps. This problem also may occur more the thinner the collider.

    Do you think this issue can be handled with the design of your collision system ?

    Thanks for your time!

    • Hey Moodie, yeah, that was the first thing I noticed when I opened the scene…
      The first solution that comes to mind would be create some sort of bias towards pushing out objects on a specific plane (for most cases along the Y plane), but I haven’t given much thought into how this would be accomplished or how much code would need to be refactored.

      The second solution is a bit simpler. Instead of treating the controller’s 3 (or however many are being used) collision spheres individually, we could gather all the objects collided with and then instead of pushing back each sphere, treat the controller as a capsule shape and push it back once. This would avoid issues where the bottom sphere’s closest point to be pushed back is downwards (since it’s so close to the ground), as the center of the capsule is located at the center of mass of the controller and would intrinsically tend to push itself out of objects along the Y plane.

      Apparently Unity 5.3 includes a Physics.OverlapCapsule too, which would be useful for the above. Either way this is a reoccurring problem and something I’ll have to study a bit more. Thanks as always for the contribution.

      • Thanks for the reply.

        For your second solution you still need to figure out where to push it back once correct? Is it X, Y or Z? For example if you stand on the edge of the cube you will be pushed out to the side which is as well incorrect. Treating them all as one object may solve the pushing back on the Y plane but not in the X/Z plane depending on the scenario. Anyways I think a lot more thinking needs to be done in order to tackle this issue. If you ever implement a solution keep me posted. 🙂


  41. Hi, the controller is perfect! Now I’m just wondering how you manage the player art rotation so it always face forward. You know, like Mario, he does’nt strafe of walk backward. Since the camera controlle seems to make the “player rotate” how do you manage that, animation wise. Thanks! P.S. I do basic programming but really I’m an animator and I just need to access the rigidbody’s local velocity to get my animation going with mecanim.

    • Hey Steeven. Is your name really spelled with two ‘e’s in a row like that? I’ve never seen that before if it is.

      Anyways, for all my player machines I make I always keep the art’s rotation separate from the actually direction the controller is moving. This way, I have full control over which way the character is pointing at all times, since as you pointed out in Mario’s case he always faces forwards, while in a game like Halo (and in my demo) the character always faces the direction of the gun (or camera).

      In the demo the character’s facing direction code is in the PlayerMachine script. This line rotates the mesh to face the direction the character is looking:

      AnimatedMesh.rotation = Quaternion.LookRotation(lookDirection, controller.up);

      …and this line is what rotates the lookDirection variable.

      lookDirection = Quaternion.AngleAxis(input.Current.MouseInput.x, controller.up) * lookDirection;

      Since the controller doesn’t use a rigidbody (they suck for character movement on so many levels), his velocity is controller manually by the variable moveDirection.

  42. Hey, I’ve got a few questions.

    First question:

    I have a pretty old version of your character controller: one that still uses the RPG Mesh. I’d like to upgrade to the newest version, but I’m a bit worried it will break some changes I’ve made. If I were to upgrade, would it cause any issues? If so, any advice on how to minimize the trouble with doing so?

    Second question:

    I’m using this controller in a multiplayer game that’s pretty far along now. I’m having an issue with 2 players colliding with each other. How can I make it so that when one player collides with another, the player’s momentum is transferred to the other? Basically I’m looking for a way to push another player.

    • Hey Liero,
      The major difference between the old and the new (from an external API point of view) are the changes in how the grounding works. In the new one, whether a controller is grounded is calculated inside the SCC class, instead of requiring you to implement your own IsGrounded method (the original demo has IsGrounded in the PlayerMachine, now the PlayerMachine just calls it from the SCC).

      For pushing, as long as there is a collider attached to each player you can access the collision data from the SCC through the collisionData property, which tells you where a collision occurred and with what object. From there, you can modify a character’s velocity however you like.

  43. Hi,

    First of all thank you for making all of this public. Unity’s built-in Character Controller has always been a pain in my rear, and I’ve managed to do many offline functionalities using the Rigidbody…but for online play I find using the Rigidbody to be to cumbersome on bandwidth. Now that I’ve found this I can go back to just sending transform data across the network. With that said, I’m having trouble really understanding the SuperStateMachine. Is it possible for you to add some commenting to it? I’m trying to build around your PlayerMachine and I’m doing just fine, until I get to the point where I need to understand the SuperStateMachine.


    • Hey Dr. Rosen,
      After reading this I opened up the SuperStateMachine.cs to check how much I had commented it…apparently practically not at all :/

      I’ll defs add some comments in the next couple days when I get a few moments, but for the time being, what issue are you mainly having? If you’re just attempting to use the SSM, although it can look pretty opaque it’s fairly simple: the current active state is stored in the currentState protected variable (in the SSM class), which is an enum. When you set currentState to a new value, a few things happen: the X_EnterState method is called, and the Update() method is redirected to the X_SuperUpdate method, where X is the name of the new state (state names correspond to the enum names, e.g., Idle, Walk, Jump…). As well, before that happens the previous state’s ExitState method is called.

      Once you get the hang of it I find it’s a superbly useful piece of code, having everything nicely separated makes it easy to debug. If this WASN’T the issue you were having, feel free to clarify. Either way I’ll add those comments.


      • Hi Erik,

        Thanks for the reply! I’m thinking what caused me to be so put off by the SSM was HOW simple it really is. I’m still only a novice programmer (when measuring in terms of beginner, amateur, novice, advanced, expert), so I’m used to seeing code (written by myself and others) that goes on for thousands of lines. The SSM is SO simple and contracted that I failed to see how it worked at all. You bringing up the X_EnterState and X_SuperUpdate began to clear things up, but I still didn’t see in the code how SuperUpdate was called. This may be, however, due to the fact that I’m still extremely confused by delegates. With that said, your Dictionary and ConfigureDelegate sent me for a REAL loop. At the end of the day I think if I can begin to understand when and where SuperUpdate is called (in the SSM) I can begin to really understand it.

        I have one more question. The SuperCharacterController doesn’t require the PlayerInput nor the PlayerMachine that you’ve provided. So for the time being, until I understand your SSM better, I can simply use my own Player Input script, correct?

        • To answer your second question first, the SCC is not dependent at all on any of the other classes (the SSM, PlayerInput or PlayerMachine). Any script that is attached to the same GameObject as the SCC will be able to receive the SuperUpdate SendMessage calls.

          The SSM is based on a state machine tutorial from UnityGems, although mine is a bit simpler and is also configured to run with the SCC (in that it runs the SuperUpdate calls, rather than the Update method). The SCC runs some logic in the Update method and then calls SuperUpdate on all components attached to it’s gameobject (line 198 of the SCC). Here, the idea is that any component can subscribe to these calls to runs their own player logic. The SSM does so in it’s SuperUpdate method, which calls two protected methods (Early and Late updates) and then a state specific one in between, which appear in the PlayerMachine as Idle_SuperUpdate and so on. Now, in order to call the correct SuperUpdate method for the proper state, these delegates need to be configured. (“Delegates” in C# are basically just variables that store methods.) This is done in the ConfigureCurrentState method, which is called every time currentState is set to a new value. You can see where the enter and exit methods are called, and in between them is called the ConfigureDelegate method.

          ConfigureDelegate looks complex but what it does is pretty simple: it searches the classes for a method named currentState_methodRoot, and returns that method as a delegate. It does this using Reflection.

          Overall the SSM can be a bit complex when you’re somewhat new to C#, since it uses lots of language specific tools (properties, delegates, generic methods), and it’s fine to avoid using it until you’re more comfortable.


          • Erik,

            Thanks again for the speedy response. I’ve studied and played around with the SSM a bit more and I think I’m grasping the concept, especially after you broke it down for me a bit more. My current project is an online multiplayer game using the new UNet. I was trying to use their built-in Network Transform component, but it doesn’t support server-authoritative movement with client-side prediction. I’ve written my own script to handle that, but it ends up competing with the SCC. Would you mind if I messaged you directly to see if you can see how I can combine the SCC with my NetworkMovement?


              • Awesome! I’ve uploaded a Unity Package to my dropbox that contains the project stripped down to only what’s needed to see where I’m having the issue. To replicate the problem, you’ll need to build out the project. Start the game (inside Unity) as a LAN(Host). You’ll see your player spawn. Next start the game (from the build you made) as a LAN(Client). Again you’ll see this player spawn. If you move as the Host you’ll see your movement happens smoothly and translates to the Client smoothly. If you move as the Client you’ll see your movement happens smoothly on the Host, but on your Client everything goes haywire. If you were to make a second build (so you have three instances running) you’ll see that the wonkiness only occurs for the local player you’re controlling.


  44. Hello Roy, I have a problem I brought in the code I even added the layers and my character just falls through the ground

    [SuperCharacterComponent]: No ground was found below the player; player has escaped level

        • Came here givin some feed back. I am really grateful for you sharing this. This stuff is awesome. Although I’m not making use of the character controller, because I wanted to see how well I can make a decent rigidbody controller turning out great so far. I have learned the ways of your SuperStateMachine which is AMAZING its making everything 10x easier, I am super thankful you sharing this.

          • Other than having one layer named “TempCast”, I don’t believe there are any other setup steps (as well ensuring your ground has colliders attached on the project layer). If your project is small you could email it to me (check my about page for my email) and I could look into it.

            The controller can clip through objects for two reasons: one is that your framerate drops resulting in a very high delta-time. The solution to this is to use the “Fixed Timestep” option on the SCC, and set the Fixed Updates Per Second to something like 60.

            The other reason is he’s simply travelling too fast. The controller in the demo project’s vertical speed is unbounded; he’ll keep accelerating downwards forever, eventually reaching insane speeds. Most games tend not to move controllers at these speeds, but some do: I address this at the end of my third blog post, with a couple possible solutions.

            Anyways, glad it’s been helping you! And yeah the SSM is awesome, my favourite tool my far.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s