Problems with hotbar system for survival game

So i got the basic stuff of the hotbar done, problem is when the user equips, unequips and equips it chooses the second weapon because of roblox’s way to organize or whatever, here is a video


I want it to pick up the same weapon again depending on hotbar… Also trying to make it support when u change the hotbar, since this is for a survival game and the user will change the hotbar layout or whatever
Here is my code currently, if someone can make it automatically reorganize or tell me how it would be nice

local PlayerService = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Client = PlayerService.LocalPlayer
local Mouse = Client:GetMouse()
local Character = Client.Character or Client.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local Inputs = {One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6}
local Orders = {One = nil, Two = nil, Three = nil, Four = nil, Five = nil, Six = nil}
local ToolEquipped = false
local HotBar = script.Parent:WaitForChild("Hotbar")
local CurrentTool
local CurrentOrder
game:GetService("StarterGui"):SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)

UserInputService.InputBegan:Connect(function(Input, GameProcessed)
	if Input.KeyCode == Enum.KeyCode.One and not GameProcessed then
		if ToolEquipped then
			print(CurrentOrder)
			if CurrentOrder == Inputs[Input.KeyCode.Name] then
				Humanoid:UnequipTools()
				ToolEquipped = false
				CurrentOrder = nil
				CurrentTool = nil
				Orders[Inputs[Input.KeyCode.Name]] = nil
			else
				local Tool = Client.Backpack:GetChildren()[Inputs[Input.KeyCode.Name]]
				if Tool then
					Humanoid:UnequipTools()
					Humanoid:EquipTool(Tool)
					CurrentTool = Tool
					Orders[Inputs[Input.KeyCode.Name]] = Tool
					CurrentOrder = Inputs[Input.KeyCode.Name]
					ToolEquipped = true
				end
			end						
		else
			local Tool = Client.Backpack:GetChildren()[Inputs[Input.KeyCode.Name]]
			if Tool then
				print("ye")
				Humanoid:EquipTool(Tool)
				CurrentTool = Tool
				Orders[Inputs[Input.KeyCode.Name]] = Tool
				CurrentOrder = Inputs[Input.KeyCode.Name]
				ToolEquipped = true
			end
		end
	end
end)

(yes i know its only 1 input, this is for testing)

1 Like

Edit: I understand your problem. Give me a minute :slight_smile:

Okay so to begin, there can be many approaches to solve this problem, and the first one that comes to my mind is OOP.

You’d be aware how objects and tables work in Lua, and one table is equal to itself only. We will make use of this property.

Basically, we will have the unequipped object be a unique table “NoneTool” which will act as a placeholder void object.

--       [[ SERVICES ]]
local PlayerService = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

--      [[ CLIENT ]]
local Client = PlayerService.LocalPlayer
local Mouse = Client:GetMouse()
local Character = Client.Character or Client.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")

--      [[ UTILS ]]

local NoneTool = {}
local ToolPack = {}

-- Fill orders with all NoneTools
for i = 1, 9 do 
    Orders[i] = NoneTool 
end

local ToolEquipped = false
local HotBar = script.Parent:WaitForChild("Hotbar")

local CurrentTool = {0, NoneTool}

--      [[ SOURCE LOGIC ]]


-- Disable Default
game:GetService("StarterGui"):SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)

-- Hook a logic to register new tools or remove them.
Client.Backpack.ChildAdded:Connect(function(NewTool)
    -- Our current tool is unequipped. Do not re register.
    if NewTool == CurrentTool[2] then
        -- Put current tool back to the ToolPack
        ToolPack[CurrentTool[1]] = CurrentTool[2]
        CurrentTool = {0, NoneTool}
        return 
    end

    -- Find the first empty index and put the tool there.
    for i = 1, 9 do
        -- Avoid inserting in current tool index.
        if ToolPack[i] == NoneTool and CurrentTool[1] ~= i then
           ToolPack[i] = NewTool
            return -- kill the function
        end
    end
    
     -- Our loop came to an end but in vain
     warn("No empty slot available. Tool not registered ")
end)


-- Hook a logic to detect deleted tools.
Client.Backpack.ChildRemoved:Connect(function(DelTool)
    -- Our removed tool is actually equipped so do nothing.
    if DelTool == CurrentTool[2] then return end

    -- If the removed tool is registered with the table then delete it.
    local i = table.find(ToolPack, DelTool)
    if i then
        ToolPack[i] = NoneTool
    end
end)


UserInputService.InputBegan:Connect(function(Input, GameProcessed)
    
    -- It is cleaner to have guard clauses at the top.
    if GameProcessed then return end

    -- General statement that translates your Enum Key code to Integer in the table.
    Input = Input.KeyCode.Value - Enum.KeyCode.Zero.Value

    -- Reject if non numeric keys are pressed.
    if Input > 9 or Input < 1 then return end

    local Tool = ToolPack[Input]
    if Tool == NoneTool then
        Humanoid:UnequipTools()
        -- Cleanup logic above.
    end

    CurrentTool = {Input, Tool}
    Humanoid:EquipTool(Tool)
end)

I think this makes the code a lot cleaner and less indented too! Try it out and let me know. Please try to read every single line and understand it’s use. If you are confused about anything, feel free to ask :smiley:

PS: I haven’t coded in a while and did this on my phone. Absolutely feel free to let me know if anything fails… (though honestly it shouldn’t)

1 Like