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 ShowLoadingText('virtual key skin') 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('game/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 80, 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.pressing=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 ---@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