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?!
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.