Getting the variable from a table in a table

Hello developers!
I’m making a drawing game and what i want to achieve here is if the user have the face in Inventory it will change the face image to other one. The script that i made is

local CharacterFaces = {
	HappyFace = {
		Inventory = true,
		AssetId = "rbxassetid://8207825395"
	},
	HoldingLaugh = {
		Inventory = true,
		AssetId = "rbxassetid://8210528464"
	},
	NeutralFace = {
		Inventory = true,
		AssetId = "rbxassetid://8210529936"
	},
	Expressionless = {
		Inventory = true,
		AssetId = "rbxassetid://8210532122"
	},
	Furious = {
		Inventory = true,
		AssetId = "rbxassetid://8210533587"
	},
}

local function NextFace()
	
	local CurNum = 1
	local MaxNum = 5
	CurNum = CurNum + 1
	print(CharacterFaces[CurNum].Inventory)
	if CharacterFaces[CurNum].Inventory then -- Error is here
		script.Parent.Character.Face.Image = CharacterFaces[CurNum].AssetId
		else
		CurNum = 1
	end
	
end


script.Parent.NextFace.MouseButton1Click:Connect(NextFace)

But what happen is
Attempt to index nil with 'Inventory'.

Thanks for helping me! i really appreciate it!

The table you’re trying to access is a dictionary without numerical indexes. To access the value, you have to do something such as this:

local faces = {--array to hold the index values
    "HappyFace",
    "HoldingLaugh",
    "NeutralFace",
    "Expressionless",
    "Furious"
}

local chosenFace = CharacterFaces[faces[CurNum]] 
--gets the value of the index from the dictionary

Im not currently on computer so im not sure. So if i use that script, i cant make it to

Happy Face {
OnInventory = true;
Assetid = ...
}

?

You can keep the dictionary you created

local dictionary = {
    index = "value"
}

local array = {
    "value"
}

print(dictionary[1]) -- prints "nil"
print(array[1]) -- prints "value"

print(dictionary.index) -- prints "value"
--^^ this is what the code I provided does
1 Like

As @HugeCoolboy2007 mentioned, you are trying to use a dictionary as an array. If you want to, you can convert your dictionary into an array but keep the names. You don’t have to use two Tables | Roblox Creator Documentation.

Your new code should be something like this:

local CharacterFaces = {
	{
		Name = "HappyFace",
		Inventory = true,
		AssetId = "rbxassetid://8207825395"
	},
	{
		Name = "HoldingLaugh",
		Inventory = true,
		AssetId = "rbxassetid://8210528464"
	},
	{
		Name = "NeutralFace",
		Inventory = true,
		AssetId = "rbxassetid://8210529936"
	},
	{
		Name = "Expressionless",
		Inventory = true,
		AssetId = "rbxassetid://8210532122"
	},
	{
		Name = "Furious",
		Inventory = true,
		AssetId = "rbxassetid://8210533587"
	},
}

local CurrentFace = 1

local function NextFace()
	CurrentFace += if (CurrentFace+1 > #CharacterFaces) then ((CurrentFace+1)%#CharacterFaces) else CurrentFace+1
	if not CharacterFaces[CurrentFace].Inventory then CurrentFace = 1 end

	script.Parent.Character.Face.Image = CharacterFaces[CurrentFace].AssetId
end


script.Parent.NextFace.MouseButton1Click:Connect(NextFace)
  • Note: I did slightly improve (change) your code, but it should work as intended.
Comments

Also know that if you don’t actually need the name property then you can use comments in your code for keeping track of what each face id should be. For example, you can’t really tell what face "rbxassetid://8210533587" is supposed to be. However, you can make a note of what it’s supposed to be using a comment. They are made using two hyphens (-) together and then anything you want to make a note of after.

For example, we can write it like this:

"rbxassetid://8210533587" -- Furious

The comment won’t have any effect on the actual code, it is merely there for helping document things people reading the code should know.

1 Like

Oh thank you so much!! I gained knowledge in LUA. I’ll test this tomorrow at computer and since i think its a solution because thats how we get the variables inside the tables in module script. Then i think its a solution!

I’ll try this tomorrow when im on the computer, thanks!

local CharacterFaces = {
	HappyFace = {
		Inventory = true,
		AssetId = "rbxassetid://8207825395"
	},
	HoldingLaugh = {
		Inventory = true,
		AssetId = "rbxassetid://8210528464"
	},
	NeutralFace = {
		Inventory = true,
		AssetId = "rbxassetid://8210529936"
	},
	Expressionless = {
		Inventory = true,
		AssetId = "rbxassetid://8210532122"
	},
	Furious = {
		Inventory = true,
		AssetId = "rbxassetid://8210533587"
	},
}

local function NextFace()
	for faceName, faceData in pairs(CharacterFaces) do
		if faceData["Inventory"] then
			print("Player owns "..faceName.."face!")
			script.Parent.Character.Face.Image = faceData["AssetId"]
			break --break loop after first owned face found
		end
	end
end

script.Parent.NextFace.MouseButton1Click:Connect(NextFace)

It seems dictionaries confuse a lot of people as most people in this thread opted to change your data structure into an array instead.

Here’s the dictionary implementation, which is albeit more efficient.

1 Like

i cant use comments because, i want to make the faces selling in shop. So if the user have it on inventory then its enabled

This works! but the problem is, it only changes 1 time. So if i want to change it again. It’s still the same

The original code you provided would just iterate through the table selecting the last face which has its “Inventory” field set to a Boolean value of true (it wasn’t selecting a face randomly), if you want the function to select a random face then you’ll need to implement random selection.

local function NextFace()
	for faceName, faceData in pairs(CharacterFaces) do
		if faceData["Inventory"] then
			print("Player owns "..faceName.."face!")
			script.Parent.Character.Face.Image = faceData["AssetId"]
			local num = math.random(1, 2)
			if num == 1 then --50% chance of loop breaking (can be changed easily)
				break
			end
		end
	end
end

This for example would essentially perform a coin-toss after each iteration of an owned face and either select the face and break the loop or ignore the face and continue the loop.

well that works! but it usually select “HoldingLaugh”/ “HappyFace”/ “NeutralFace”. But it’ll be ok since there will be alot of face, i just didn’t put everything, Thanks btw! Do you want me to solution you? Cause i already did on someone?

local function NextFace()
	local ownedFaces = {}
	for faceName, faceData in pairs(CharacterFaces) do
		if faceData["Inventory"] then
			table.insert(ownedFaces, faceName)
			print("Player owns "..faceName.."face!")
		end
	end
	
	if #ownedFaces >= 1 then
		local random = math.random(1, #ownedFaces)
		local faceName = ownedFaces[random]
		script.Parent.Character.Face.Image = CharacterFaces[faceName]["AssetId"]
	end
end

With no bias.