Custom Character Controller in Unity: Release 2.0.0

Immediately after completing the Mario 64 HD demo project I began working on the second version of the Super Character Controller. For over a month now I’ve had a download link up on the controller’s page for a Beta version of the project, which allowed users to see what I was working on at the time and contribute to the latest version.

As per usual, the Super Character Controller can be downloaded from it’s main page.

Just a blue man in a technicolour world

Just a blue man in a technicolour world

2.0.0 adds a number of features that are discussed in detail in the accompanying documentation, changlog, or previous blog posts, but below is an outline of the major changes.

New Grounding Techniques

The grounding algorithm in version 1 of the controller had numerous problems, mostly that it was inaccurate and inconsistent when dealing with several edge cases. Most of these have been resolved, with the solutions described in a previous post here.

Binary Space Partitioning Tree

Replacing the RPGMesh class is the BSPTree. BSPTree recursively partitions a mesh’s triangles into two sets using a series of partition planes. The component is complete, but not necessarily fully optimized or the best possible implementation of a BSPTree. More can be read in the Future Work section of the documentation.

Other updates can be viewed on the controller’s main page, as well as a list of contributors to the project. These changes are also showed in the README in the package, and all code and libraries used are sourced in the PDF document also included. If I missed anyone in the changelog or anyone’s code in the sources section, let me know so I can fix it.

There’s been a lot of interest in having a Git repo setup for this project, so now that version 2 is out it’s definitely on my radar, and hopefully something I can get setup soon. I’ve never setup and maintained an open-source project, so if anyone has any suggestions on best practices or tips n’ tricks, please leave them in the comments below.

Advertisement

25 thoughts on “Custom Character Controller in Unity: Release 2.0.0

  1. I’m totally blown away by this update… I can’t get anything to break, it works so well. The SpaceZone test scene is SO COOL too. AAAAAAA.

    • I even made some moving platforms (following the docs) and they work perfectly, pushing the character around and everything.

      I’d tip you if I had the money to 😦

      • Glad to see it worked out well! I’m sure there are plenty of bugs, but it’s definitely much cleaner than the previous release overall.

        Tipping wouldn’t be necessary anyways, since I built it off fholm’s original RPGController library, which was free, so it feels fair to share this too for free.

  2. Hello. I am wondering, is this controller precise enough for multiplayer usage( I need super precise physics to happen on server side and client side ),the built in just creates problems with my authoritative model, the collisions differ from time to time on the server and client.

    • It should be. All of the collision code is fully exposed—the only part of Unity’s collision engine that is used is in the Physics.OverlapSphere as well as some raycasting and spherecasting. Everything else is done in the controller class itself.

      I haven’t used it with the new Unet stuff yet, but I’m planning to try it out shortly. If you do end up using it, please post back to to let us know how it works out.

  3. Hey Erik, in the old and new demo there’s a bug / glitch / problem regarding the “Pushback” function contained in the SCC class. (which probably you’re anaware of)

    In your Test Zone demo scene I put two red boxes like this:

    And when I try to walk on them, this happens:
    https://vid.me/e/Y7Zj

    Of course you can imagine how this problem extends beyond just Box Colliders, as the player (/character) can get stuck between any collider.

    The problem here is obvious: the pushback method only handles one collider at a time, and the player gets stuck between two boxes because the box’s response vector is opposite to the other one.
    In other words, one box says to go to the right while the other one says to go to the left; and the character doesn’t really know what to do, so he/she stands there. Also, with this bug the player can get out of bounds and escape the level.

    The solution to this would be to move the character up on the boxes, “ignoring” the conflicting response vectors and make a new one.
    I have no idea how to approach this in code though…

    It’s a shame this happens because the physics would be perfect without this.

    So if you have ideas / know how to solve this / don’t understand something please let me know.

    Oh and by the way, I know it’s something completely off topic, but I think you should lock the cursor in your demos, it’s a little annoying (or maybe I’m just too grumpy). Nothing game-breaking, but it’s definitely something you should consider 🙂

    • Since the Pushback method is already being run recursively, one possible solution would be to compare previous pushback vectors to each other, and if they are exactly opposite of each other (or nearly exactly opposite, for example with an angle ~179 degrees between the two) you would alter the pushback vector in some way, allowing the character to “escape.” For this to work well there would need to be some sort of intelligent altering of the pushback vector (perhaps along the surface of the normal it is being pushed back from?)

      I’ll look into it but you’re welcome to open an issue on the github to bring attention to it, if you like.

      • Yeah, sometimes (when, for example, the character gets “stuck” between two spheres) the character would need multiple frames to “escape”, and in this situation the pushback response vectors may not be completely opposite (45/90 degrees between the two)

        I wonder if Unity’s default character controller has this problem too.

        As for the github, I’m terrible at explaining things (in case you haven’t noticed), but I think I’ll open an issue as you said.

        • He wouldn’t necessarily need multiple frames, since the Pushback is actually run multiple times per frame.

          The above issue though is likely due to some imprecision in the grounding method. Probably caused when trying to simulate the SphereCast data from the raycast. This gif shows me using the DebugMove on the SCC with a negative Y value. I drag the controller up (in the editor) and it falls down, but doesn’t get “sucked” into the two boxes.

          http://gfycat.com/FakeFatalBlacklab

          To answer your second question about the default controller it does have the same issue, and is not capable of “escaping” from situations it’s stuck in. However, it uses some sort of sweeptest to detect collisions, making it much less likely that it will get stuck.

          http://gfycat.com/WillingBeautifulKitty

          • I see.

            So from my understanding the character wouldn’t actually get stuck without the issue regarding the SimulateSphereCast function, but if for some reasons it gets stuck between the two boxes, the pushback method wouldn’t push him upwards, so the character doesn’t escape.

            This problem leads to two other different issues: the grounding issue, and the pushback issue.

            Is that correct? Because if it is I’ll edit the github issue.

              • Hey Erik, I think I found a possible solution to the “pushback” issue!

                It’s really hard to explain with words, so here’s an image.

                The “polygon” in the image is a mesh collider, the

                Basically if the angle between two vectors is greater than 90°, you sum those vectors. (The long red vector in the image is the sum of the two vectors)

                If the sum vector length is zero (which means the two vectors are exactly opposite) than get the normal of one of the two vectors.

                Now that you have the sum vector, make its magnitude the highest number in unity (Mathf.MaxFloat or Mathf.Infinity).

                That point will be the origin of a spherecast, with radius equal to the character’s radius, and direction opposite to the sum vector.

                Of course make the spherecast hit only that collider, using the “Temporary Layer”.

                After getting the hit point of the sphere cast and get the origin of the sphere that hit the collider, the character should teleport to that point. (the origin of the sphere)

                I’m not sure if this is the best solution, but I think it’s worth trying to implement it.

                Let me know about your thoughts about this solution.

                • Hey Leon, sorry for the slow reply, been a very busy week for me. I’ve read your solution, and I’ll post a more detailed response sometime tomorrow when I get a chance to test some of the ideas.
                  Thanks for the work!

                  • No problem! 🙂
                    I just wanted to correct an imprecision in my solution.

                    “If the sum vector length is zero (which means the two vectors are exactly opposite) than get the normal of one of the two vectors.”

                    That wouldn’t make any sense, since there are infinite vectors that are perpendicular to another vector.

                    Maybe it would make more sense to sum the two vectors that go along the two surfaces of the collider(/s), instead of summing the two response vectors.

                    Let me know if the tests are successful or not!

  4. Hey! I’m trying to use this library but I have a strange problem. My character keeps falling through the floor! It doesn’t occur in the TestZone stage you set up, but when I try to prefab that character and put him into another project, it bugs out and stops colliding with the floor. Sometimes he will collide with the floor- it seems like any sort of downward motion causes him to fall through. I tried using the prefab in your terrain scene and this is also the result I get. Any ideas?

    • The terrain scene currently is not supported, but is in there as I was planning on eventually getting TerrainColliders working with the controller.

      For other projects, ensure that you have a layer named TempCast as shown in this image.

  5. [more readable reply to Erik]

    No problem! 🙂
    I just wanted to correct an imprecision in my solution.

    “If the sum vector length is zero (which means the two vectors are exactly opposite) than get the normal of one of the two vectors.”

    That wouldn’t make any sense, since there are infinite vectors that are perpendicular to another vector.

    Maybe it would make more sense to sum the two vectors that go along the two surfaces of the collider(/s), instead of summing the two response vectors.

    Let me know if the tests are successful or not!

    • Yeah I really am starting to hate this comment formatting. New Years resolution is to change up the style on this site.

      While there are infinite perpendicular vectors, I typically just take the Cross of the normal and the controller’s current Up direction, which gets you a vector along the surface of the normal.

      To your original idea, I’ve read it through several times and I can’t see any major issues in the concept. Bear in mind that currently the controller in theory COULD push itself out of the example you gave above (the “sharp corner” of the mesh collider) as it resolves it’s collisions recursively. This can be inefficient though, as in your example it would probably take 3 or 4 collision resolutions to escape, versus 2 resolutions and then a SphereCast (and as SphereCast is part of the native API it is very efficient). The only known situation to me when you cannot escape is when the two collision vectors are exact opposites, leading to the controller to just get pushed back and forth. Your solution of SphereCasting should solve this, but it’s something that you’d need to implement and test before seeing if all the details and edge cases work.

      Normally I’d try to put this in but I’m currently prototyping a project (and learning Unity’s new networking), but feel free to checkout a branch on git and build it!

      As always, thanks for the help and interest in the project.

      • I’m not quite familiar with github, so I guess a branch is where I put a new unity project with my idea implemented (maybe?). But anyway when I have some time (I am currently learning how to build a custom editor and inspector, and trying to implement a 2D version of a character controller inspired to yours) I will try to implement my solution and maybe come up with a better one, and let you know about the results.

        • Branches allow you to create a separate version of the project, where you can create changes and they do not influence the main project. Then, when you’re happy with the changes you can request that they be integrated with the main project.

          Good luck!

            • Ok Erik, I posted a branch on github, but there are things to note:

              1- Done quick, and untested! There are probably a lot of errors when you import this into unity (unfortunately I’m not as experienced as you are in C# or any coding language)
              2- I don’t know if the enum “colliderAndPushback” and the foreach statements are the way to test the vectors to each other
              3- The solution here is slightly changed from what I described in the comment, because the character spherecasts twice, once forward and once backwards, and then test which hit point is the closest
              4- Uncompleted, I’m not sure how to get the origin of the sphere of the spherecast that hit the collider.

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 )

Connecting to %s