• Hold a key to open a derma panel
    7 replies, posted
Hey, I was trying to open a derma panel after holding a key for x seconds. Unfortunately, I failed hehe So here's my code: [CODE]function GM:PlayerButtonDown(ply, b) if b == KEY_R then timer.Simple(3, function() frame:MoveTo(ScrW()-230, ScrH()-400, 2, 0, -1, function() frame:MakePopup() end) end) end end[/CODE] The problem is that it obviously doesn't open after holding "r" for 3 seconds. It instead wait 3 seconds after you clicked on "R" and open the panel after that. So I would like to know how to achieve that. Thank you !
If you wanted to achieve whatever you wanted to achieve, you'd use some hook that runs every frame, tick or generally very often and check in that hook if the key is held, and if increment some value in it. I'd use it that way: [code] local opened = false -- we can either track the panel open status by checking if the panel is visible or valid, or by keeping a var local timepressed = 0 -- Track the time pressed local time = 0 --internal value - the hook runs every tick, but we gonna make the statement pass true only every second local function btndown() /* The following statement will run only if the KEY_R is pressed, if the derma isn't open, if the key pressed is pressed for three seconds or more and if the variable 'time' is one second before CurTime, aka one second before present time. */ if input.IsKeyDown(KEY_R) and not opened and time < CurTime() and timepressed <= 3 then timepressed = timepressed + 1 time = CurTime() + 1 if timepressed == 3 then -- you could check if the panel isn't valid first, could make sure that it doesn't open twice. After all, it is a hook that runs per tick, never know what will happen opened = true --Open your derma here --Do not forget to either switch the var 'opened' for validity check for the panel, or to simply set 'opened' to false on the OnClose function of the base panel. Up to you end elseif not input.IsKeyDown(KEY_R) and timepressed > 0 then timepressed = 0 end end hook.Add("Think", "ButtonCheck_UNIQ", btndown) [/code] Ofc, using hooks like KeyReleased and KeyPressed would probably be much, much more efficient, but that works too. The code is untested so I have no idea how it would work. I had an idea how to realize it using only KeyReleased and KeyPressed and one timer, but it would be untested and I'd be uncertain. I have tried to explain it in the best way possible. Also, keep in mind that my method might be horrible and I might get burned on a stake for this, but it should work.
I think this is the simplest way to do it: [CODE] local time -- this makes the variable local even though it has no value local open = false -- this variable defines whether the menu is opened already hook.Add( "Think", "DoStuff", function() if input.IsKeyDown( KEY_R ) then -- if R is currently down if !time then time = CurTime() + 3 end -- set the time to be 3 seconds from now if CurTime() > time and !open then -- if it's been 3 seconds and the panel isn't already open frame:MoveTo(ScrW()-230, ScrH()-400, 2, 0, -1, function() -- move the frame frame:MakePopup() -- focus the menu end) open = true -- set the panel as being open end else open = false -- let them open it again time = nil -- reset the timer end end ) [/CODE] [URL="https://github.com/Mysterypancake1/GMod-Binding/"]By the way, I made a binding module that might help someone in the future[/URL], but it doesn't account for a time delay.
It does work, because the check goes further only if CurTime() is higher than time. Where if the check is successful, I set the time var to be higher than current CurTime() by one, which means the check will be successful again after one second. edit: edited my code since I forgot ()'s on my CurTime. Soz
- snip -
[QUOTE=MPan1;52357491]snip [CODE] local time -- this makes the variable local even though it has no value local open = false -- this variable defines whether the menu is opened already hook.Add( "Think", "DoStuff", function() if input.IsKeyDown( KEY_R ) then -- if R is currently down if !time then time = CurTime() + 3 end -- set the time to be 3 seconds from now if CurTime() > time and !open then -- if it's been 3 seconds and the panel isn't already open frame:MoveTo(ScrW()-230, ScrH()-400, 2, 0, -1, function() -- move the frame frame:MakePopup() -- focus the menu end) open = true -- set the panel as being open end else open = false -- let them open it again after letting go of R time = nil -- reset the time end end ) [/CODE][/QUOTE] Why are you setting the var open to false upon letting the key go? What if there is already a previous menu opened and user presses the R button for 3 seconds again? Second menu would pop up, the var open should be set to false only by closing the derma frame, just to be sure.
[QUOTE=RaKo;52358621]Why are you setting the var open to false upon letting the key go? What if there is already a previous menu opened and user presses the R button for 3 seconds again?[/QUOTE] It wouldn't open another menu. MakePopup doesn't create a new menu, vgui.Create does. All MakePopup does is make the menu interactive. Here's a version with R only working once: [CODE] local time -- this makes the variable local even though it has no value local open = false -- this variable defines whether the menu is opened already hook.Add( "Think", "DoStuff", function() if input.IsKeyDown( KEY_R ) then -- if R is currently down if !time then time = CurTime() + 3 end -- set the time to be 3 seconds from now if CurTime() > time and !open then -- if it's been 3 seconds and the panel isn't already open frame:MoveTo(ScrW()-230, ScrH()-400, 2, 0, -1, function() -- move the frame frame:MakePopup() -- focus the menu end) open = true -- set the panel as being open end end end ) [/CODE] [QUOTE=RaKo;52358606]It does work, because the check goes further only if CurTime() is higher than time. Where if the check is successful, I set the time var to be higher than current CurTime() by one, which means the check will be successful again after one second. edit: edited my code since I forgot ()'s on my CurTime. Soz[/QUOTE] What I don't get about your code is the point of having the timepressed variable at all. It's easier to just use one variable - CurTime().
Well, thanks everyone for the help and sorry for that late reply haha
Sorry, you need to Log In to post a reply to this thread.