Basic start
This commit is contained in:
245
mobile_libs/vctrl.lua
Normal file
245
mobile_libs/vctrl.lua
Normal file
@@ -0,0 +1,245 @@
|
||||
local gc_newQuad=love.graphics.newQuad
|
||||
|
||||
---Get distance between two points
|
||||
---@param x1 number
|
||||
---@param y1 number
|
||||
---@param x2 number
|
||||
---@param y2 number
|
||||
---@return number
|
||||
local function math_distance(x1,y1,x2,y2)
|
||||
return ((x1-x2)^2+(y1-y2)^2)^.5
|
||||
end
|
||||
|
||||
local function mDrawQ(obj,quad,x,y,a,k)
|
||||
local _,_,w,h=quad:getViewport()
|
||||
love.graphics.draw(obj,quad,x,y,a,k,nil,w*.5,h*.5)
|
||||
end
|
||||
|
||||
local empty_quad
|
||||
-- A table containing quads used to draw icons for virtual control system.
|
||||
-- local virtual_quad=setmetatable((function()
|
||||
-- local t={}
|
||||
-- local w=180
|
||||
-- empty_quad=gc_newQuad(0,0,1,1,5*w,7*w)
|
||||
-- for i,name in next,{
|
||||
-- 'left','right','up','down','',
|
||||
-- 'rotate_right','rotate_left','','','',
|
||||
-- '','','','','',
|
||||
-- '','','','','',
|
||||
-- '','','menu_back','','',
|
||||
-- '','','','','',
|
||||
-- '','','','','menu_decide',
|
||||
-- } do if #name>0 then t[name]=gc_newQuad((i-1)%5*w,math.floor((i-1)/5)*w,w,w,5*w,7*w) end end
|
||||
-- t.rotate_right2, t.rotate_left2 = t.rotate_right, t.rotate_left
|
||||
-- return t
|
||||
-- end)(),{
|
||||
-- __index=function() return empty_quad end
|
||||
-- })
|
||||
local virtual_quad=setmetatable((function()
|
||||
local t={}
|
||||
local w=180
|
||||
empty_quad=gc_newQuad(0,0,1,1,5*w,2*w)
|
||||
for i,name in next,{
|
||||
'left','right','up','down','restart',
|
||||
'rotate_right','rotate_left','rotate_right2','rotate_left2'
|
||||
} do if #name>0 then t[name]=gc_newQuad((i-1)%5*w,math.floor((i-1)/5)*w,w,w,5*w,2*w) end end
|
||||
return t
|
||||
end)(),{
|
||||
__index=function() return empty_quad end
|
||||
})
|
||||
local virtual_texture=love.graphics.newImage('mobile_libs/vctrlTexture.png')
|
||||
|
||||
|
||||
local control_type={}
|
||||
|
||||
control_type.button={}
|
||||
control_type.button.__index=control_type.button
|
||||
function control_type.button:new(data)
|
||||
local data=data or {}
|
||||
return setmetatable({
|
||||
show=data.show==nil and true or data.show,
|
||||
x=data.x or 320,
|
||||
y=data.y or 240,
|
||||
r=data.r or 80, -- size
|
||||
shape=data.shape or 'circle',
|
||||
key=data.key or 'X',
|
||||
iconSize=data.iconSize or 60,
|
||||
alpha=data.alpha or 0.75,
|
||||
quad=virtual_quad[data.key]
|
||||
},self)
|
||||
end
|
||||
function control_type.button:export()
|
||||
return {
|
||||
type = 'button',
|
||||
show = self.show,
|
||||
x = self.x,
|
||||
y = self.y,
|
||||
r = self.r,
|
||||
shape = self.shape,
|
||||
key = self.key,
|
||||
iconSize = self.iconSize,
|
||||
alpha = self.alpha
|
||||
}
|
||||
end
|
||||
function control_type.button:reset()
|
||||
self.pressed=false
|
||||
self.lastPressTime=-1e99
|
||||
self.pressingID=false
|
||||
end
|
||||
function control_type.button:press(_,_,id)
|
||||
self.pressed=true
|
||||
self.lastPressTime=love.timer.getTime()
|
||||
self.pressingID=id
|
||||
-- love.keypressed(self.key, love.keyboard.getScancodeFromKey(self.key))
|
||||
SCENE:onInputPress{input=self.key,type="virtual"}
|
||||
end
|
||||
function control_type.button:release()
|
||||
self.pressed=false
|
||||
self.pressingID=false
|
||||
-- love.keyreleased(self.key,love.keyboard.getScancodeFromKey(self.key))
|
||||
SCENE:onInputRelease{input=self.key,type="virtual"}
|
||||
end
|
||||
function control_type.button:drag(dx,dy)
|
||||
self.x,self.y=self.x+dx,self.y+dy
|
||||
end
|
||||
function control_type.button:draw(forceAlpha)
|
||||
local alpha = forceAlpha or self.alpha
|
||||
love.graphics.setLineWidth(4)
|
||||
if self.shape=='circle' then
|
||||
love.graphics.setColor(0,0,0,alpha)
|
||||
love.graphics.circle('fill',self.x,self.y,self.r-4)
|
||||
|
||||
love.graphics.setColor(1,1,1,self.pressed and .5 or 0)
|
||||
love.graphics.circle('fill',self.x,self.y,self.r-4)
|
||||
|
||||
love.graphics.setColor(1,1,1,alpha)
|
||||
love.graphics.circle('line',self.x,self.y,self.r-2)
|
||||
elseif self.shape=='square' then
|
||||
love.graphics.setColor(0,0,0,alpha)
|
||||
love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8)
|
||||
|
||||
love.graphics.setColor(1,1,1,self.pressed and .5 or 0)
|
||||
love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8)
|
||||
|
||||
love.graphics.setColor(1,1,1,alpha)
|
||||
love.graphics.rectangle('line',self.x-self.r-2,self.y-self.r-2,self.r*2+4,self.r*2+4)
|
||||
end
|
||||
if self.iconSize>0 and self.quad then
|
||||
love.graphics.setColor(1,1,1,alpha)
|
||||
local _,_,w,h=self.quad:getViewport()
|
||||
mDrawQ(
|
||||
virtual_texture,
|
||||
self.quad,
|
||||
self.x,self.y,0,
|
||||
self.iconSize/100*math.min(self.r*2/w,self.r*2/h)
|
||||
)
|
||||
end
|
||||
end
|
||||
function control_type.button:getDistance(x,y)
|
||||
if self.shape=='circle' then
|
||||
return math_distance(x,y,self.x,self.y)/self.r
|
||||
elseif self.shape=='square' then
|
||||
return math.max(math.abs(x-self.x),math.abs(y-self.y))/self.r
|
||||
end
|
||||
end
|
||||
|
||||
local touches={}
|
||||
local global_toggle=false
|
||||
VCTRL={}
|
||||
VCTRL.focus=nil -- Focusing buttons
|
||||
VCTRL.hasChanged = false
|
||||
|
||||
---@class VCTRL.data
|
||||
---@field type 'button'
|
||||
---@field x number
|
||||
---@field y number
|
||||
---@field shape? string
|
||||
---@field key? string
|
||||
---@field iconSize? number
|
||||
---@field alpha? number
|
||||
---@field show? boolean
|
||||
|
||||
---@param ... VCTRL.data[]
|
||||
---Adding (multiple) virtual button(s)
|
||||
function VCTRL.new(...)
|
||||
for _,d in pairs(...) do table.insert(VCTRL,control_type[d.type]:new(d)) end
|
||||
end
|
||||
|
||||
---@param toggle boolean|false
|
||||
---Enabling virtual control or not
|
||||
function VCTRL.toggle(toggle)
|
||||
if not toggle then
|
||||
-- Release all buttons to prevent button ghost situation
|
||||
for id, b in pairs(touches) do
|
||||
b:release(id)
|
||||
touches[id]=nil
|
||||
end
|
||||
end
|
||||
global_toggle=toggle
|
||||
end
|
||||
|
||||
function VCTRL.clearAll()
|
||||
local toggle = global_toggle
|
||||
VCTRL.toggle(false)
|
||||
global_toggle = toggle
|
||||
|
||||
for i=#VCTRL,1,-1 do VCTRL[i] = nil end
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
---@param force? boolean Forcing click on hidden widgets?
|
||||
function VCTRL.press(x,y,id,force)
|
||||
if not (global_toggle and id) then return end
|
||||
local obj,closestDist=false,1e99
|
||||
for _, w in ipairs(VCTRL) do
|
||||
if w.show or force then
|
||||
local d=w:getDistance(x,y)
|
||||
if d<=1 and d<closestDist then
|
||||
obj,closestDist=w,d
|
||||
end
|
||||
end
|
||||
end
|
||||
if obj then
|
||||
touches[id]=obj
|
||||
obj:press(x,y,id)
|
||||
VCTRL.focus=obj
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function VCTRL.release(id)
|
||||
if not (global_toggle and id) then return end
|
||||
if touches[id] then
|
||||
touches[id]:release()
|
||||
touches[id]=nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function VCTRL.drag(dx,dy,id)
|
||||
if not global_toggle then return end
|
||||
if touches[id] then
|
||||
touches[id]:drag(dx,dy)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function VCTRL.draw(forceAlpha)
|
||||
if not global_toggle then return end
|
||||
for _, w in ipairs(VCTRL) do
|
||||
if w.show then w:draw(forceAlpha) end
|
||||
end
|
||||
end
|
||||
|
||||
function VCTRL.reset()
|
||||
for _, w in ipairs(VCTRL) do
|
||||
if w.pressingID then touches[w.pressingID] = nil end
|
||||
w:reset()
|
||||
end
|
||||
end
|
||||
|
||||
function VCTRL.exportAll()
|
||||
local t = {}
|
||||
for o, k in ipairs(VCTRL) do t[o] = k:export() end
|
||||
return t
|
||||
end
|
||||
Reference in New Issue
Block a user