Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
--# Passdrag
Passdrag
= class() -- Looks odd as code, but nice if it crashes
local ellipseMesh = function(width, height, top, bottom, change) -- Function to create a(n) circle/ellipse mesh with a gradient
local pwidth, pheight, ptop, pbototom, pchange
pwidth = width or 128
if type(height) == "number" or height == nil then
pheight = height or width
ptop = top or color(255)
if type(bottom) == "userdata" then
pbottom = bottom or ptop
pchange = change or 1
else
pbottom = ptop
pchange = bottom or 1
end
else
pheight = width
ptop = height or color(255)
if type(top) == "userdata" then
pbottom = top or ptop
pchange = bottom or 1
else
pbottom = ptop
pchange = top or 1
end
end
pwidth, pheight = pwidth / 2, pheight / 2
local m = mesh()
local v = {}
local c = {}
local p = {}
for d = 0, 360, pchange do
local r = math.rad(d)
table.insert(p, vec2(pwidth * math.sin(r), pheight * math.cos(r)))
end
v = triangulate(p)
m.vertices = v
for k, v in ipairs(v) do
table.insert(c, ptop:mix(pbottom, v:normalize().y * 0.5 + 0.5))
end
m.colors = c
return m
end
function Passdrag:init(x, y, size) -- Passdrag GUI & handler setup
self.rot = {a = 0}
self.tid = 0
self.size = size
self.x, self.y = x, y
self.ePos = vec2(0, size)
self.styles = {
Light = {
bg = color(255),
txt = color(200),
cFill = color(255),
cStroke = color(220),
cDark = color(210),
pWidth = 5,
},
Dark = {
bg = color(0),
txt = color(40),
cFill = color(30),
cStroke = color(25),
cDark = color(20),
pWidth = 5
},
Retro = {
bg = color(128, 96, 64, 255),
txt = color(64, 24, 16),
cFill = color(136, 102, 74, 255),
cStroke = color(74, 32, 24),
cDark = color(64, 24, 16),
pWidth = 3,
},
Nature = {
bg = color(191, 255, 191),
txt = color(31, 63, 31),
cFill = color(74, 136, 74),
cStroke = color(63, 127, 63),
cDark = color(48, 112, 48),
pWidth = 5,
},
Sky = {
bg = color(191, 223, 255),
txt = color(255),
cFill = color(95, 191, 255),
cStroke = color(240, 240),
cDark = color(74, 120, 255),
pWidth = 8,
},
}
self.oldStyles = self.styles
self.style = "Light"
self.darkness = {a = 0}
self:updateMesh()
self.sequence = ""
self.lastChar = ""
end
function Passdrag:updateMesh() -- Update the gradiented mesh, not recommended for manual use
self.m = ellipseMesh(self.size / 3 - self.styles[self.style].pWidth, self.styles[self.style].cFill, self.styles[self.style].cDark, 10)
end
function Passdrag:setStyle(x) -- Set style to x
self.style = x
self:updateMesh()
end
function Passdrag:addStyle(x, y) -- Add style x with a preset of y
self.styles[x] = y
end
function Passdrag:duplicateStyle(x, y) -- Make a new style y, with the presets of x
self.styles[y] = self.styles[x]
end
function Passdrag:deleteStyle(x) -- Delete style x
self.styles[x] = nil
end
function Passdrag:restoreStyle(x) -- Restore style (x or current) to its original preset
x = x or self.style
self.styles[x] = self.oldStyles[x]
end
function Passdrag:restoreStyles() -- Restore all styles to their original presets
self.styles = self.oldStyles
end
function Passdrag:addChar(x) -- Add character to current drag, not recommended for manual use
if x ~= self.lastChar then
self.sequence = self.sequence .. x
self.lastChar = x
end
end
function Passdrag:resetSequence() -- Reset drag
self.sequence = ""
self.lastChar = ""
end
function Passdrag:draw() -- Draw the GUI and update
for k, v in pairs(self.styles[self.style]) do
self["g" .. k] = v
end
local checks = {"bg", "txt", "cFill", "cStroke", "cDark", "pWidth"}
for k, v in ipairs(checks) do
if self["s" .. v] ~= nil then
self.styles[style][v] = self["s" .. v]
self["s" .. v] = nil
end
end
local deg = math.floor(math.abs((math.deg(self.rot.a) - 90) / 45) + 0.5)
if deg == 8 then
deg = 0
end
for i = 1, 3 do
if deg <= 5 then
deg = deg + 2
elseif deg >= 6 then
deg = deg - 6
end
end
self:addChar(tostring(deg + 1))
local c = {}
for k, v in ipairs(self.m.vertices) do
table.insert(c, self.styles[self.style].cFill:mix(self.styles[self.style].cDark:mix(self.styles[self.style].cFill, self.darkness.a), v:normalize().y * 0.5 + 0.5))
end
self.m.colors = c
pushMatrix()
pushStyle()
fill(self.styles[self.style].cFill)
stroke(self.styles[self.style].cStroke)
strokeWidth(self.styles[self.style].pWidth)
self.ePos.x, self.ePos.y = math.sin(-self.rot.a) * self.size / 2, math.cos(-self.rot.a) * self.size / 2
translate(self.x, self.y)
pushMatrix()
translate(self.ePos.x, self.ePos.y)
ellipse(0, 0, self.size / 3)
self.m:draw()
fill(0, 0)
ellipse(0, 0, self.size / 3)
popMatrix()
for i = 0, 7 do
pushMatrix()
rotate(i * (360 / 8))
line(self.size - self.size / 4, 0, self.size, 0)
popMatrix()
end
popStyle()
popMatrix()
end
function Passdrag:touched(touch) -- Handles touches & animations on the GUI
if self.tid == 0 and touch.state == BEGAN and vec2(touch.x - self.x, touch.y - self.y):dist(self.ePos) < self.size / 3 then
self.tid = touch.id
if self.t ~= nil then
tween.stop(self.t)
end
if self.t2 ~= nil then
tween.stop(self.t2)
end
self.t = tween(0.45, self.darkness, {a = 1}, tween.easing.quadInOut)
end
if touch.id == self.tid and (touch.state == BEGAN or touch.state == MOVING) then
self.rot.a = math.atan2(touch.y - HEIGHT / 2, touch.x - WIDTH / 2) - math.pi / 2
local deg = math.floor(math.abs((math.deg(self.rot.a) - 90) / 45) + 0.5)
if deg == 8 then
deg = 0
end
for i = 1, 3 do
if deg <= 5 then
deg = deg + 2
elseif deg >= 6 then
deg = deg - 6
end
end
self:addChar(tostring(deg + 1))
end
if touch.id == self.tid and (touch.state == ENDED or touch.state == CANCELLED) then
self.tid = 0
tween.stop(self.t)
self.t = tween(0.45, self.darkness, {a = 0}, tween.easing.quadInOut)
self.t2 = tween(0.45, self.rot, {a = math.rad(((math.floor(math.deg(self.rot.a) / 45 - 0.5) + 0.5) + 0.5) * 45)})
end
end
--# Main
-- Passdrag
function setup()
print()
pd = Passdrag(WIDTH / 2, HEIGHT / 2, 200)
styles = {"Light", "Dark", "Retro", "Nature", "Sky"}
parameter.integer("Style", 1, #styles, 1)
parameter.watch("styles[Style]")
parameter.watch("pd.sequence")
parameter.action("Save Passdrag", function()
savePassdrag()
output.clear()
print()
tween.delay(0.1, function()
output.clear()
print()
print("Passdrag saved")
end)
end)
parameter.watch("Saved_Passdrag")
parameter.watch("Passdrag_Matches_Saved")
end
function draw()
pd:setStyle(styles[Style])
background(pd.styles[pd.style].bg)
Saved_Passdrag = readPassdrag()
Passdrag_Matches_Saved = pd.sequence == Saved_Passdrag
pd:draw()
font("HelveticaNeue-Light")
fontSize(48)
fill(pd.styles[pd.style].txt)
text("Passdrag", WIDTH / 2, HEIGHT - HEIGHT / 16)
fontSize(24)
text("Your drag: " .. pd.sequence, WIDTH / 2, HEIGHT - HEIGHT / 8)
text("Drag length: " .. pd.sequence:len(), WIDTH / 2, HEIGHT - HEIGHT / 6)
end
function touched(touch)
pd:touched(touch)
end
function savePassdrag()
local fileName = "passdrag.txt"
local file = os.getenv("HOME") .. "/Documents/" .. fileName
local wFd = io.open(file, "w")
wFd:write(pd.sequence)
wFd:close()
end
function readPassdrag()
local fileName = "passdrag.txt"
local file = os.getenv("HOME") .. "/Documents/" .. fileName
local rFd = io.open(file, "r")
local v = ""
if rFd ~= nil then
for i in rFd:lines() do
v = v .. i
end
end
if rFd ~= nil then
rFd:close()
end
return v
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.