Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How would I concatenate 'inputObject' to match Enum.KeyCode?

This is very tough to explain, I myself took some time trying to make a title. I'm trying to make a pickUp Script and I'm having trouble with the drop portion. I will admit there are definitely flaws, I just sorta went along with it, so I will post the whole Event. Basically, there are 3 undefined carrierSlots; CFrame positions, on the Character at the moment, and the drop function is to index whichever Item is currently in the Slot# that was received by UserInput. The sequence is supposed to go somewhat like this: Holding E - Slot Index (1-3), Right Click. The first two keys are supposed to be held down, Right Click will "drop" the Indexed Item wherever the cursorPoint is currently located.

I have a table that looks like so

local carrierSlotIndex = {
   ["1"] = "One";
   ["2"] = "Two";
   ["3"] = "Three";
};

these are the carrierSlotIndex keys

This is the concatenation line

userInputService:IsKeyDown(
	Enum.KeyCode[carrierSlotIndex[inputObject]]
)

This is the Script

userInputService.InputBegan:Connect(function(inputObject, gameProcessed)
	local cursorPoint = cursor.Hit.p
	if (userInputService:IsKeyDown(Enum.KeyCode.E) and not gameProcessed) then
		if (userInputService:IsKeyDown(Enum.KeyCode[carrierSlotIndex[tostring(inputObject)]])) then
			if (type(inputObject) == "number") then
				for _,inputObject_ in ipairs(carrierSlotIndex) do
					if (inputObject_ ~= carrierSlotIndex) then
						return false
					end
					if (cursorPoint ~= cursorPoint) then cursorPoint = cursor.Hit.p end
					print("Dropped Item")
					local carrierItems = carrierInventory:GetChildren()
					local carrierItem = carrierItems[inputObject]
					if (carrierItem ~= nil) then
						if (inputObject.UserInputType == Enum.UserInputType.MouseButton2) then
							local weld = findObject(carrierItem,"Weld", "weld")
							if (weld) then weld:Destroy() end
							local setSlickDetector Instance.new("ClickDetector"); setSlickDetector:Clone().Parent = carrierItem
							carrierItem.CFrame = CFrame.new(0,0,0)
							carrierItem.Parent = workspace
							carrierItem.Position = cursorPoint			
							carrierItem.Anchored = true
							break
						end
					end
				end
			end
		end
	end
end)

This question is quite a lot so I'd really appriciate to whomever can provide a working answer, I'll accept it right off the bat and upvote too! Thanks!

If there is anything confusing about my explanation, please feel free to ask me to elaborate

I've also done some testing and removed tostring() from the concatenation line. I now got bad argument #2 to '?' (string expected, got nil) what am I doing wrong?!

8 comments

1

I dont know the answer but i applaud how well you've explained the question.

0

Thanks

1

This will not work. 'inputObject' is just an instance (like parts, scripts, models, etc) with the KeyCode and UserInputType and all those properties.

0

InputObject is the key pressed right?

0

A, B, C, you can concatenate this with Enum.KeyCode then by saying Enum.KeyCode[inputObject]

0

InputObject when it comes to numbers isn't "One" "Two" is 1, 2, so I'm making this index the item in the table to make it read Enum.KeyCode.One

0

like incapaxian said, InputObject is an object which holds properties of the input

0

How can I use it THEN?

1 answer

This isn't too simple of a problem as it requires some logical thinking. When you face something like this, break it into multiple smaller components -- that's the first step into modular programming. The way you've thrown everything into one "anonymous" function is not a good practice and will really hurt in the long term as it is very messy.

Here's how I'd approach this issue, without any extra modules. An improvement would be to get rid of the global variables and treat the sequence as one object that handles its own logic. Its creator would then make binds for each step in the sequence.

local Players = game:GetService("Players")
local UIS = game:GetService("UserInputService")

local localPlayer = Players.LocalPlayer
local mouse = localPlayer:GetMouse()

--

local SeqState = {
	none = 0,
	first = 1,
	second = 2,
	third = 3,
}

local inputToSeqState = {
	[{Enum.KeyCode.E}] = SeqState.first,
	[{Enum.KeyCode.One, Enum.KeyCode.Two, Enum.KeyCode.Three}] = SeqState.second,
	[{Enum.UserInputType.MouseButton2}] = SeqState.third,
}

--
	
local carrierSlots = {}
local lastSequenceState = SeqState.none
local lastChosenNumber = nil

--

	--	Carrier placement logic
local function placeCarrier(carrier, pos)
	carrier.CFrame = CFrame.new(pos)
	carrier.Parent = workspace
end

local function getNumberFromKeyCode(k)
	--	There must be a simpler way
	local e = Enum.KeyCode
	return	(k == e.One or k == e.KeypadOne) and 1 or
			(k == e.Two or k == e.KeypadTwo) and 2 or
			(k == e.Three or k == e.KeypadThree) and 3
end

local seqFunctions = {
	[SeqState.second] = function(inputObject)
		--	This shouldn't be done in the real world as it is a bad practice
		lastChosenNumber = getNumberFromKeyCode(inputObject.KeyCode)
	end,
	
	[SeqState.third] = function(inputObject)
		local n = lastChosenNumber
		placeCarrier(carrierSlots[n], mouse.Hit.p)
	end,
}

--

local function isInArray(array, val)
	for i = 1, #array do
		if array[i] == val then
			return true
		end
	end
	return false
end

local function getSeqState(inputObject)
	for validInput, seqState in next, inputToSeqState do
		if isInArray(validInput, inputObject.KeyCode) or isInArray(validInput, inputObject.UserInputType) then
			return seqState
		end
	end
end

local function stepSequence(seqState, inputObject)
	if seqFunctions[seqState] then
		seqFunctions[seqState](inputObject)
	end
end

local function isNextStep(last, new)
	return new == last + 1
end

local function processInputBegan(inputObject, processed)
	if not processed then
		local seqState = getSeqState(inputObject)
		if seqState and isNextStep(lastSequenceState, seqState) then
			lastSequenceState = seqState
			stepSequence(seqState, inputObject)
		end
	end
end

local function processInputEnded(inputObject, processed)
	if not processed then
		local seqState = getSeqState(inputObject)
		if seqState then
			if seqState <= lastSequenceState then
				lastSequenceState = math.clamp(seqState - 1, SeqState.none, math.huge)
			end
		end
	end
end

--	Event connections

UIS.InputBegan:Connect(processInputBegan)
UIS.InputEnded:Connect(processInputEnded)

--	Demonstration phase

local function createPart(props)
	local p = Instance.new("Part")
	for prop, val in next, props do
		p[prop] = val
	end
	return p
end

table.insert(carrierSlots, createPart{BrickColor = BrickColor.Red(), Anchored = true})
table.insert(carrierSlots, createPart{BrickColor = BrickColor.Green(), Anchored = true})
table.insert(carrierSlots, createPart{BrickColor = BrickColor.Blue(), Anchored = true})

It doesn't require anything extra, you can just drop it into a LocalScript inside StarterPlayerScripts. I'd still suggest to experiment with it and implement it on your own, for the sake of experience.

2 comments

0

I am so confused

0

I'll gladly explain whatever you're confused with. The most confusing part might be SeqState, which is just an enum to describe the current position of the sequence. I was also very confused with what exactly were you asking, and went along with the original goal, which was the key sequence.

This discussion is preserved as it was. New answers, comments, and votes are closed.