Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

[?] Custom Characters: Detecting the Ground

Asked by
duckwit 1404 Moderation Voter
9 years ago

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:

Technique #1

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.

Technique #2

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!

3 answers

Log in to vote
0
Answered by
adark 5487 Badge of Merit Moderation Voter Community Moderator
9 years ago

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.

0
Thanks for taking the time to respond, Adark. I'm afraid I don't understand your proposed solution, though. How does placing a Part at the end point of the first ray cast (from the center of mass) achieve anything? Surely the placement of that first part is subject to the exact same problems as using one ray for the whole detection process in the first place. I may just be misunderstanding what yo duckwit 1404 — 9y
0
..what you wrote. Perhaps you could elaborate on this? Thanks. duckwit 1404 — 9y
0
You place the part AT the center of mass, and then do a single raycast FROM it, straight down. If the CoM is balanced, so is the entire model, if you just want basic physics. adark 5487 — 9y
1
However, that will allow it to fall through thin cracks (which is symptomatic of not solving the problem he wants) BlueTaslem 18071 — 9y
View all comments (3 more)
1
A solution I use (sort of) for my Portal game is to "expand" all parts by the size of the player. This is the behavior requested. Expanding by less would get a mix which might be optimal. BlueTaslem 18071 — 9y
0
I should have clarified that the rotation of the Part is locked in all but the Y-axis, so if any part of the surface is on ground then the whole block is stable, so CoM tests are unnecessary. As a side note, I don't understand why you say to place a Part there and update its position, rather than just keeping/updating a Vector3 of the CoM? duckwit 1404 — 9y
0
@BlueTaslem I don't understand your solution, either, I'm afraid! What do you mean by "expand" and how does this affect detecting ground? duckwit 1404 — 9y
Ad
Log in to vote
0
Answered by
hiccup111 231 Moderation Voter
9 years ago

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

0
This would only be necessary if so many rays were required as to slow each update considerably, but I'd rather not have to process an excess of Rays anyway, still, thanks for the suggestion. duckwit 1404 — 9y
Log in to vote
0
Answered by
duckwit 1404 Moderation Voter
9 years ago

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.

0
Hi, have you tried using Part:GetTouchingParts()? According to wiki parts to need to have CanCollide set to true and cannot be adjacent or flying (obviously), and so I did a quick test with a simple custom character despite it's legs being CanCollide on it still intersected the baseplate, but some exceptions may apply (HipHeight). For that case you can also try checking Humanoid's states & events FieryEvent 185 — 7y
0
No, I haven't tried that, precisely because adjacent parts don't count as touching, so the ground underneath a character wouldn't count as touching. Also, using Humanoid state defies much of the value in custom physics - the idea is to be independent from the default ROBLOX implementation. duckwit 1404 — 7y

Answer this question