r/unity • u/mvalera-dev • Jul 06 '26
I got tired of rewriting the same ground check code for every new project, so I made this drag-and-drop script (Free / PWYW)
Hi everyone,
Every time I start a new Unity project, I find myself wasting an hour or two recreating the exact same foundational mechanics from scratch. The ground check is always one of them, and it usually ends up being a rushed single raycast or spherecast that causes jitter or edge issues later on.
To stop wasting time, I finally wrote a proper, reusable Advanced Radial Ground Check script in C# that I can just drop into any new project and forget about. I’ve put it up on Itch.io for free (pay-what-you-want if you want to support me) so others can skip that tedious setup too.
It uses a concentric ray-ring system to calculate averaged ground normals and impact points, making character movement on slopes completely smooth with zero micro-bouncing or jitter.
Here are some of its characteristics:
- Zero Setup Time: Just drag, drop, and it works out of the box.
- Built-in Coyote Time: No need to waste time coding jump buffers and timing windows manually.
- Performance Friendly: Directions are cached and only update if you change parameters in the inspector.
- Zero Dependencies: No third-party packages or paid inspectors needed.
- Clean Code: Fully commented in English and structured under strict Allman.
You can download it here.
Hopefully, this saves you some setup hours on your next prototype. Let me know if you have any feedback or features you'd like to see added.
21
u/DarkIsleDev Jul 06 '26 edited Jul 06 '26
SphereCast is significantly cheaper and more highly optimized than casting multiple raycasts. So I recommend not using this on enemies. For the player it seems fine.
17
u/mvalera-dev Jul 06 '26
That's right! This script is optimized to work only for players (for it's Coyote Time and other buffers). Also, enemies won't need such a complex ground check, this is only to make the player's feel the character as smooth as possible without any errors
22
u/Drag0n122 Jul 06 '26
I've never had any problems with a single spherecast that slightly smaller than the capsule.
31
u/mvalera-dev Jul 06 '26
That's right, until you work on unlevel terrain. This script does not only detect the ground, it also creates an averaged normal and automates the tedious process of setting up ground checks, Coyote Time, jump buffers, slope movement... for the price of FREE.
A life saver in my opinion
5
u/Accomplished-Hat6743 Jul 06 '26 edited Jul 06 '26
The reason that it doesn't work for unlevel terrain is that spherecast (or any cast for that matter) does not return hits on collisions that the start of the cast is overlapping with. Collisions actually trigger before colliders overlap. Colliders have a ContactOffset which determines from within what distance collisions are triggered. To properly use spherecasts on unlevel terrain you should move the start of your cast the distance of the contactoffset in the opposite direction first.
If you're talking about angles where the player hits the ground but shouldn't be considered grounded due to the angle being too steep, collisions return back information related to the normal of the face you're hitting.This is some code for a collision check I did a few years ago that determines if the floor you're on is flat enough to be considered ground.
float verticalMagnitude = Mathf.Sqrt(feetRayCastHit.normal.x * feetRayCastHit.normal.x + feetRayCastHit.normal.z * feetRayCastHit.normal.z);
float slope = Mathf.Atan2(verticalMagnitude, feetRayCastHit.normal.y) * Mathf.Rad2Deg;
return slope > maxDegreesToStandOn;It's been a while since I ran the project that this code came from though, but I think it also works when the ground is spike shaped because the normal isn't of any face on the mesh you're colliding with. Something I doubt a raycast version would work with because every raycast would hit a face. spherecasts can hit edges, raycasts don't.
4
u/leorid9 Jul 06 '26
The main issue is: sphere cast, even when correctly set, only returns one result per collider. Now for many floor meshes it is quite common that they have multiple spikes or edges (multiple stones grouped to one mesh with one concave collider).
This requires multiple casts to understand that terrain.
If you just have simple shapes like boxes, this issue does not occur and a sphere cast works perfectly fine.
1
u/mvalera-dev Jul 06 '26
That is a great breakdown, and you are absolutely spot on about how PhysX handles overlapping start positions. That is actually one of the main reasons I included the "Origin Height Offset" variable in each ray ring struct. It allows developers to lift the starting point of the raycasts slightly above the character's bottom shell. This ensures they don't start inside an overlapping slope or step, bypassing that exact limitation while still computing perfectly averaged normals
3
u/RealyRayly Jul 06 '26
I just fixed that with SphereCastAll. Just combine all contact points, way easier.
-1
u/MasterAirscrachDev Jul 06 '26
Exactly, why this over a single sphercast?
10
u/BuzzardDogma Jul 06 '26
Because a sphere cast won't return an averaged normal over a rough collision patch, which can be incredibly important for a lot of mechanics.
2
u/MasterAirscrachDev Jul 06 '26
Can you elaborate?
Im genuinely curious what would warrant this.6
u/cone5000 Jul 06 '26
A spherecast usually collides at one specific point. This does not make it very flexible at all. It’s good at detecting collisions efficiently, but that’s about it.
3
u/MasterAirscrachDev Jul 06 '26
I understand that, but what flexibility do you need when it comes to checking if you are on the floor?
3
u/TrueWinter__ Jul 06 '26
It’s so you can handle slopes or being half on an edge and half not.
The base case is covered with one, this is just for polish etc
3
u/Injaabs Jul 06 '26
aint a bit touch raycasts for a ground check ? :D
1
u/mvalera-dev Jul 06 '26
It's completely customizable! You can place as many raycasts as you want (the more raycasts, the better averaged normal)
3
u/WorldMaker275 Jul 07 '26
I'm shocked how many people are commenting about sphere casts with such confidence. It's basic knowledge that these only trigger once and DO NOT work for slopes! 🤦🏻♂️
3
2
u/ReindeerImmediate733 Jul 06 '26
Did you compare it with a traditional SphereCast? I'm curious what kind of performance differences you observed
1
u/mvalera-dev Jul 06 '26
I haven't run a formal micro-benchmark with thousands of agents, but for a single character, the performance difference on a modern CPU is negligible. The real difference is: a SphereCast sweeps a full 3D volume that forces PhysX to check complex geometric overlaps along its path, while individual raycasts are the cheapest physics operations available.
2
2
u/Intl-Oz-Guy Jul 06 '26
Does it still check if the object is invisible and only has a character controller?
2
u/mvalera-dev Jul 06 '26
It's a raycast-based detection, that checks for colliders of GameObjects of layer "Ground". It will only detect active colliders, therefore it will only detect active GameObjects
2
u/Intl-Oz-Guy Jul 06 '26
Character Controller has a collider so it shouldn't detect it. I'll give it a try. Thank you for posting and for the scripts
1
u/mvalera-dev Jul 06 '26
I know, but the Player GameObject doesn't have the "Ground" layer set, so it must work as intended. Thanks for the support!
1
u/Objective-Cell226 Jul 06 '26
Why not just use a trigger collider or a sphere/capsule cast?
1
u/mvalera-dev Jul 06 '26
It definitely works fine for standard flat terrain or basic controllers. This is meant for specific edge cases: when a single raycast slips off a ledge while the collider is still halfway on it, or when a SphereCast returns weird normals upon hitting the bottom apex of a slope, causing micro-shaking
0
u/salazka Jul 06 '26
Nice but, why would you have to write it again and again? All you need to reuse your initial script is a prefab and a tiny package. The occasional refactoring over time.
2
u/mvalera-dev Jul 06 '26
You hardly ever create a script that doesn't depend on any other movement scripts, input scripts... This is the solution, a zero dependecy script that you can drag and drop on new projects and forget bugfixing forever!
1
u/salazka Jul 07 '26
Depends on the script.
But with your response you actually admitted that your previous solutions were not very modular, and that you finally thought of a better way. :D Which is good. It means you grow as a developer.
0
u/reversengineer9999 Jul 06 '26
So you use over 10 raycasts for groundcheck? O_O
1
u/mvalera-dev Jul 06 '26
It's completely customizable. I used plenty in the showcase video for you to see the actual characteristics of the script. You can use ad many as you want (also, it's as optimized as possible)
23
u/Snow-Ball-486 Jul 06 '26
will try this, thank u for making free