Super Character Controller

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

Changelog

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.

References

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

117 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.

      Erik

      • 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.
        Cheers!

        • 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: http://i.imgur.com/ly1ogVN.jpg

          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. http://youtu.be/ENLM1cfAMp0

    • 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()
        {
        moveDirection=Vector3.zero;
        }

        • 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.

            Regards

            • 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 :P

  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?

                  Regards

  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.

    Erik

    • 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:

    http://postimg.org/image/w1szw4gjj/

    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!

    Cheers

    • 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!

        Cheers,
        Moodie

  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:
    https://www.dropbox.com/s/dc4wr2oeocx2fvr/Sphere_VS_Capsule.txt?dl=0
    If you have any questions about it feel free to let me know.

    Thanks again, you have been a great help.

    Cheers,
    Moodie

    • 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.RotateAround(transform.position,rotdir,rotspeed*Time.deltaTime);
      //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 != Vector3.zero){
      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: http://i.imgur.com/7uboDHt.gif. 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: http://i.imgur.com/5rxeEqf.jpg (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.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s