In order to compute various mechanical behaviours of a character, such as jumping and walking, it is necessary to know whether a Part is "on the ground".
Given an arbitrary physically simulated cuboid, how do you know when there is sufficient substance beneath it on which to rest itself?
If you don't understand what I mean, think of this related question "How do you know that a Part is or is not falling?". You might give a trivial answer, like "when the Y velocity is less than 0", and I would reply "I do not count sliding down a slope as falling".
I have experimented with two techniques, both of which are approximations host to various disadvantages:
Measure acceleration frame-by-frame and conclude that there is no ground beneath if the vertical acceleration is within N% of gravitational acceleration. Using a value of 15% was derived empirically and should represent a good upper bound.
Take "root" to be the physical Part in question:
prevy = root.Velocity.Y t = tick() coroutine.wrap(function() while wait() do local tempy = root.Velocity.Y local deltat = tick() - t local dydt = (tempy - prevy)/deltat --rate of change of velocity, i.e. acceleration if math.abs(1+dydt/g) < 0.15 then ground = false else ground = true end)()
This technique is not always reliable with smaller upper bounds, and the greater the upper bound on the error %, the more unreliable other behaviour (such as walking down a steep slope) will be.
If any of a number of downwards rays parallel with the Y-axis comes into contact with something, conclude that there is ground beneath. I will not post the implementation of this technique, as it is computationally straightforward and intuitive.
The problem with this is that many rays are needed to be cast continually because only a fraction of the Part in question may be resting on a surface. Suppose that the smallest surface size of an ambient detail is 1 stud^2, how many rays need to be cast from a Part with a 4 st^2 bottom surface to guarantee that the 1 st^2 surface that it may be resting on is detected?
How do you suggest improving the above techniques, and what other approaches can you think of?
Thank you for your time!
The easiest method I can think of would be to use a single raycast from the character's center of mass. Place an invisible part at this point, updating it whenever you update the positioning of the model (or less), and do a raycast straight down to see if it hits ground.
This isn't perfect and will result in some weird situations where the characters' feet could be off a cliffside, but it wouldn't fall, but it is a lot cheaper than multiple raycasts.
A modification of this uses two raycasts from the character's model's feet (one each, that is) to see if each is touching ground. This has an additional benefit of allowing you to slightly reposition the feet model so that the flats of the feet are always on the ground, rather than hovering inside or above it.
I'd give you some code, but I'm on mobile right now, sorry!
Good luck.
This may read a little strange, but I was watching a video by NVidia, about how their GPUs process MFAA (Multi-Framed sampled Anti-aliasing).
This AA method basically rendered the same object at different times, compared the results, and displayed good AA, without using as much processing power in a single frame.
If you're using Server-scripts, this may not work so good; But for LocalScripts, utilizing RunServices 1/60 update time - you could split down the impact of multiple ray-casts.
In other words, instead of casting all rays through a for loop in one update-interval - which can cause lag with multiple objects - cast one ray for each object in one frame, then the next offset ray-cast in the next frame.
You could also determine how detailed the ray casts be, based on how long it took to do this last ray cast.
This is my theory anyway, hopefully there's an idea in there somewhere you could use. ^^
Technique #3
The solution that I've found is to exploit some special behaviour in how the ROBLOX engine positions Part
Instances.
Given a Part
that has CanCollide
set to true, instructing part.Position = ...
will cause ROBLOX to evaluate the geometry of the Part
and environment for collisions and reposition the Part
if an intersection is detected. Not only does it do this, but it also does so before the next instruction executes (rather than on a frame-by-frame basis). Hence, (ignoring other slight quirks that can be easily resolved) one can check for ground by creating a Part
with the same bottom area of the 'Player', moving it to below the Player, and then checking if the position is what you set it to (i.e that it has not been changed by ROBLOX due to an intersection).
Test thus far suggest that this method is quick, reliable, and functions well with varied environmental structures.