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

Is there anyway to check what terrain the player is walking on?

Asked by 3 years ago
Edited 3 years ago

I'm making a survival game, and I want the player to both walk slower and regain less heat on snow, but I don't know how to check what material they're walking on. I've tried using Humanoid.FloorMaterial, but that value is always nil for me. If anyone knows a better method, that'd be amazing.

0
i don't think that there is a way to do that yet bruce_matthew 4 — 3y
0
use raycasting imKirda 4491 — 3y
0
The issue with terrain is that it is all one big part, and you can't script it, delete it, move it, edit it, check it etc... it would be more efficient to find a realistic grass part/mesh that you can script with. That's also what .FloorMaterial is for the material of the part not the terrian. Let me know if this helps archerdancom -3 — 3y

2 answers

Log in to vote
1
Answered by
imKirda 4491 Moderation Voter Community Moderator
3 years ago

That's actually a good question and it's quite simple too, all you need for that is Raycasting. It will fire ray from your Character and return the result. Here is how you set it up (LocalScript):

So first you need RunService, i will be using it's event called RenderStepped in this case:

local RunService = game:GetService("RunService")

-- Function which will run when render is stepped (Every frame)
-- If you have 60 FPS, it will run 60 times per second
local function OnRenderStepped()

end)

RunService.RenderStepped:Connect(OnRenderStepped) -- Connects the event to the function

Now you need to create Ray, rays are created with 3 arguments, Origin, Direction and RaycastParams. The parameters should be created right at the start of script, they have 4 arguments, FilterDescendantsInstances (Which descendants of given instances will only be accepted OR be ignored based off of given FilterType), IgnoreWater (Whether the ray will ignore water), CollisionGroup (Ray's collisiong group) and FilterType (Blacklist or Whitelist). So let's create the parameters:

local RaycastParameters = RaycastParams.new()
RaycastParameters.IgnoreWater = true or false -- Choose what you need
RaycastParameters.FilterDescendantsInstances = {Character} -- Put your character in here so rays won't be detecting the character
RaycastParameters.FilterType = Enum.RaycastFilterType.Blacklist -- If it would be Whitelist then ONLY Character would be detected, but with blaclist the character WON'T be detectable

Now let's create the ray!

local RunService = game:GetService("RunService")

local HumanoidRootPart = "Your Humanoid Root Part"

local RaycastDistance = 5 -- How far will the ray cast, 5 studs is perfect (It won't detect the terrain when you jump which is good)

local function OnRenderStepped()
    local Origin = HumanoidRootPart.Position -- From where will the ray cast (Vector3)

    -- Now for direction, Since you can't do CFrame.DownVector, you will need to use CFrame.UpVector which returns upper look vector of given CFrame and turn it into negative number which will turn it into DownVector.
    local Direction = - (HumanoidRootPart.CFrame.UpVector * RaycastDistance) - Multiply by raycast distance here to make the ray longer

    -- Now this creates the ray itself which as i said earlier, accepts 3 arguments and is called using workspace
    local Hit = workspace:Raycast(Origin, Direction, RaycastParameters) -- This returns hit which means what did the ray hit

    -- Now check if the hit exists
    if Hit then
        -- Hit returns: Instance, Position, Material and 1 more thing sorry i don't remember but it's said somewhere on the devforum, in this case we need Material
        local TerrainName = Hit.Material.Name -- Gets the name of material

        print(TerrainName) -- if i would be standing on grass material, it would say "Grass"
    end
end)

RunService.RenderStepped:Connect(OnRenderStepped)

Now this should be working but let's turn this into a lot more comfortable thing using BindableEvents and it's event called BindableEvent.Event!

local TerrainChangedSignal = Instance.new("BindableEvent") -- Creates the event

local function OnTerrainChanged(NewTerrain) -- Whenever the event is fired,  this function will run
    print(NewTerrain)
end

TerrainChangedSignal.Event:Connec(OnTerrainChanged) -- Connects the event

And now it's done, then you need to connect the event and so the whole script looks like this:

local RunService = game:GetService("RunService")

local TerrainChangedSignal = Instance.new("BindableEvent")

local Character = "Your Character"
local HumanoidRootPart = "Your Humanoid Root Part"

local RaycastParameters = RaycastParams.new()
RaycastParameters.IgnoreWater = false
RaycastParameters.FilterDescendantsInstances = {Character}
RaycastParameters.FilterType = Enum.RaycastFilterType.Blacklist

local RaycastDistance = 5

local function OnTerrainChanged(NewTerrain)
    print(NewTerrain)
end

local function OnRenderStepped()
    local Origin = HumanoidRootPart.Position
    local Direction = - (HumanoidRootPart.CFrame.UpVector * RaycastDistance)

    local Hit = workspace:Raycast(Origin, Direction, RaycastParameters)

    if Hit then
        local TerrainName = Hit.Material.Name

        TerrainChangedSignal:Fire(TerrainName) -- Fires the event that floor was changed!
    end
end)

TerrainChangedSignal.Event:Connec(OnTerrainChanged)
RunService.RenderStepped:Connect(OnRenderStepped)

The OnTerrainChanged function will fire every render because i did not include checking if last floor terrain was not the new one but i guess you can make it work, you have 80 reputation after all.

0
Help appreciated. I'll be sure to check it out soon. DejaSketch 84 — 3y
0
Great answer, every part is nicely described. OP must accept this answer. TopBagon 109 — 3y
Ad
Log in to vote
0
Answered by 3 years ago

I would make the terrain a part. Then the grassy terrain would be normal terrain.

So:

local humanoid = game.Players.LocalPlayer:WaitForChild("Humanoid")
local terrain = game.Workspace.Terrain --the default terrain things in Roblox Studio
local snowMat = game.Workspace.SnowGround --the part here
local lavaMat = game.Workspace.LavaGround --the part here

if humanoid.FloorMaterial = snowMat then
print("On snow.")
end

if humanoid.FloorMaterial = terrain then
print("On terrain base.")
end

if humanoid.FloorMaterial = lavaMat then
print("Burning cuz of lava.")
end

require(script)
require(lavaMat)
require(snowMat)
require(Terrain)
require(humanoid)

Ensure that you know how to use: local humanoid humanoid.FloorMaterial

Answer this question