Skip to content

Instantly share code, notes, and snippets.

@mattkrins
Last active May 14, 2017 17:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mattkrins/9983ea8ebca71d85a8c643bdadaab442 to your computer and use it in GitHub Desktop.
Save mattkrins/9983ea8ebca71d85a8c643bdadaab442 to your computer and use it in GitHub Desktop.
An Interactive 2D3D button library for Garry's Mod.
local Interactive2D3D = {}
Interactive2D3D.IsVisible = function(self) return (self.Visible or false) end
Interactive2D3D.Start = function(self, vPos, aRot, vScale)
if !vPos or !aRot then return false end
self.Valid = true
local plpostoscreenx = vPos.x - LocalPlayer():GetShootPos().x
local plpostoscreeny = vPos.y - LocalPlayer():GetShootPos().y
local plpostoscreen = math.sqrt( plpostoscreenx^2+plpostoscreeny^2 )
local dist1 = 1/( math.cos( math.rad( EyeAngles().y ) ) ) * plpostoscreen
local distfull = 1/( math.cos( math.rad( EyeAngles().p ) ) ) * dist1
local trace = {}
trace.start = LocalPlayer():GetShootPos()
trace.endpos = LocalPlayer():GetAimVector() * distfull + trace.start
trace.filter = LocalPlayer()
local tr = util.TraceLine( trace )
if tr.Entity and IsValid(tr.Entity) then self.Visible = false return false end
self.Visible = true
local test = trace.endpos
local vWorldPos=test-vPos;
vWorldPos:Rotate( Angle( 0, -aRot.y, 0 ) );
vWorldPos:Rotate( Angle( -aRot.p, 0, 0 ) );
vWorldPos:Rotate( Angle( 0, 0, -aRot.r ) );
self.EyeHitx = (vWorldPos.x/(vScale or 1))
self.EyeHity = ((-vWorldPos.y)/(vScale or 1))
return true
end
Interactive2D3D.Finish = function(self)
if !self:IsVisible() then return false end
return self:Remove()
end
Interactive2D3D.Use = function(self, Name)
if !self:IsVisible() then return false end
if !Name and self.Buttons then
for _,v in pairs(self.Buttons) do
if self:Use(v.Name) then if (v.LastClick or 0) < CurTime() then if v.DoClick then self:Remove(v.Name) v:DoClick() v.LastClick = CurTime()+0.1 return v.Name end end break end
end
else
if !self.Buttons or !self.Buttons[Name] then return false end
return self.Buttons[Name]:IsHovered()
end
end
hook.Add( "KeyPress", "Interactive2D3DKeyPress", function( _, key ) if ( key == IN_USE ) then Interactive2D3D:Use() end end )
Interactive2D3D.Remove = function(self, Name)
if Name and self.Buttons and self.Buttons[Name] then
self.Buttons[Name] = nil
else
self.Buttons = {}
self.Visible = false
self.Valid = false
end
return true
end
Interactive2D3D.MakeButton = function(self, x, y, w, h , Name)
if !Name or !self.Valid then return false end
self.Buttons = self.Buttons or {}
if self.Buttons[Name] then
if self:IsVisible() and self.EyeHitx and self.EyeHity then
if (self.EyeHitx < w-(x*-1)) and (self.EyeHitx > x) and (self.EyeHity < h-(y*-1)) and (self.EyeHity > y) then
if !self.Buttons[Name].Hovered then self.Buttons[Name].Hovered = true end
else
if self.Buttons[Name].Hovered then self.Buttons[Name].Hovered = false end
end
if self.Buttons[Name].Paint then self.Buttons[Name]:Paint(x, y, w, h) end
end
return self.Buttons[Name]
end
local Button = {}
Button.Name = Name
Button.Hovered = false
Button.IsHovered = function(this) return this.Hovered or false end
Button.Remove = function(this) return self:Remove(this.Name) or false end
Button.Pos = {x = (x or 0), y = (y or 0), w = (w or 0), h = (h or 0)}
Button.GetPos = function(this) return this.Pos or {} end
self.Buttons[Name] = Button
return Button
end
function cam.EndInteractive3D2D() cam.End3D2D() end
function cam.StartInteractive3D2D(vector, angle, scale, distance) -- This is a helper function to replace Start3D2D.
if distance then
if vector:Distance(LocalPlayer():GetPos()) < distance then
cam.Start3D2D( vector, angle, scale )
Interactive2D3D:Start(vector, angle, scale )
else
Interactive2D3D:Finish()
end
else
cam.Start3D2D( vector, angle, scale )
Interactive2D3D:Start(vector, angle, scale )
end
end
@mattkrins
Copy link
Author

mattkrins commented Oct 14, 2016

Example:

hook.Add( "PreDrawOpaqueRenderables", "ButtonTest", function()
    local vector = Vector(0,0,0)
    local distance = 1000
    if vector:Distance(LocalPlayer():GetPos()) < distance then
        local angle = Angle(0,0,0)
        angle:RotateAroundAxis( angle:Forward(), 90 )
        angle:RotateAroundAxis( angle:Right(), 90 )
        cam.StartInteractive3D2D( vector, angle, 0.1, distance ) -- This is a wrapper for Start3D2D, you see the code if you don't want to use it.
            local TestButton = Interactive2D3D:MakeButton(0, 0, 100, 100, "TestButton") -- Make a 3D2D button (x, y, w, h, UniqueName)
            TestButton.DoClick = function(self) -- When the button is pressed.
                print(self.Name.." Was Pressed!")
            end
            TestButton.Paint = function(self, x, y, w, h) -- This is a helper function, you don't need to actually render inside this.
                draw.RoundedBox( 0, x, y, w, h, Color( 255, 255, 255, 255 ) )
                if self:IsHovered() then draw.RoundedBox( 0, x, y, w, h, Color( 0, 0, 0, 255 ) ) end
            end
        cam.EndInteractive3D2D()
    end
end )

Preview:

example

Result when pressed with Use(E):

TestButton Was Pressed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment