How to get value of something from table using variable

I am attempting to use the script to play a different sound when the player walks on different materials. So far so good, however it seems that I can not use a string in a variable to get a value from the a table. Here is my code:

local Character = Player.Character

local DefaultSound = Character.Head:WaitForChild("Running").SoundId

local FloorMaterials = {
	[Enum.Material.Concrete] = "Concrete",
	[Enum.Material.Grass] = "Grass",
	[Enum.Material.Pebble] = "Pebble",
	[Enum.Material.Metal] = "Metal"
}

local Grass = {2154046681,2154046895,2154047106,2154047325}
local Concrete = {2154040185,2154040376,2154040597}
local Pebble = {2154068078,2154068306,2154068522,2154068766}
local Metal = {1708956242,1708957364,1708957110,1708956822,1708956542}

local NewSound = function(ID)
	if Character:FindFirstChild("HumanoidRootPart") then
		local Sound = Instance.new("Sound", Character.HumanoidRootPart)
		game:GetService("Debris"):AddItem(Sound,3)
		Sound.SoundId = "rbxassetid://"..ID
		Sound.Playing = true
	end
end

local Step = function()
	local Material = FloorMaterials[Character.Humanoid.FloorMaterial]
	if Material then
		--NewSound(Material[math.random(1,#Material)])
		print(Material[math.random(#Material)])
	end
end

In the function “Step”, the variable “Material” is the plain name of the material the player is walking on. I am trying to use this variable to get a random audio from one of the tables at the top of the script. However, attempting to use the variable to do this results in nil.

How do I go about using a variable to get a value from the table?

3 Likes

Here’s a suggestion, not sure if it’s very efficient though

local function GetFloor(Character)
for Material,_ in pairs(FloorMaterials) do
if Material == Character.Humanoid.FloorMaterial then
return Material
end
end

Try and tweak it to your script and see if that works!

2 Likes

If all you need is the name of the material then you don’t even need the table. You can just simply use .Name after the Enum and it’ll return the name for you.

1 Like

You could try to avoid the second step and assign the table of sound ids directly to the material in FloorMaterials

1 Like
local FloorMaterials = {
   [Enum.Material.Grass.Value] = {2154046681,2154046895,2154047106,2154047325},
   [Enum.Material.Concrete.Value] = {2154040185,2154040376,2154040597}
   [Enum.Material.Pebble.Value] = {2154068078,2154068306,2154068522,2154068766}
   [Enum.Material.Metal.Value] = {1708956242,1708957364,1708957110,1708956822,1708956542}
}
local Step = function()
    local Material = FloorMaterials[Character.Humanoid.FloorMaterial.Value]
    if Material then
	    --NewSound(Material[math.random(1,#Material)])
	    print(Material[math.random(#Material)])
    end
end
2 Likes

FloorMaterial is already a value.

1 Like

https://developer.roblox.com/api-reference/property/Humanoid/FloorMaterial

Value type: Material (which is an Enum, which is a userdata with a property called Value, which is a number)

2 Likes

I don’t see why @OP would use .Value over using the Enum? What use case would this serve over just using Enum.Material.Plastic? Your initial reply also just posts code, with no explanation as to why the OP should use .Value; some clarification would help.

Quite honestly, no exact reason. I just forget that you can use anything other that strings and numbers as indices after working in C#.

1 Like

When you attempt to index FloorMaterials, you’re doing so with random numbers between 1 and the length of the dictionary. FloorMaterials is not indexed by numbers, it’s indexed by EnumItems, so Material[math.random(#Material)] does not work. You also cannot get the length of a dictionary.

You can use this function to get a random item from any dictionary, just pass it FloorMaterials.
You could keep this function in a utils module, or you could precompute the FloorMaterials array when your script starts and remove all the caching stuff.

local optionsCache = {}
local function RandomFromDict(dict)
	local options = optionsCache[dict]
	if not options then	
		options = {}
		
		for i,v in pairs(dict) do
			table.insert(options, v)
		end
		
		optionsCache[dict] = options
	end
	
	return options[math.random(#options)]
end

It generates an array for the members of dict and caches it so it doesn’t have to keep regenerating the array, then gets a random item from the array via numerical index. This function is unsuitable if dict is extremely large, or if it keeps changing.

1 Like