Hi everyone,
Mostly title, but it usess continuous collision detection (CCD) for capsule colliders (the pill shape in red). No shapecasts/raycasts/queries were used
Videos/Examples
This shows basic movement, jumping, and just general the acting of gravity + control
Here is colliding with a wall (and floor)
For better or for worse, it is a true capsule shape, so it has some interesting interactions with shapes
It works walking up slopes, I am still working on a way to reduce the “hopping” motion when going down though—any suggestions are welcome
Thanks to the capsule shape, it can work with stairs too
Here it traverses (more or less) complex geometry, aka walking across the monkey—still working towards making it less jarring though
Admittedly, it does need some work that I specified beneath a few of the examples. Beyond that, I went ahead and replaced the camera system and the inputs “just because” (I was reinventing the wheel, might as well make the whole car). Neither of those work extremely well. The camera doesn’t have a zoom feature yet (easy to solve) and doesn’t have collisions (difficult to solve). The movement doesn’t have acceleration or any really cool techniques like coyote time—but I’ll add all that in the future.
There will be a severe lack of visuals here on
How I made it
I used this paper for the idea: Continuous Collision Detection of General Convex Objects Under Translation by Gino van Bergen
To summarize, it says that you can “inflate” or “deflate” an object by another and still perform operations. It’s hard to make a capsule sweep through space, so we try to reduce that problem to be between a ray (position and direction in space) and an “inflated” environment
A bit longer, if I look for the intersection between shape A and shape B, I might set up an equation like A = B. I might want to move B to the other side, to make A - B = 0. To add or subtract shapes, you can use Minkowski addition - Wikipedia. This is the idea behind a discrete collision detection algorithm called GJK, that tries to find if A - B = 0 through optimization. In the context of Gino van Bergen’s algorithm, he has A + O + tD = B, where O + tD represent a raycast (which in our case is player velocity). He subtracts over O + tD = B - A, where A is the capsule (and also symmetrical, so -A = A). So we have O + tD = B + A. We can cache B + A assuming the capsule doesn’t change in shape for every shape B in the environment (since it is no longer what is moving, rather the “O” for origin of the ray).
Anyway, the search for t is just a raycasting problem, so after we “inflate” the environment (sum every shape and the components of the capsule together, notably ball and cylinder) we finally find the time of impact (TOI) between the capsule and whatever geometry. All of this is represented in code for exact precision (ex/ cylinder being a radius and two vertices, ball being a radius and point)
If anyone has any follow-up questions, feel free to ask
Details I found interesting
- I used a basic grid architecture to find potentially colliding objects faster (aka the broad phase)
- Uses buffers since there is a LOT of data that is unchanging (given I am working in a static environment)
- Gives a lot of flexibility given on-demand collision detection. For example, giving the server authority to run its own calculations (A part of me died after I saw Roblox was coming out with server-authoritative characters, but surely their system is better than mine)
- Having continuous collisions makes the character not susceptible to issues like tunneling (swept), and also has more accuracy in where it “finds” the collision). Admittedly, these are uncommon issues to have given the character isn’t often going mach 5
- Has collide-and-slide built in, like you can see when the capsule collides with the wall in the second example it doesn’t just “stop.” (Even more primitively, it uses to walk across the floor since the floor counts as one collision already)
- Again, uses capsules—I think Roblox uses boxes (don’t quote me on that)
- While the monkey is represented by capsule-inflated-triangles (leading to some redundancy or balls/cylinders/faces hidden by others), primitives like the boxes are manually defined to ensure there are no hidden colliders. I might work on convex hulls w/ convex decomposition for more optimized complex geometry that needs less precision, but as it stands now thats low priority
Thanks for reading
TLDR: watch the videos, lmk what I could do to improve character movement
edit 1: i messed up notation ![]()
