Basic start
This commit is contained in:
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug Cambridge",
|
||||||
|
"type": "lua-local",
|
||||||
|
"request": "launch",
|
||||||
|
"program": {
|
||||||
|
"command": "lovec"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"scriptRoots": [
|
||||||
|
"."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Lua.workspace.library": [
|
||||||
|
"${addons}/love2d/module/library"
|
||||||
|
],
|
||||||
|
"Lua.runtime.version": "LuaJIT",
|
||||||
|
"Lua.runtime.special": {
|
||||||
|
"love.filesystem.load": "loadfile"
|
||||||
|
},
|
||||||
|
"Lua.workspace.checkThirdParty": false
|
||||||
|
}
|
||||||
69
main.lua
69
main.lua
@@ -1,6 +1,12 @@
|
|||||||
|
if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE")=="1" then
|
||||||
|
LLDEBUGGER=require('lldebugger')
|
||||||
|
LLDEBUGGER.start()
|
||||||
|
end
|
||||||
|
|
||||||
function love.load()
|
function love.load()
|
||||||
highscores = {}
|
highscores = {}
|
||||||
love.graphics.setDefaultFilter("linear", "nearest")
|
love.graphics.setDefaultFilter("linear", "nearest")
|
||||||
|
|
||||||
require "load.rpc"
|
require "load.rpc"
|
||||||
require "load.graphics"
|
require "load.graphics"
|
||||||
require "load.fonts"
|
require "load.fonts"
|
||||||
@@ -9,8 +15,55 @@ function love.load()
|
|||||||
require "load.save"
|
require "load.save"
|
||||||
require "load.bigint"
|
require "load.bigint"
|
||||||
require "load.version"
|
require "load.version"
|
||||||
loadSave()
|
|
||||||
require "funcs"
|
require "funcs"
|
||||||
|
TOUCH_SETTINGS = require 'mobile_libs.settings'
|
||||||
|
BUTTON = require 'mobile_libs.simple-button'
|
||||||
|
BUTTON.setDefaultOption{
|
||||||
|
draw = function(self)
|
||||||
|
---@type love.Font
|
||||||
|
self.font = self.font
|
||||||
|
|
||||||
|
love.graphics.setColor(self.backgroundColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
|
||||||
|
if self._pressed then
|
||||||
|
love.graphics.setColor(self.pressColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
elseif self._hovering then
|
||||||
|
love.graphics.setColor(self.hoverColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = type(self.text) == 'function' and self.text() or self.text
|
||||||
|
|
||||||
|
local lineAmount
|
||||||
|
do
|
||||||
|
local _, t = self.font:getWrap(text, (self.w - 5) * 2)
|
||||||
|
lineAmount = #t
|
||||||
|
end
|
||||||
|
|
||||||
|
local _font_height = self.font:getHeight()
|
||||||
|
|
||||||
|
local textHeight = _font_height * (lineAmount * 0.5)
|
||||||
|
local textPos = self.y + (self.h * 0.5) - textHeight
|
||||||
|
|
||||||
|
love.graphics.setColor(self.textColor)
|
||||||
|
love.graphics.setFont(self.font)
|
||||||
|
love.graphics.printf(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation)
|
||||||
|
|
||||||
|
love.graphics.setColor(self.borderColor)
|
||||||
|
love.graphics.setLineWidth(1)
|
||||||
|
love.graphics.rectangle('line', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
end,
|
||||||
|
backgroundColor = {0, 0, 0, 0.8},
|
||||||
|
pressColor = {0.4, 1, 1, 0.5},
|
||||||
|
borderColor = {1, 1, 1, 0.8},
|
||||||
|
font=font_3x5_2,
|
||||||
|
}
|
||||||
|
require 'mobile_libs.vctrl'
|
||||||
|
|
||||||
|
loadSave()
|
||||||
require "scene"
|
require "scene"
|
||||||
|
|
||||||
--config["side_next"] = false
|
--config["side_next"] = false
|
||||||
@@ -22,6 +75,9 @@ function love.load()
|
|||||||
|
|
||||||
-- used for screenshots
|
-- used for screenshots
|
||||||
GLOBAL_CANVAS = love.graphics.newCanvas()
|
GLOBAL_CANVAS = love.graphics.newCanvas()
|
||||||
|
-- Used for transforming 2D positions
|
||||||
|
GLOBAL_TRANSFORM = love.math.newTransform()
|
||||||
|
love.resize(love.graphics.getWidth(), love.graphics.getHeight())
|
||||||
|
|
||||||
-- aliasing to prevent people using math.random by accident
|
-- aliasing to prevent people using math.random by accident
|
||||||
math.random = love.math.random
|
math.random = love.math.random
|
||||||
@@ -114,6 +170,9 @@ function love.keypressed(key, scancode)
|
|||||||
scene.restart_message = true
|
scene.restart_message = true
|
||||||
if config.secret then playSE("mode_decide")
|
if config.secret then playSE("mode_decide")
|
||||||
else playSE("erase", "single") end
|
else playSE("erase", "single") end
|
||||||
|
--TEST
|
||||||
|
elseif scancode == "f9" and scene.title == "Title" then
|
||||||
|
scene = TouchConfigScene()
|
||||||
-- f12 is reserved for saving screenshots
|
-- f12 is reserved for saving screenshots
|
||||||
elseif scancode == "f12" then
|
elseif scancode == "f12" then
|
||||||
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
||||||
@@ -283,6 +342,14 @@ end
|
|||||||
function love.resize(w, h)
|
function love.resize(w, h)
|
||||||
GLOBAL_CANVAS:release()
|
GLOBAL_CANVAS:release()
|
||||||
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
|
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
|
||||||
|
|
||||||
|
SCREEN_SCALE_FACTOR = math.min(w / 640, h / 480)
|
||||||
|
GLOBAL_TRANSFORM:setTransformation(
|
||||||
|
(w - SCREEN_SCALE_FACTOR * 640) / 2,
|
||||||
|
(h - SCREEN_SCALE_FACTOR * 480) / 2,
|
||||||
|
0,
|
||||||
|
SCREEN_SCALE_FACTOR
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- higher values of TARGET_FPS will make the game run "faster"
|
-- higher values of TARGET_FPS will make the game run "faster"
|
||||||
|
|||||||
41
mobile_libs/file.lua
Normal file
41
mobile_libs/file.lua
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
local FILE = {}
|
||||||
|
local binser = require "libs.binser"
|
||||||
|
-- local bitser = require "libs.bitser"
|
||||||
|
|
||||||
|
local serializer_used
|
||||||
|
|
||||||
|
function FILE.serialize(data)
|
||||||
|
if serializer_used == 'bitser' then
|
||||||
|
return bitser.dumps(data)
|
||||||
|
else
|
||||||
|
return binser.serialize(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FILE.deserialize(data)
|
||||||
|
if serializer_used == 'bitser' then
|
||||||
|
return bitser.loads(data)
|
||||||
|
else
|
||||||
|
return binser.deserialize(data)[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FILE.read(path)
|
||||||
|
if love.filesystem.getInfo(path) then
|
||||||
|
return FILE.deserialize(love.filesystem.read(path))
|
||||||
|
else
|
||||||
|
error("No file: "..path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FILE.write(path, data)
|
||||||
|
love.filesystem.write(path, FILE.serialize(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param lib_name 'bitser'|'binser'
|
||||||
|
---Init the FILE module with chosen serializer
|
||||||
|
return function(lib_name)
|
||||||
|
assert(lib_name == 'bitser' or lib_name == 'binser', '[lib_name] must be "bitser" or "binser"')
|
||||||
|
serializer_used = lib_name
|
||||||
|
_G.FILE = FILE
|
||||||
|
end
|
||||||
38
mobile_libs/settings.lua
Normal file
38
mobile_libs/settings.lua
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
local fs = love.filesystem
|
||||||
|
|
||||||
|
local CONFIG_FILE = '/mobile/touch_config.txt'
|
||||||
|
local _settings = fs.read(CONFIG_FILE) ~= nil and FILE.read(CONFIG_FILE) or {}
|
||||||
|
local _defaultSettings = {
|
||||||
|
firstTime = true,
|
||||||
|
__default__={
|
||||||
|
{type='button',x= 70,y=280,key= 'up',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x= 70,y=430,key= 'down',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x= -5,y=355,key= 'left',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x= 145,y=355,key= 'right',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x=640- -5,y=355,key= 'rotate_left',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x=640-145,y=355,key= 'rotate_left2',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x=640- 70,y=430,key= 'rotate_right',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x=640- 70,y=280,key='rotate_right2',r=45,iconSize=60,alpha=0.4},
|
||||||
|
{type='button',x=320, y=420,key= 'restart',r=35,iconSize=60,alpha=0.4},
|
||||||
|
},
|
||||||
|
|
||||||
|
---@type table<string,string>[]
|
||||||
|
bind = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
return setmetatable(
|
||||||
|
{__default__ = _defaultSettings},
|
||||||
|
{
|
||||||
|
__index = function(_, k)
|
||||||
|
if _settings[k] == nil then
|
||||||
|
_settings[k] = _defaultSettings[k]
|
||||||
|
FILE.write(CONFIG_FILE,_settings)
|
||||||
|
end
|
||||||
|
return _settings[k]
|
||||||
|
end,
|
||||||
|
__newindex = function(_, k, v)
|
||||||
|
_settings[k] = v
|
||||||
|
FILE.write(CONFIG_FILE,_settings)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
)
|
||||||
323
mobile_libs/simple-button.lua
Normal file
323
mobile_libs/simple-button.lua
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
-- SIMPLE-BUTTON.lua<br>
|
||||||
|
-- A simple module that aims to help you quickly create buttons<br>
|
||||||
|
-- It is can be used as a base class to help you quickly creating button<br>
|
||||||
|
-- This module has type notations so IntelliSense should give you some suggestions<br>
|
||||||
|
local BUTTON = {}
|
||||||
|
|
||||||
|
-- MIT License
|
||||||
|
|
||||||
|
-- Copyright (c) 2024 SweetSea-ButImNotSweet
|
||||||
|
|
||||||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
-- of this software and associated documentation files (the "Software"), to deal
|
||||||
|
-- in the Software without restriction, including without limitation the rights
|
||||||
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
-- copies of the Software, and to permit persons to whom the Software is
|
||||||
|
-- furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
-- The above copyright notice and this permission notice shall be included in all
|
||||||
|
-- copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
-- SOFTWARE.
|
||||||
|
|
||||||
|
local NULL = function() end
|
||||||
|
local function checkColorTableValidation(C)
|
||||||
|
if C and type(C) == "table" and (#C == 3 or #C == 4) then
|
||||||
|
for _, v in pairs(C) do
|
||||||
|
if type(v) ~= "number" or v<0 or v>1 then return false end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class BUTTON.button
|
||||||
|
---@field text? string|function # Name of the button, will be used to show
|
||||||
|
---@field textOrientation? "center"|"justify"|"left"|"right"
|
||||||
|
---
|
||||||
|
---@field x? number # Position of the button (x, y, w, h)
|
||||||
|
---@field y? number # Position of the button (x, y, w, h)
|
||||||
|
---@field w? number # Position of the button (x, y, w, h)
|
||||||
|
---@field h? number # Position of the button (x, y, w, h)
|
||||||
|
---@field r? number # Radius corner, cannot larger than half of button's width and half of button's height
|
||||||
|
---
|
||||||
|
---@field borderWidth? number|1 # Line width will be used to draw button
|
||||||
|
---@field borderJoin? "bevel"|"miter"|"none"
|
||||||
|
---@field borderStyle? "rough"|"smooth"
|
||||||
|
---
|
||||||
|
---@field font? love.Font
|
||||||
|
---
|
||||||
|
---@field backgroundColor? integer[]
|
||||||
|
---@field textColor? integer[]
|
||||||
|
---@field borderColor? integer[]
|
||||||
|
---@field hoverColor? integer[]
|
||||||
|
---@field pressColor? integer[]
|
||||||
|
---
|
||||||
|
---@field codeWhenPressed? function| # Code will be execute when pressed
|
||||||
|
---@field codeWhenReleased? function| # Code will be execute when released
|
||||||
|
---@field drawingButtonFunc? function| # The function is used to draw text<br>You can override the default one if you feel the default text drawing function is not suitable for you
|
||||||
|
---
|
||||||
|
---@field draw? function
|
||||||
|
---@field update? function
|
||||||
|
local button = {
|
||||||
|
textOrientation = "center",
|
||||||
|
r = 0,
|
||||||
|
|
||||||
|
backgroundColor = {0,0,0,0},
|
||||||
|
hoverColor = {1,1,1,0.5},
|
||||||
|
pressColor = {0, 1, 0.5, 0.5},
|
||||||
|
borderColor = {1,1,1},
|
||||||
|
textColor = {1,1,1},
|
||||||
|
|
||||||
|
font = love.graphics.newFont(15),
|
||||||
|
|
||||||
|
borderWidth = 1,
|
||||||
|
borderJoin = "none",
|
||||||
|
borderStyle = "smooth",
|
||||||
|
|
||||||
|
codeWhenPressed = NULL,
|
||||||
|
codeWhenReleased = NULL,
|
||||||
|
update = NULL,
|
||||||
|
|
||||||
|
_hovering = false,
|
||||||
|
_pressed = false,
|
||||||
|
_touchID = false,
|
||||||
|
}; button.__index = button
|
||||||
|
function button:draw()
|
||||||
|
love.graphics.setLineWidth(self.borderWidth)
|
||||||
|
love.graphics.setLineStyle(self.borderStyle)
|
||||||
|
love.graphics.setLineJoin(self.borderJoin)
|
||||||
|
|
||||||
|
love.graphics.setColor(self.backgroundColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
|
||||||
|
if self._pressed then
|
||||||
|
love.graphics.setColor(self.pressColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
elseif self._hovering then
|
||||||
|
love.graphics.setColor(self.hoverColor)
|
||||||
|
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setColor(self.textColor)
|
||||||
|
love.graphics.setFont(self.font)
|
||||||
|
|
||||||
|
local text = type(self.text) == 'function' and self.text() or self.text
|
||||||
|
|
||||||
|
local lineAmount
|
||||||
|
do
|
||||||
|
local _, t = self.font:getWrap(text, self.w)
|
||||||
|
lineAmount = #t
|
||||||
|
end
|
||||||
|
local textHeight = self.font:getHeight() * (lineAmount * 0.5)
|
||||||
|
local textPos = self.y + (self.h * 0.5) - textHeight
|
||||||
|
love.graphics.printf(text, self.x, textPos, self.w, self.textOrientation)
|
||||||
|
|
||||||
|
love.graphics.setColor(self.borderColor)
|
||||||
|
love.graphics.rectangle('line', self.x, self.y, self.w, self.h, self.r)
|
||||||
|
end
|
||||||
|
---Check if current position is hovering the button, if it is, return true
|
||||||
|
function button:isHovering(x,y)
|
||||||
|
if not y then return false end
|
||||||
|
if
|
||||||
|
x >= self.x and
|
||||||
|
y >= self.y and
|
||||||
|
x <= self.x + self.w and
|
||||||
|
y <= self.y + self.h
|
||||||
|
then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---Trigger press action, only when ``self._hovering`` is true
|
||||||
|
function button:press(x, y, touchID)
|
||||||
|
if self:isHovering(x, y) and not self._pressed then
|
||||||
|
self._touchID = touchID
|
||||||
|
self._pressed = true
|
||||||
|
|
||||||
|
self.codeWhenPressed()
|
||||||
|
self:draw()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---Trigger release action, don't need ``self._hovering`` to ``true``
|
||||||
|
function button:release(x, y, touchID)
|
||||||
|
local valid
|
||||||
|
if touchID then
|
||||||
|
valid = touchID == self._touchID
|
||||||
|
else
|
||||||
|
valid = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if valid then
|
||||||
|
self._pressed = false
|
||||||
|
self._touchID = false
|
||||||
|
|
||||||
|
if touchID then
|
||||||
|
self._hovering = false
|
||||||
|
else
|
||||||
|
self._hovering = self:isHovering(x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:isHovering(x, y) then
|
||||||
|
self.codeWhenReleased()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param D BUTTON.button|BUTTON.newData
|
||||||
|
---@param safe? boolean @ Creating widget? If not then ignore accept missing important parameters
|
||||||
|
---@return nil
|
||||||
|
---Validate the provided data, will be called by ``BUTTON.new`` and ``BUTTON.setDefaultOption``<br>
|
||||||
|
---***WARNING! THIS FUNCTION WILL RAISE EXCEPTION IF DATA IS INVALID!***
|
||||||
|
function BUTTON.checkDataValidation(D, safe)
|
||||||
|
if not safe then
|
||||||
|
if type(D.text) == 'function' then
|
||||||
|
assert(type(D.text()) == 'string', "[text] is a function but it doesn't return any string?!")
|
||||||
|
elseif type(D.text) ~= 'string' then
|
||||||
|
error("[text] must be a string or a function returns string, got "..type(D.text))
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(type(D.x) == "number" , "[x] must be a integer")
|
||||||
|
assert(type(D.y) == "number" , "[y] must be a integer")
|
||||||
|
assert(type(D.w) == "number" and D.w > 0, "[w] must be a positive integer")
|
||||||
|
assert(type(D.h) == "number" and D.h > 0, "[h] must be a positive integer")
|
||||||
|
assert((type(D.r) == "number" and D.r >= 0 and D.r <= D.w * 0.5 and D.r <= D.h * 0.5) or D.r == nil, "[r] must be a positive integer and cannot larger than half of button's width and half of button's height")
|
||||||
|
else
|
||||||
|
assert(type(D.r) == "number" and D.r >= 0 or D.r == nil, "[r] must be a positive integer (CAUTION: a extra condition is temproraily ignored because you are setting default option)")
|
||||||
|
end
|
||||||
|
assert(table.contains({"center","justify","left","right"}, D.textOrientation) or D.textOrientation == nil, "[borderJoin] must be 'bevel', 'miter' or 'none")
|
||||||
|
assert((type(D.borderWidth) == "number" and D.borderWidth > 0) or D.borderWidth == nil, "[borderWidth] must be a postive integer")
|
||||||
|
assert(table.contains({"bevel", "miter", "none"}, D.borderJoin) or D.borderJoin == nil, "[borderJoin] must be 'bevel', 'miter' or 'none")
|
||||||
|
assert(table.contains({"rough", "smooth"}, D.borderStyle) or D.borderStyle == nil, "[borderStyle] must be 'rough' or 'smooth'")
|
||||||
|
assert((D.font and D.font.typeOf and D.font:typeOf("Font")) or D.font == nil, "[font] must be love.Font")
|
||||||
|
|
||||||
|
assert(checkColorTableValidation(D.backgroundColor), "[backgroundColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||||
|
assert(checkColorTableValidation(D.hoverColor), "[hoverColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||||
|
assert(checkColorTableValidation(D.pressColor), "[hoverColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||||
|
assert(checkColorTableValidation(D.borderColor), "[borderColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||||
|
assert(checkColorTableValidation(D.textColor), "[textColor] must be a table with r, g, b (, a) values, all of them must be integers between 0 and 1")
|
||||||
|
|
||||||
|
assert(type(D.codeWhenPressed) == "function" or D.codeWhenPressed == nil, "[codeWhenPressed] must be a function or nil")
|
||||||
|
assert(type(D.codeWhenReleased) == "function" or D.codeWhenReleased == nil, "[codeWhenReleased] must be a function or nil")
|
||||||
|
assert(type(D.drawingButtonFunc) == "function" or D.drawingButtonFunc == nil, "[drawingButtonFunc] must be a function or nil")
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class BUTTON.newData
|
||||||
|
---@field text string|function # Name of the button, will be used to show. If function provided, it should return the string!
|
||||||
|
---@field textOrientation? "center"|"justify"|"left"|"right"
|
||||||
|
---
|
||||||
|
---@field x number # Position of the button (x, y, w, h)
|
||||||
|
---@field y number # Position of the button (x, y, w, h)
|
||||||
|
---@field w number # Position of the button (x, y, w, h)
|
||||||
|
---@field h number # Position of the button (x, y, w, h)
|
||||||
|
---@field r? number # Radius corner, cannot larger than half of button's width and half of button's height
|
||||||
|
---
|
||||||
|
---@field borderWidth? number|1 # Line width will be used to draw button
|
||||||
|
---@field borderJoin? "bevel"|"miter"|"none"
|
||||||
|
---@field borderStyle? "rough"|"smooth"
|
||||||
|
---
|
||||||
|
---@field font? love.Font
|
||||||
|
---
|
||||||
|
---@field backgroundColor? integer[]
|
||||||
|
---@field textColor? integer[]
|
||||||
|
---@field borderColor? integer[]
|
||||||
|
---@field hoverColor? integer[]
|
||||||
|
---@field pressColor? integer[]
|
||||||
|
---
|
||||||
|
---@field codeWhenPressed? function| # Code will be execute when pressed
|
||||||
|
---@field codeWhenReleased? function| # Code will be execute when released
|
||||||
|
---@field drawingButtonFunc? function| # The function is used to draw text<br>You can override the default one if you feel the default text drawing function is not suitable for you
|
||||||
|
---
|
||||||
|
---@field draw? function
|
||||||
|
---@field update? function
|
||||||
|
|
||||||
|
---@param D BUTTON.newData
|
||||||
|
---@nodiscard
|
||||||
|
---Create a new button, provide you a table with 4 functions inside: draw and update, press and release<br>
|
||||||
|
---You need to put them into intended callbacks :)
|
||||||
|
---
|
||||||
|
---Remember to fill 5 necessary parameters: name, x, y, w and h
|
||||||
|
function BUTTON.new(D)
|
||||||
|
local B = setmetatable(D, button)
|
||||||
|
BUTTON.checkDataValidation(B)
|
||||||
|
return B
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param D BUTTON.button
|
||||||
|
function BUTTON.setDefaultOption(D)
|
||||||
|
BUTTON.checkDataValidation(setmetatable(D, button), true)
|
||||||
|
for k, v in pairs(D) do
|
||||||
|
if button[k] ~= nil then
|
||||||
|
button[k] = v
|
||||||
|
else
|
||||||
|
error("Parameter named ["..k.."] is not existed or cannot be set default value, in BUTTON!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- < EXTRA GENERAL OPTIONS >
|
||||||
|
|
||||||
|
---Draw all buttons in provided list
|
||||||
|
---@param list table<any,BUTTON.button>
|
||||||
|
function BUTTON.draw(list)
|
||||||
|
for _, v in pairs(list) do v:draw() end
|
||||||
|
end
|
||||||
|
---Update all buttons in provided list
|
||||||
|
---@param list table<any,BUTTON.button>
|
||||||
|
function BUTTON.update(list)
|
||||||
|
for _, v in pairs(list) do v:update() end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Check if current mouse position is inside button<br>
|
||||||
|
---Calling BUTTON.press will trigger this, but you can call it when moving mouse so button can be highlighted when being hovered
|
||||||
|
---@param list table<BUTTON.button>
|
||||||
|
---@param x number # Mouse position
|
||||||
|
---@param y number # Mouse position
|
||||||
|
function BUTTON.checkHovering(list, x, y)
|
||||||
|
local highlighted_a_button = false
|
||||||
|
for _, v in pairs(list) do
|
||||||
|
if highlighted_a_button then
|
||||||
|
v._hovering = false
|
||||||
|
else
|
||||||
|
v._hovering = v:isHovering(x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not highlighted_a_button and v._hovering then highlighted_a_button = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Trigger the press action, only if ``button._hovering == true``
|
||||||
|
---@param list table<BUTTON.button>
|
||||||
|
---@param x number # Mouse position
|
||||||
|
---@param y number # Mouse position
|
||||||
|
function BUTTON.press(list, x, y, touchID)
|
||||||
|
for _, v in pairs(list) do if v:press(x, y, touchID) then return true end end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Trigger the release action
|
||||||
|
---@param list table<BUTTON.button>
|
||||||
|
function BUTTON.release(list, x, y, touchID)
|
||||||
|
for _, v in pairs(list) do if v:release(x, y, touchID) then return true end end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Do a reset, useful for switching scenes
|
||||||
|
function BUTTON.reset(list)
|
||||||
|
for _, v in pairs(list) do
|
||||||
|
v._pressed = false
|
||||||
|
v._hovering = false
|
||||||
|
v._touchID = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return BUTTON
|
||||||
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
|
||||||
BIN
mobile_libs/vctrlTexture.png
Normal file
BIN
mobile_libs/vctrlTexture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
296
mobile_scene/touch_config.lua
Normal file
296
mobile_scene/touch_config.lua
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
---@diagnostic disable: cast-local-type
|
||||||
|
local TouchConfigScene = Scene:extend()
|
||||||
|
TouchConfigScene.title = "Touchscreen config"
|
||||||
|
|
||||||
|
local function roundUnit(n,u)
|
||||||
|
local u = u or 1
|
||||||
|
return math.floor(n/u+.5)*u
|
||||||
|
end
|
||||||
|
local function drawText(text, x, y, size, orientation, color)
|
||||||
|
if color == nil then color = {1, 1, 1, 1} end
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
love.graphics.setColor(color)
|
||||||
|
love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
local buttonList
|
||||||
|
local sliderList = {}
|
||||||
|
---@class VCTRL.data
|
||||||
|
local focusingButton
|
||||||
|
---@type number
|
||||||
|
local snapUnit = 1
|
||||||
|
|
||||||
|
---@type function
|
||||||
|
local function exitSceneFunc(saved)
|
||||||
|
VCTRL.release()
|
||||||
|
BUTTON.release(buttonList)
|
||||||
|
if TOUCH_SETTINGS.firstTime and not saved then
|
||||||
|
SCENE = InputConfigScene(true)
|
||||||
|
else
|
||||||
|
SCENE = TitleScene()
|
||||||
|
TOUCH_SETTINGS.firstTime = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
buttonList = {
|
||||||
|
showToggle = BUTTON.new{
|
||||||
|
text = function()
|
||||||
|
if focusingButton then
|
||||||
|
return focusingButton.show and ">SHOW<\nhide" or "show\n>HIDE<"
|
||||||
|
else
|
||||||
|
return "show\nhide"
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
x = 400, y = 110, w = 60, h = 40,
|
||||||
|
codeWhenReleased = function()
|
||||||
|
if focusingButton then
|
||||||
|
focusingButton.show = not focusingButton.show
|
||||||
|
VCTRL.hasChanged = true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
update = function(self) self.textColor = focusingButton and {1, 1, 1} or {0.5, 0.5, 0.5} end
|
||||||
|
},
|
||||||
|
-- previewToggle = BUTTON.new{
|
||||||
|
-- text = "Preview\nON",
|
||||||
|
-- x = 570, y = 60, w = 60, h = 40,
|
||||||
|
-- codeWhenReleased = function()
|
||||||
|
-- VCTRL.release()
|
||||||
|
-- BUTTON.release(buttonList)
|
||||||
|
-- SCENE = TouchConfigPreviewScene()
|
||||||
|
-- end
|
||||||
|
-- },
|
||||||
|
resetAll = BUTTON.new{
|
||||||
|
text = "RESET\nALL",
|
||||||
|
x = 500, y = 110, w = 60, h = 40,
|
||||||
|
codeWhenReleased = function()
|
||||||
|
local selection = love.window.showMessageBox(
|
||||||
|
"Save config?", "Are you really sure about RESETTING ALL touchscreen configuration?",
|
||||||
|
{"Yes", "No", escapebutton = 2, enterbutton = 1},
|
||||||
|
"info", true
|
||||||
|
)
|
||||||
|
if selection == 1 then
|
||||||
|
VCTRL.focus = nil; focusingButton = nil
|
||||||
|
VCTRL.hasChanged = false
|
||||||
|
VCTRL.clearAll()
|
||||||
|
VCTRL.new(TOUCH_SETTINGS.__default__)
|
||||||
|
TOUCH_SETTINGS.bind[1] = TOUCH_SETTINGS.__default__
|
||||||
|
end
|
||||||
|
end
|
||||||
|
},
|
||||||
|
menuScreen = BUTTON.new{
|
||||||
|
text = "MENU",
|
||||||
|
x = 570, y = 10, w = 60, h = 40,
|
||||||
|
codeWhenReleased = function()
|
||||||
|
if VCTRL.hasChanged or TOUCH_SETTINGS.firstTime then
|
||||||
|
local selection = love.window.showMessageBox(
|
||||||
|
"Save config?", "Do you want to save your changes before exiting?",
|
||||||
|
{"Save", "Discard", "Keep editing", escapebutton = 3, enterbutton = 1},
|
||||||
|
"info", true
|
||||||
|
)
|
||||||
|
if selection == 1 then
|
||||||
|
TOUCH_SETTINGS.bind[1] = VCTRL.exportAll()
|
||||||
|
-- love.window.showMessageBox("Saved!", "Your changes was saved!")
|
||||||
|
|
||||||
|
exitSceneFunc(true)
|
||||||
|
elseif selection == 2 then
|
||||||
|
VCTRL.clearAll()
|
||||||
|
VCTRL.new(TOUCH_SETTINGS.bind[1])
|
||||||
|
-- love.window.showMessageBox("Discarded!", "Your changes was discarded!")
|
||||||
|
|
||||||
|
exitSceneFunc()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exitSceneFunc()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sliderList.buttonSize = newSlider(
|
||||||
|
200, 30, 120, 0, 0, 120,
|
||||||
|
function(v)
|
||||||
|
if focusingButton then
|
||||||
|
v = roundUnit(v, 5)
|
||||||
|
if focusingButton.r ~= v then
|
||||||
|
focusingButton.r = v
|
||||||
|
VCTRL.hasChanged = true
|
||||||
|
end
|
||||||
|
sliderList.buttonSize.value = v / 120
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{width = 40}
|
||||||
|
)
|
||||||
|
sliderList.iconSize = newSlider(
|
||||||
|
480, 30, 120, 0, 0, 100,
|
||||||
|
function(v)
|
||||||
|
if focusingButton then
|
||||||
|
v = roundUnit(v, 5)
|
||||||
|
if focusingButton.iconSize ~= v then
|
||||||
|
focusingButton.iconSize = v
|
||||||
|
VCTRL.hasChanged = true
|
||||||
|
end
|
||||||
|
sliderList.iconSize.value = v / 100
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{width = 40}
|
||||||
|
)
|
||||||
|
sliderList.opacity = newSlider(
|
||||||
|
200, 80, 120, 0, 0, 1,
|
||||||
|
function()
|
||||||
|
local v
|
||||||
|
if focusingButton then
|
||||||
|
v = roundUnit(sliderList.opacity.value, 0.01)
|
||||||
|
if focusingButton.alpha~=v then
|
||||||
|
focusingButton.alpha = v
|
||||||
|
VCTRL.hasChanged = true
|
||||||
|
end
|
||||||
|
sliderList.opacity.value = v
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{width = 40}
|
||||||
|
)
|
||||||
|
local gridSizeTable = {1, 2, 5, 10, 20, 50, 100}
|
||||||
|
sliderList.gridSize = newSlider(
|
||||||
|
480, 80, 120, 1, 1, #gridSizeTable - 1,
|
||||||
|
function()
|
||||||
|
local f = #gridSizeTable - 1
|
||||||
|
local v = roundUnit(sliderList.gridSize.value, 1 / f)
|
||||||
|
sliderList.gridSize.value = v
|
||||||
|
snapUnit = gridSizeTable[roundUnit(v * f + 1)]
|
||||||
|
end,
|
||||||
|
{width = 40}
|
||||||
|
); sliderList.gridSize.forceLight = true
|
||||||
|
|
||||||
|
local function sliderList_draw()
|
||||||
|
for _, s in pairs(sliderList) do
|
||||||
|
if s.forceLight then
|
||||||
|
love.graphics.setColor(1, 1, 1)
|
||||||
|
else
|
||||||
|
love.graphics.setColor(focusingButton and {1, 1, 1} or {0.5, 0.5, 0.5})
|
||||||
|
end
|
||||||
|
love.graphics.setLineWidth(1)
|
||||||
|
s:draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sliderList_update()
|
||||||
|
local x, y
|
||||||
|
if #love.touch.getTouches() == 1 then
|
||||||
|
x, y = GLOBAL_TRANSFORM:inverseTransformPoint(love.touch.getPosition(love.touch.getTouches()[1]))
|
||||||
|
else
|
||||||
|
x, y = GLOBAL_TRANSFORM:inverseTransformPoint(love.mouse.getPosition())
|
||||||
|
end
|
||||||
|
for _, s in pairs(sliderList) do
|
||||||
|
s:update(x, y, #love.touch.getTouches() == 1 or love.mouse.isDown(1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TouchConfigScene:new()
|
||||||
|
VCTRL.toggle(true)
|
||||||
|
|
||||||
|
VCTRL.focus = nil
|
||||||
|
focusingButton = nil
|
||||||
|
end
|
||||||
|
function TouchConfigScene:update()
|
||||||
|
-- TODO
|
||||||
|
if VCTRL.focus~=focusingButton then
|
||||||
|
focusingButton = VCTRL.focus
|
||||||
|
sliderList.opacity.value = focusingButton.alpha
|
||||||
|
sliderList.buttonSize.value = focusingButton.r / 120
|
||||||
|
sliderList.iconSize.value = focusingButton.iconSize / 100
|
||||||
|
end
|
||||||
|
|
||||||
|
BUTTON.update(buttonList)
|
||||||
|
sliderList_update()
|
||||||
|
end
|
||||||
|
|
||||||
|
local string_format = string.format
|
||||||
|
function TouchConfigScene:render()
|
||||||
|
drawBackground("title_night")
|
||||||
|
|
||||||
|
if snapUnit >= 5 then
|
||||||
|
local x1, y1 = GLOBAL_TRANSFORM:inverseTransformPoint(0, 0)
|
||||||
|
local x2, y2 = GLOBAL_TRANSFORM:inverseTransformPoint(love.graphics.getDimensions())
|
||||||
|
|
||||||
|
love.graphics.setColor(1,1,1,math.sin(love.timer.getTime()*4)*.1+.25)
|
||||||
|
love.graphics.setLineWidth(1)
|
||||||
|
-- From 0 to X
|
||||||
|
for i=x1, x2+snapUnit, snapUnit do
|
||||||
|
local x = i - i % snapUnit
|
||||||
|
love.graphics.line(x, y1, x, y2)
|
||||||
|
end
|
||||||
|
-- From 0 to Y
|
||||||
|
for i=y1,y2+snapUnit,snapUnit do
|
||||||
|
local y= i - i % snapUnit
|
||||||
|
love.graphics.line(x1, y, x2, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setColor(0, 0, 0, 0.7)
|
||||||
|
love.graphics.rectangle("fill", 5, 5, 560, 100)
|
||||||
|
|
||||||
|
-- Button Size
|
||||||
|
drawText(string_format("Size (buttons)\n%14.1d", focusingButton and focusingButton.r or 0), 10, 13, 100, "left")
|
||||||
|
-- Icon size
|
||||||
|
drawText(string_format("Size (icons)\n%13.1d%%", focusingButton and focusingButton.iconSize or 0), 290, 13, 100, "left")
|
||||||
|
-- Opacity
|
||||||
|
drawText(string_format("Opacity\n%13.1d%%", focusingButton and focusingButton.alpha * 100 or 0), 10, 63, 100, "left")
|
||||||
|
-- Snap to grid
|
||||||
|
drawText(string_format("Snap to grid\n%14.1d", snapUnit), 290, 63, 100, "left")
|
||||||
|
|
||||||
|
for _, v in ipairs(VCTRL) do
|
||||||
|
if v ~= focusingButton then
|
||||||
|
v:draw(
|
||||||
|
focusingButton and
|
||||||
|
(v.show and 0.5 or 0.1) or
|
||||||
|
(v.show and 1 or 0.5)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if focusingButton then
|
||||||
|
focusingButton:draw(
|
||||||
|
math.clamp(
|
||||||
|
math.sin(love.timer.getTime()*4)*.5+0.1,
|
||||||
|
focusingButton.show and 1 or 0.1, 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
sliderList_draw()
|
||||||
|
BUTTON.draw(buttonList)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param e SCENE_onInput
|
||||||
|
function TouchConfigScene:onInputMove(e)
|
||||||
|
if e.type == "touch" or (e.type == "mouse" and love.mouse.isDown(1)) then
|
||||||
|
if VCTRL.drag(e.dx, e.dy, e.id or 1) then VCTRL.hasChanged = true end
|
||||||
|
elseif e.type == "mouse" then
|
||||||
|
BUTTON.checkHovering(buttonList, e.x, e.y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---@param e SCENE_onInput
|
||||||
|
function TouchConfigScene:onInputPress(e)
|
||||||
|
if e.type == "mouse" or e.type == "touch" then
|
||||||
|
if not (
|
||||||
|
VCTRL.press(e.x, e.y, e.id and e.id or 1, true) or
|
||||||
|
BUTTON.press(buttonList, e.x, e.y, e.id) or
|
||||||
|
(e.x >= 120 and e.x <= 280 and e.y >= 10 and e.y <= 100) or
|
||||||
|
(e.x >= 400 and e.x <= 560 and e.y >= 10 and e.y <= 100)
|
||||||
|
) then
|
||||||
|
VCTRL.focus = nil
|
||||||
|
focusingButton = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---@param e SCENE_onInput
|
||||||
|
function TouchConfigScene:onInputRelease(e)
|
||||||
|
if e.type == "mouse" or e.type == "touch" then
|
||||||
|
if not BUTTON.release(buttonList, e.x, e.y, e.id) then
|
||||||
|
if focusingButton and VCTRL.release(e.id or 1) then
|
||||||
|
focusingButton.x = roundUnit(focusingButton.x, snapUnit)
|
||||||
|
focusingButton.y = roundUnit(focusingButton.y, snapUnit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return TouchConfigScene
|
||||||
@@ -21,3 +21,4 @@ TuningScene = require "scene.tuning"
|
|||||||
SettingsScene = require "scene.settings"
|
SettingsScene = require "scene.settings"
|
||||||
CreditsScene = require "scene.credits"
|
CreditsScene = require "scene.credits"
|
||||||
TitleScene = require "scene.title"
|
TitleScene = require "scene.title"
|
||||||
|
TouchConfigScene = require "mobile_scene.touch_config"
|
||||||
Reference in New Issue
Block a user