Based on those factors, the only option I can think of at the moment would be to utilize raycasting in combination with previously mentioned events / methods. This is because the aforementioned FloorMaterial
, HumanoidStateType
, and positional / height checks would probably not be able to determine the full context that a player is mid-air (essentially, not knowing whether or not their Character is indoors). Furthermore:
-
Although you could integrate UserInputService.JumpRequest
to ignore situations where a player requests to jump, that could be abused since the JumpRequest
event can be fired repeatedly while the Character is mid-air.
-
You could use the Humanoid.Jumping
event or manually listen for the value of Humanoid.Jump
to change to true
(as it is momentarily set to true when a Character successfully jumps, and is set back to false until the Character successfully jumps again), but this would not be able to detect if a player jumped from a high altitude, is not indoors, and the amount of time it takes until they land on a surface.
- (This also happens to be very similar to listening for the
HumanoidStateType
of Jump
)
However, if you did not want to use raycasting and were to theoretically have a certain amount of time that a player would need to be mid-air before it detects the player, you may be able to use a combination of the RunService
and listening for the Humanoid.StateChanged
event.
Before fully creating that system, you could use the RunService
to measure the amount of time it takes, on average, for a Characterâs HumanoidStateType
to go from Jump
to Landed
or Running
, when the playerâs Character is jumping on a flat surface (which would differ based on the JumpHeight
/ JumpPower
settings for the Characters in your game). With that baseline, you could store a number that is slightly higher than that to ensure that it would not detect players who are mid-air for the average amount of time it takes to jump while indoors.
In the actual system, you could use Humanoid.StateChanged
to check when a playerâs Character enters the Freefall
or Flying
state and then begin tracking the amount of time elapsed (through the RunService
) until the event fires again with the new HumanoidStateType
being set to Landed
or Running
. If it exceeds the time threshold before the HumanoidStateType
is set back to Landed
or Running
, it is more likely that the Character has not jumped or fallen while indoors.
Unfortunately, without raycasting, this would also have its flaws, as players may be able to jump from elevated surfaces while indoors and still be able to exceed that time threshold.
One more note about the Raycasting optionâŚ
If you decide to go with the raycasting option, it would be possible to optimize its usage by only creating raycasts during necessary situations. For instance, when utilizing a combination of FloorMaterial
, HumanoidStateType
, and positional / height checks, you could raycast downwards from the Character if:
- The
FloorMaterial
is Enum.Material.Air
-
HumanoidStateType
is set to either Jumping
, Freefall
, or Flying
- The Character meets the in-world positional / height requirements that youâve set
If all of those conditions are true, upon a successful downwards raycast, you could check if the RaycastResult.Distance
exceeds a desired threshold that you deem to be a large enough distance to indicate that a player is mid-air without being inside of a building. For example, if the distance returned by the Raycast
is only 10 studs, the player is probably indoors. If the distance is 100 studs, on the other hand, that would indicate that there is nothing between the Character model and the world below them for a distance that is much more likely to only be possible if the Character is outdoors.
(Note that the filtering of the Raycast
would also need to be set up in a way where it ignores Instances that should not be considered a walkable surface. For instance, situations where one playerâs Character is directly above another playerâs Character, or, eventually, the surface of another playerâs flying vehicle, could lead to erroneous results that incorrectly determine that a player is freefalling or flying while being very close to a building, the ground, etc.)
- Extra note: If you add flying vehicles into your game in the future, it will be much easier to accurately determine situations where a player is flying a vehicle without needing to use
Raycasts
, the RunService
, etc., since you could check if Humanoid.Seated
is true or if their HumanoidStateType
is set to Seated
, and then check if Humanoid.SeatPart
returns a Seat
that is in one of the flying vehicles, in addition to checking any positional / height requirements youâve established to ensure it doesnât detect the player as being mid-air while piloting a flying vehicle that is still on the ground.
Based on the conditions that you have mentioned, those are the possible solutions I can think of right now. Keep in mind that there may be other solutions that I am currently unaware of.
I hope that you will be able to find a suitable solution that matches the needs for your game!