Last active
May 15, 2016 22:05
-
-
Save DolenzSong/ef91fd371fd13fe1c00a to your computer and use it in GitHub Desktop.
ChoiceMaker doesn't make anything right now, but is an initial implementation of a method for specifying screens and UIs as simple functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# Main | |
-- ChoiceMaker | |
--80 columns: | |
--3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 | |
displayMode(OVERLAY) | |
supportedOrientations(LANDSCAPE_ANY) | |
function setup() | |
--monitor performance | |
profiler.init() | |
--toggle for reporting debug messages | |
setReporting(true) | |
--set global styles | |
rectMode(CENTER) | |
font("HelveticaNeue-Light") | |
fontSize(24) | |
stroke(255, 255, 255, 255) | |
strokeWidth(3) | |
fill(255, 255, 255, 255) | |
--set starting state | |
showFirstScreen() | |
showFirstUI() | |
--create win and lose screens | |
winScreen = image(WIDTH,HEIGHT) | |
setContext(winScreen) | |
background(255, 231, 0, 255) | |
sprite("SpaceCute:Star", WIDTH / 2, HEIGHT/2,WIDTH,HEIGHT) | |
setContext() | |
loseScreen = image(WIDTH,HEIGHT) | |
setContext(loseScreen) | |
background(73, 30, 33, 255) | |
sprite("Tyrian Remastered:Flame Wave", WIDTH / 2, HEIGHT/2,WIDTH,HEIGHT) | |
setContext() | |
--tests() | |
startScreen = imageResizedToScreen(readImage("Cargo Bot:Game Area")) | |
uiPieceHandler.backgroundImage = startScreen | |
uiPieceHandler.shouldUpdateScreenBlur = true | |
end | |
function draw() | |
profiler.draw() | |
currentScreen() | |
currentUI() | |
end | |
--measure performance: | |
profiler={} | |
function profiler.init(quiet) | |
profiler.del=0 | |
profiler.c=0 | |
profiler.fps=0 | |
profiler.mem=0 | |
if not quiet then | |
parameter.watch("profiler.fps") | |
parameter.watch("profiler.mem") | |
end | |
end | |
function profiler.draw() | |
profiler.del = profiler.del + DeltaTime | |
profiler.c = profiler.c + 1 | |
if profiler.c==10 then | |
profiler.fps=profiler.c/profiler.del | |
profiler.del=0 | |
profiler.c=0 | |
profiler.mem=collectgarbage("count", 2) | |
end | |
end | |
--# setup | |
--showFirstScreen sets the currentScreen (will be loaded from a saved value in the future) | |
function showFirstScreen() | |
if currentScreen == nil then | |
currentScreen = sampleScreenA | |
end | |
end | |
--showFirstUI sets the currentUI (will be loaded from a saved value in the future) | |
function showFirstUI() | |
report("showing UI") | |
if currentUI == nil then | |
choicesActive = false | |
currentUI = introductionUI | |
end | |
end | |
--defineMainButtons sets up the main buttons for sample screens and UI. | |
--this means changes made to these in editable mode will not persist between sessions | |
function defineMainButtons() | |
--button for introductionUI: activates editable mode | |
uiPieceHandler.buttons['welcome'] = | |
{x = 502.5, y = 384.5, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = function() | |
showPlayModeUI() | |
choicesActive = true | |
end} | |
--button for toggling editableMode | |
uiPieceHandler.buttons['to editable mode'] = | |
{x = 928.5, y = 729.0, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = showEditModeUI} | |
--button for toggling fixed mode | |
uiPieceHandler.buttons['to fixed mode'] = | |
{x = 932.5, y = 727.5, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = showPlayModeUI} | |
--button for resetting sample game, used by both end screens | |
uiPieceHandler.buttons['reset sample game'] = | |
{x = 865.0, y = 248.5, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
--buttonTable definition for "you lose" text area | |
uiPieceHandler.buttons['you lost sample game'] = | |
{x = 865.0, y = 315.5, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
--buttonTable definition for "you win" text area | |
uiPieceHandler.buttons['you won sample game'] = | |
{x = 861.5, y = 319.0, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
--button for losing sample game, used on the start screen of the sample game | |
uiPieceHandler.buttons['lose sample game'] = | |
{x = 860.0, y = 167.5, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
--buttonTable definition for start screen text area | |
uiPieceHandler.buttons['sample game start screen'] = | |
{x = 860.5, y = 321.0, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
--button for winning sample game, used on the start screen of the sample game | |
uiPieceHandler.buttons['win sample game'] = | |
{x = 860.0, y = 244.0, width=uiPieceHandler.defaultWidth, | |
height=uiPieceHandler.defaultHeight, | |
action = uiPieceHandler.defaultButtonAction} | |
end | |
--# screens | |
--screen defaults | |
choiceWidth = 400 | |
narrationWidth = choiceWidth | |
narrationHeight = 300 | |
--draws backgroundImage and updates blur if needed | |
drawBackground = function(backgroundImage) | |
sprite(backgroundImage, WIDTH / 2, HEIGHT/2,WIDTH,HEIGHT) | |
if uiPieceHandler.shouldUpdateScreenBlur then | |
uiPieceHandler.screenBlur = imageWithGaussian2PassBlur(backgroundImage) | |
uiPieceHandler.shouldUpdateScreenBlur = false | |
end | |
end | |
--all the screens that can be used as currentScreen | |
function sampleScreenA() | |
drawBackground(startScreen) | |
textArea("sample game start screen",narrationWidth,narrationHeight) | |
choice("win sample game", sampleScreenB,choiceWidth) | |
choice("lose sample game", sampleScreenC,choiceWidth) | |
end | |
function sampleScreenB() | |
drawBackground(winScreen) | |
textArea("you won sample game",narrationWidth,narrationHeight) | |
choice("reset sample game", sampleScreenA,choiceWidth) | |
end | |
function sampleScreenC() | |
drawBackground(loseScreen) | |
textArea("you lost sample game",narrationWidth,narrationHeight) | |
choice("reset sample game", sampleScreenA,choiceWidth) | |
end | |
--# uiModes | |
--UI defaults | |
uiModeButtonWidth = 300 | |
uiModeButtonFontColor = color(229, 223, 94, 255) | |
--all the UIs that can be used as currentUI | |
function introductionUI() | |
tintScreen(color(255,128,128)) | |
button("welcome", function() | |
showPlayModeUI() | |
choicesActive = true | |
end) | |
end | |
function editModeUI() | |
tintScreen(color(0,128,128,95)) | |
button("to fixed mode", showPlayModeUI,uiModeButtonWidth,nil,uiModeButtonFontColor) | |
end | |
function playModeUI() | |
button("to editable mode", showEditModeUI,uiModeButtonWidth,nil,uiModeButtonFontColor) | |
end | |
--these are the routines that manage UI displays | |
function showUI() | |
if currentUI == nil then | |
currentUI = introductionUI | |
end | |
end | |
function showEditModeUI() | |
currentUI = editModeUI | |
buttons_are_draggable = true | |
end | |
function showPlayModeUI() | |
currentUI = playModeUI | |
buttons_are_draggable = false | |
end | |
--# uiPieces | |
--pieces are interface elements like buttons, text areas, etc | |
--because I began with the button class, all pieces are called 'buttons' in many places | |
--thess should all be refactored so that there's a generic 'piece' function | |
--button only actually needs a name to work, the rest have defaults | |
function button(name, action, width, height, fontColor) | |
--create a default button if none exists under this name | |
if uiPieceHandler.buttons[name] == nil then | |
uiPieceHandler.defaultButton(name) | |
end | |
--set button drawing values, using saved values if none passed in | |
local buttonTable = uiPieceHandler.buttons[name] | |
local x,y = buttonTable.x, buttonTable.y | |
width = width or buttonTable.width | |
height = height or buttonTable.height | |
fontColor = fontColor or buttonTable.fontColor | |
--update the stored values if necessary | |
if width ~= buttonTable.width then | |
uiPieceHandler.buttons[name].width = width | |
end | |
if height ~= buttonTable.height then | |
uiPieceHandler.buttons[name].height = height | |
end | |
if fontColor ~= buttonTable.fontColor then | |
uiPieceHandler.buttons[name].fontColor = fontColor | |
end | |
--'action' must be stored, not retrieved; it's called outside of this function | |
if action ~= nil or buttonTable.action == nil then | |
buttonTable.action = action | |
end | |
--draw the button | |
roundedRectangle{ | |
x=x,y=y,w=width,h=height, | |
tex=uiPieceHandler.screenBlur, | |
texCoord=vec4(x,y,width,height)} | |
styleSafe(function() | |
fill(fontColor) | |
text(name, x, y) | |
end) | |
--handle touches (wherein action gets called or not) | |
uiPieceHandler.evaluateTouchFor(name) | |
--set the flag that shows we rendered | |
uiPieceHandler.buttons[name].didRenderAlready = true | |
end | |
--textArea is a button that has no action and defaults to black text | |
function textArea(textToShow, width, height, fontColor) | |
--a placeholder action value | |
local action | |
--if first draw, set temporary empty action (in case tapped in first draw) | |
if uiPieceHandler.buttons[name] == nil then | |
action = function() end | |
end | |
--pass all the values to button()--by default setting border transparent (as above) | |
button(textToShow, action, width, height, fontColor) | |
--if button action isn't nil yet, nil it--this will only be needed first time drawn | |
if uiPieceHandler.buttons[textToShow].action ~= nil then | |
uiPieceHandler.buttons[textToShow].action = nil | |
end | |
end | |
--choice creates a button whose action changes currentScreen to the specified screen | |
function choice(choiceText, resultScreenAsFunction, width, height, fontColor) | |
--define the change screen action, depending on choicesActive setting | |
local choiceAction | |
local actionNotSet = uiPieceHandler.buttons[choiceText].action == uiPieceHandler.defaultButtonAction | |
if actionNotSet and resultScreenFunction ~= nil then | |
choiceAction = function () | |
currentScreen = resultScreenAsFunction | |
uiPieceHandler.shouldUpdateScreenBlur = true | |
end | |
end | |
--set custom font color and pass all values to button | |
fontColor = fontColor or color(160, 173, 223, 255) | |
button(choiceText, choiceAction, width, height, fontColor) | |
end | |
--[[ | |
true mesh rounded rectangle. Original by @LoopSpace | |
with anti-aliasing, optional fill and stroke components, optional texture that preserves aspect ratio of original image, automatic mesh caching | |
usage: RoundedRectangle{key = arg, key2 = arg2} | |
required: x;y;w;h: dimensions of the rectangle | |
optional: radius: corner rounding radius, defaults to 6; | |
corners: bitwise flag indicating which corners to round, defaults to 15 (all corners). | |
Corners are numbered 1,2,4,8 starting in lower-left corner proceeding clockwise | |
eg to round the two bottom corners use: 1 | 8 | |
to round all the corners except the top-left use: ~ 2 | |
tex: texture image | |
texCoord: vec4 specifying x,y,width,and height to use as texture coordinates | |
scale: size of rect (using scale) | |
use standard fill(), stroke(), strokeWidth() to set body fill color, outline stroke color and stroke width | |
]] | |
local __RRects = {} | |
function roundedRectangle(t) | |
local s = t.radius or 8 | |
local c = t.corners or 15 | |
local w = math.max(t.w+1,2*s)+1 | |
local h = math.max(t.h,2*s)+2 | |
local hasTexture = 0 | |
local texCoord = t.texCoord or vec4(0,0,1,1) --default to bottom-left-most corner, full with and height | |
if t.tex then hasTexture = 1 end | |
local label = table.concat({w,h,s,c,hasTexture,texCoord.x,texCoord.y},",") | |
if not __RRects[label] then | |
local rr = mesh() | |
rr.shader = shader(rrectshad.vert, rrectshad.frag) | |
local v = {} | |
local no = {} | |
local n = math.max(3, s//2) | |
local o,dx,dy | |
local edge, cent = vec3(0,0,1), vec3(0,0,0) | |
for j = 1,4 do | |
dx = 1 - 2*(((j+1)//2)%2) | |
dy = -1 + 2*((j//2)%2) | |
o = vec2(dx * (w * 0.5 - s), dy * (h * 0.5 - s)) | |
-- if math.floor(c/2^(j-1))%2 == 0 then | |
local bit = 2^(j-1) | |
if c & bit == bit then | |
for i = 1,n do | |
v[#v+1] = o | |
v[#v+1] = o + vec2(dx * s * math.cos((i-1) * math.pi/(2*n)), dy * s * math.sin((i-1) * math.pi/(2*n))) | |
v[#v+1] = o + vec2(dx * s * math.cos(i * math.pi/(2*n)), dy * s * math.sin(i * math.pi/(2*n))) | |
no[#no+1] = cent | |
no[#no+1] = edge | |
no[#no+1] = edge | |
end | |
else | |
v[#v+1] = o | |
v[#v+1] = o + vec2(dx * s,0) | |
v[#v+1] = o + vec2(dx * s,dy * s) | |
v[#v+1] = o | |
v[#v+1] = o + vec2(0,dy * s) | |
v[#v+1] = o + vec2(dx * s,dy * s) | |
local new = {cent, edge, edge, cent, edge, edge} | |
for i=1,#new do | |
no[#no+1] = new[i] | |
end | |
end | |
end | |
-- print("vertices", #v) | |
-- r = (#v/6)+1 | |
rr.vertices = v | |
rr:addRect(0,0,w-2*s,h-2*s) | |
rr:addRect(0,(h-s)/2,w-2*s,s) | |
rr:addRect(0,-(h-s)/2,w-2*s,s) | |
rr:addRect(-(w-s)/2, 0, s, h - 2*s) | |
rr:addRect((w-s)/2, 0, s, h - 2*s) | |
--mark edges | |
local new = {cent,cent,cent, cent,cent,cent, | |
edge,cent,cent, edge,cent,edge, | |
cent,edge,edge, cent,edge,cent, | |
edge,edge,cent, edge,cent,cent, | |
cent,cent,edge, cent,edge,edge} | |
for i=1,#new do | |
no[#no+1] = new[i] | |
end | |
rr.normals = no | |
--texture | |
if t.tex then | |
rr.shader.fragmentProgram = rrectshad.fragTex | |
rr.texture = t.tex | |
local w,h = t.tex.width,t.tex.height | |
local textureOffsetX,textureOffsetY = texCoord.x,texCoord.y | |
local coordTable = {} | |
for i,v in ipairs(rr.vertices) do | |
coordTable[i] = vec2((v.x + textureOffsetX)/w, (v.y + textureOffsetY)/h) | |
end | |
rr.texCoords = coordTable | |
end | |
local sc = 1/math.max(2, s) | |
rr.shader.scale = sc --set the scale, so that we get consistent one pixel anti-aliasing, regardless of size of corners | |
__RRects[label] = rr | |
end | |
__RRects[label].shader.fillColor = color(fill()) | |
if strokeWidth() == 0 then | |
__RRects[label].shader.strokeColor = color(fill()) | |
else | |
__RRects[label].shader.strokeColor = color(stroke()) | |
end | |
if t.resetTex then | |
__RRects[label].texture = t.resetTex | |
t.resetTex = nil | |
end | |
local sc = 0.25/math.max(2, s) | |
__RRects[label].shader.strokeWidth = math.min( 1 - sc*3, strokeWidth() * sc) | |
pushMatrix() | |
translate(t.x,t.y) | |
scale(t.scale or 1) | |
__RRects[label]:draw() | |
popMatrix() | |
end | |
rrectshad ={ | |
vert=[[ | |
uniform mat4 modelViewProjection; | |
attribute vec4 position; | |
//attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
//varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec3 vNormal; | |
void main() | |
{ | |
// vColor = color; | |
vTexCoord = texCoord; | |
vNormal = normal; | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
frag=[[ | |
precision highp float; | |
uniform lowp vec4 fillColor; | |
uniform lowp vec4 strokeColor; | |
uniform float scale; | |
uniform float strokeWidth; | |
//varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec3 vNormal; | |
void main() | |
{ | |
lowp vec4 col = mix(strokeColor, fillColor, smoothstep((1. - strokeWidth) - scale * 0.5, (1. - strokeWidth) - scale * 1.5 , vNormal.z)); //0.95, 0.92, | |
col = mix(vec4(col.rgb, 0.), col, smoothstep(1., 1.-scale, vNormal.z) ); | |
// col *= smoothstep(1., 1.-scale, vNormal.z); | |
gl_FragColor = col; | |
} | |
]], | |
fragTex=[[ | |
precision highp float; | |
uniform lowp sampler2D texture; | |
uniform lowp vec4 fillColor; | |
uniform lowp vec4 strokeColor; | |
uniform float scale; | |
uniform float strokeWidth; | |
//varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec3 vNormal; | |
void main() | |
{ | |
vec4 pixel = texture2D(texture, vTexCoord) * fillColor; | |
lowp vec4 col = mix(strokeColor, pixel, smoothstep(1. - strokeWidth - scale * 0.5, 1. - strokeWidth - scale * 1.5, vNormal.z)); //0.95, 0.92, | |
// col = mix(vec4(0.), col, smoothstep(1., 1.-scale, vNormal.z) ); | |
col *= smoothstep(1., 1.-scale, vNormal.z); | |
gl_FragColor = col; | |
} | |
]] | |
} | |
--# uiPieceHandler | |
-- uiPieceHandler: provides various functions for UI pieces: | |
-- enables pieces to be initialized with defaults | |
-- manages how pieces look and behave | |
uiPieceHandler = {} | |
uiPieceHandler.defaultWidth = 160 | |
uiPieceHandler.defaultHeight = 55 | |
uiPieceHandler.defaultFontColor = color(89, 75, 75, 255) | |
uiPieceHandler.buttons = {} | |
uiPieceHandler.shouldUpdateScreenBlur = true | |
uiPieceHandler.backgroundImage = 0 --not sure how this will be set irl | |
uiPieceHandler.screenBlur = 0 --0 means "none drawn yet"; will normally be an image | |
parameter.boolean("buttons are draggable", false) | |
uiPieceHandler.defaultButton = function(name) | |
uiPieceHandler.buttons[name] = {x=math.random(WIDTH),y=math.random(HEIGHT), | |
width = uiPieceHandler.defaultWidth, height = uiPieceHandler.defaultHeight, | |
fontColor = uiPieceHandler.defaultFontColor, | |
didRenderAlready = false} | |
end | |
uiPieceHandler.defaultButtonAction = function() | |
report("in 'setup()', use 'buttonAction(name, action)' to define an action for".. | |
"this button") | |
end | |
uiPieceHandler.doAction = function(name) | |
if uiPieceHandler.buttons[name].action == nil then | |
return | |
else | |
uiPieceHandler.buttons[name].action() | |
end | |
end | |
uiPieceHandler.clearRenderFlags = function() | |
for name, buttonTable in pairs(uiPieceHandler.buttons) do | |
buttonTable.didRenderAlready = false --now see if rendering is triggered at the right time | |
end | |
end | |
--evaluateTouchFor: called by each button inside the button() function | |
--precondition: to use CurrentTouch, pass nothing to the touch value | |
--postcondition: one of these: | |
-- a new activatedButton is set (if touch began on this piece) | |
-- activatedButton has been cleared (touch ended) | |
-- a button tap has occurred (for detecting button presses in editable mode) | |
-- a button has been moved (activatedButton was dragged in editable mode) | |
-- nothing (this piece did not interact with the touch) | |
uiPieceHandler.evaluateTouchFor = function(name, touch) | |
if touch == nil then | |
touch = CurrentTouch | |
end | |
if uiPieceHandler.thisButtonIsActivated(name, touch) then | |
uiPieceHandler.makeActivatedButtonRespond(name, touch) | |
end | |
end | |
--thisButtonIsActivated: called to decide if this button should respond to this touch | |
--precondition: name and touch cannot be nil | |
--postconditions: | |
-- activatedButton has been set or unchanged (note that it is never cleared here) | |
-- boolean returned true if the given button is the activatedButton, false if not | |
uiPieceHandler.thisButtonIsActivated = function(name, touch) | |
--if there is already an activatedButton and this isn't it, return false | |
if activatedButton ~= nil and activatedButton ~= name then | |
return false | |
end | |
--if there is no activatedButton, see if this should become activatedButton | |
if activatedButton == nil then | |
--if touch state is BEGAN and touch is inside button, set it to activatedButton | |
if touch.state == BEGAN and uiPieceHandler.touchIsInside(name, touch) then | |
activatedButton = name | |
else | |
--otherwise return false | |
return false | |
end | |
end | |
--here only reached if this is activated button (or has become it), so return true | |
return true | |
end | |
--uiPieceHandler.touchIsInside: calculated using touch's distance from this piece | |
--preconditions: name and touch cannot be nil, and touched object is basically rectangular | |
uiPieceHandler.touchIsInside = function(name, touch) | |
local xDistance = math.abs(touch.x-uiPieceHandler.buttons[name].x) | |
local yDistance = math.abs(touch.y-uiPieceHandler.buttons[name].y) | |
insideX = xDistance < uiPieceHandler.buttons[name].width /2 | |
insideY = yDistance < uiPieceHandler.buttons[name].height /2 | |
if insideX and insideY then | |
return true | |
else | |
return false | |
end | |
end | |
--makeActivatedButtonRespond: decide how the given button should react to given touch | |
--precondition: button and touch cannot be nil, button must be activatedButton | |
uiPieceHandler.makeActivatedButtonRespond = function(name, touch) | |
--move button if it should be moved | |
if buttons_are_draggable then | |
uiPieceHandler.evaluateDrag(name, touch) | |
end | |
--if this is an end touch, do a button action, or save new position, or do nothing | |
if touch.state == ENDED then | |
if buttons_are_draggable then | |
if touch.tapCount == 1 then | |
uiPieceHandler.doAction(name) | |
else | |
report("saving buttons positions") | |
uiPieceHandler.savePositions() | |
end | |
elseif uiPieceHandler.touchIsInside(name, touch) then | |
uiPieceHandler.doAction(name) | |
report(name, uiPieceHandler.buttons[name].action) | |
end | |
activatedButton = nil | |
end | |
end | |
uiPieceHandler.evaluateDrag = function (name, touch) | |
if touch.state == MOVING then | |
uiPieceHandler.buttons[name].x = touch.x | |
uiPieceHandler.buttons[name].y = touch.y | |
end | |
end | |
uiPieceHandler.savePositions = function (name, position) | |
dataString = "" | |
for name, buttonValues in pairs(uiPieceHandler.buttons) do | |
dataString = dataString.."uiPieceHandler.buttons['"..name.."'] = \n" | |
dataString = dataString.." {x = "..buttonValues.x | |
dataString = dataString..", y = "..buttonValues.y..",\n" | |
dataString = dataString.." width="..buttonValues.width..", " | |
dataString = dataString.."height="..buttonValues.height..",\n" | |
dataString = dataString.." fontColor=color("..buttonValues.fontColor.r.."," | |
dataString = dataString..buttonValues.fontColor.g.."," | |
dataString = dataString..buttonValues.fontColor.b.."," | |
dataString = dataString..buttonValues.fontColor.a.."),\n" | |
dataString = dataString.." action = uiPieceHandler.defaultButtonAction}\n\n" | |
end | |
saveProjectTab("uiPieceTables",dataString) | |
end | |
--# fullScreenBlur | |
function imageResizedToScreen(imageToResize) | |
local screenSizedImage = image(WIDTH,HEIGHT) | |
setContext(screenSizedImage) | |
sprite(imageToResize,WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) | |
setContext() | |
return screenSizedImage | |
end | |
function blurClipFromImage(sourceImage,x,y,width,height) | |
local clippedRect = image(width,height) | |
local clippedRectPosition = vec2(x,y) | |
local clippedRectHalved = vec2(width/2,height/2) | |
setContext(clippedRect) | |
pushMatrix() | |
translate(-clippedRectPosition.x+clippedRectHalved.x,-clippedRectPosition.y+clippedRectHalved.y) | |
sprite(sourceImage,sourceImage.width/2,sourceImage.height/2) | |
popMatrix() | |
setContext() | |
return imageWithGaussian2PassBlur(clippedRect) | |
end | |
function imageWithGaussian2PassBlur(imageToBlur) | |
--aspect ratio for blurring with: | |
local largestSide = math.max(imageToBlur.width,imageToBlur.height) | |
local aspect = vec2(largestSide/imageToBlur.width, largestSide/imageToBlur.height) --should be inverse ratio? | |
--aspect = vec2(0.45,0.45) --********* clean up | |
--dimensions for fullSized and downsampled images | |
local downsampleAmount = 0.5 -- going down to 0.25 actually looks pretty good, but, weirdly, slower than 0.5 | |
local fullDimensions = vec2(imageToBlur.width,imageToBlur.height) | |
local downsampleDimensions = vec2(imageToBlur.width*downsampleAmount,imageToBlur.height*downsampleAmount) | |
--images | |
local blurImages = {} | |
blurImages.fullSized = imageToBlur | |
blurImages.downsampled = image(downsampleDimensions.x,downsampleDimensions.y) | |
setContext(blurImages.downsampled) | |
sprite(imageToBlur,downsampleDimensions.x/2,downsampleDimensions.y/2,downsampleDimensions.x,downsampleDimensions.y) | |
setContext() | |
--meshes | |
local blurMeshes = {} | |
blurMeshes.horizontal = mesh() | |
blurMeshes.vertical = mesh() | |
--horizontal mesh settings | |
blurMeshes.horizontal.texture = blurImages.fullSized | |
blurMeshes.horizontal:addRect(downsampleDimensions.x/2,downsampleDimensions.y/2, | |
downsampleDimensions.x,downsampleDimensions.y) --fullSized image uses downsampled rect | |
blurMeshes.horizontal.shader = shader(gaussianShader.vert[1],gaussianShader.frag) | |
blurMeshes.horizontal.shader.am = aspect | |
--vertical mesh settings | |
blurMeshes.vertical.texture = blurImages.downsampled | |
blurMeshes.vertical:addRect(fullDimensions.x/2,fullDimensions.y/2, | |
fullDimensions.x,fullDimensions.y) --downsampled image uses fullSized rect | |
blurMeshes.vertical.shader = shader(gaussianShader.vert[2],gaussianShader.frag) | |
blurMeshes.vertical.shader.am = aspect | |
--draw the blurred horizontal mesh to the vertical mesh texture | |
setContext(blurMeshes.vertical.texture) | |
blurMeshes.horizontal:draw() --pass one | |
setContext() | |
--draw the double-blurred vertical mesh to a new image | |
local renderTarget = image(imageToBlur.width,imageToBlur.height) | |
setContext(renderTarget) | |
blurMeshes.vertical:draw() --pass two | |
setContext() | |
--send back the blurred image | |
return renderTarget | |
end | |
gaussianShader = { | |
vert = { -- horizontal pass vertex shader | |
[[ | |
uniform mat4 modelViewProjection; | |
uniform vec2 am; // ammount of blur, inverse aspect ratio (so that oblong shapes still produce round blur) | |
attribute vec4 position; | |
attribute vec2 texCoord; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_Position = modelViewProjection * position; | |
vTexCoord = texCoord; | |
v_blurTexCoords[ 0] = vTexCoord + vec2(-0.028 * am.x, 0.0); | |
v_blurTexCoords[ 1] = vTexCoord + vec2(-0.024 * am.x, 0.0); | |
v_blurTexCoords[ 2] = vTexCoord + vec2(-0.020 * am.x, 0.0); | |
v_blurTexCoords[ 3] = vTexCoord + vec2(-0.016 * am.x, 0.0); | |
v_blurTexCoords[ 4] = vTexCoord + vec2(-0.012 * am.x, 0.0); | |
v_blurTexCoords[ 5] = vTexCoord + vec2(-0.008 * am.x, 0.0); | |
v_blurTexCoords[ 6] = vTexCoord + vec2(-0.004 * am.x, 0.0); | |
v_blurTexCoords[ 7] = vTexCoord + vec2( 0.004 * am.x, 0.0); | |
v_blurTexCoords[ 8] = vTexCoord + vec2( 0.008 * am.x, 0.0); | |
v_blurTexCoords[ 9] = vTexCoord + vec2( 0.012 * am.x, 0.0); | |
v_blurTexCoords[10] = vTexCoord + vec2( 0.016 * am.x, 0.0); | |
v_blurTexCoords[11] = vTexCoord + vec2( 0.020 * am.x, 0.0); | |
v_blurTexCoords[12] = vTexCoord + vec2( 0.024 * am.x, 0.0); | |
v_blurTexCoords[13] = vTexCoord + vec2( 0.028 * am.x, 0.0); | |
}]], | |
-- vertical pass vertex shader | |
[[ | |
uniform mat4 modelViewProjection; | |
uniform vec2 am; // ammount of blur | |
attribute vec4 position; | |
attribute vec2 texCoord; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_Position = modelViewProjection * position; | |
vTexCoord = texCoord; | |
v_blurTexCoords[ 0] = vTexCoord + vec2(0.0, -0.028 * am.y); | |
v_blurTexCoords[ 1] = vTexCoord + vec2(0.0, -0.024 * am.y); | |
v_blurTexCoords[ 2] = vTexCoord + vec2(0.0, -0.020 * am.y); | |
v_blurTexCoords[ 3] = vTexCoord + vec2(0.0, -0.016 * am.y); | |
v_blurTexCoords[ 4] = vTexCoord + vec2(0.0, -0.012 * am.y); | |
v_blurTexCoords[ 5] = vTexCoord + vec2(0.0, -0.008 * am.y); | |
v_blurTexCoords[ 6] = vTexCoord + vec2(0.0, -0.004 * am.y); | |
v_blurTexCoords[ 7] = vTexCoord + vec2(0.0, 0.004 * am.y); | |
v_blurTexCoords[ 8] = vTexCoord + vec2(0.0, 0.008 * am.y); | |
v_blurTexCoords[ 9] = vTexCoord + vec2(0.0, 0.012 * am.y); | |
v_blurTexCoords[10] = vTexCoord + vec2(0.0, 0.016 * am.y); | |
v_blurTexCoords[11] = vTexCoord + vec2(0.0, 0.020 * am.y); | |
v_blurTexCoords[12] = vTexCoord + vec2(0.0, 0.024 * am.y); | |
v_blurTexCoords[13] = vTexCoord + vec2(0.0, 0.028 * am.y); | |
}]]}, | |
--fragment shader | |
frag = [[precision mediump float; | |
uniform lowp sampler2D texture; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_FragColor = vec4(0.0); | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 0])*0.0044299121055113265; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 1])*0.00895781211794; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 2])*0.0215963866053; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 3])*0.0443683338718; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 4])*0.0776744219933; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 5])*0.115876621105; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 6])*0.147308056121; | |
gl_FragColor += texture2D(texture, vTexCoord )*0.159576912161; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 7])*0.147308056121; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 8])*0.115876621105; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 9])*0.0776744219933; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[10])*0.0443683338718; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[11])*0.0215963866053; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[12])*0.00895781211794; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[13])*0.0044299121055113265; | |
}]] | |
} | |
--# blur | |
--[[ | |
Gaussian = {} --a component for nice effects like shadows and blur | |
--Gaussian blur | |
--adapted by Yojimbo2000 from http://xissburg.com/faster-gaussian-blur-in-glsl/ | |
function smoothstep(t,a,b) | |
local a,b = a or 0,b or 1 | |
local t = math.min(1,math.max(0,(t-a)/(b-a))) | |
return t * t * (3 - 2 * t) | |
end | |
function Gaussian.setImage(givenImage) | |
local p = givenImage | |
local hardCodedFalloff = 1 | |
local ww,hh = p.width * hardCodedFalloff, p.height * hardCodedFalloff -- shadow image needs to be larger than the element casting the shadow, in order to capture the blurry shadow falloff | |
-- self.ww, self.hh = ww,hh | |
local d = math.max(ww, hh) | |
local blurRad = smoothstep(d, math.max(WIDTH, HEIGHT)*1.5, 60) * 1.5 | |
local aspect = vec2(d/ww, d/hh) * blurRad --work out the inverse aspect ratio | |
-- print(p.title, "aspect", aspect) | |
local downSample = 0.25 | |
local dimensions = vec2(ww, hh) * downSample --down sampled | |
local blurTex = {} --images | |
local blurMesh = {} --meshes | |
for i=1,2 do --2 passes, one for horizontal, one vertical | |
blurTex[i]=image(dimensions.x, dimensions.y) | |
local m = mesh() | |
m.texture=blurTex[i] | |
m:addRect(dimensions.x/2, dimensions.y/2,dimensions.x, dimensions.y) | |
m.shader=shader(Gaussian.shader.vert[i], Gaussian.shader.frag) | |
-- blurred[i].shader.am = falloff | |
m.shader.am = aspect | |
blurMesh[i] = m | |
end | |
local imgOut = image(dimensions.x, dimensions.y) | |
pushStyle() | |
pushMatrix() | |
setContext(blurTex[1]) | |
scale(downSample) | |
--self:drawImage() | |
--from blur | |
--function Blur:drawImage() | |
pushMatrix() | |
--translate(-self.parent:left(), -self.parent:bottom()) | |
translate(-200,-10)--??? | |
--Soda.drawing(self.parent) --draw all elements to the blur image, with the parent set as the breakpoint (so that the parent window itself does not show up in the blurred image) | |
popMatrix() | |
--end | |
popMatrix() | |
popStyle() | |
setContext(blurTex[2]) | |
blurMesh[1]:draw() --pass one | |
setContext(imgOut) | |
blurMesh[2]:draw() --pass two, to output | |
setContext() | |
return imgOut | |
end | |
function Gaussian:draw() | |
local p = self.parent | |
self.mesh:setRect(1, p.x + self.off, p.y - self.off, self.ww, self.hh) | |
self.mesh:draw() | |
end | |
--------------------------------------------------------------------------- | |
Blur = class(Gaussian) | |
function Blur:init(t) | |
self.parent = t.parent | |
self.falloff = 1 | |
self.off = 0 | |
self:setMesh() | |
-- self.image = image(self.parent.w * 0.25, self.parent.h * 0.25) | |
-- self.draw = self.setMesh -- | |
end | |
function Blur:draw() end | |
function Blur:setMesh() | |
-- self.draw = null | |
self.image = self:setImage() | |
self.parent.shapeArgs.tex = self.image | |
self.parent.shapeArgs.resetTex = self.image | |
end | |
function Blur:drawImage() | |
pushMatrix() | |
translate(-self.parent:left(), -self.parent:bottom()) | |
Soda.drawing(self.parent) --draw all elements to the blur image, with the parent set as the breakpoint (so that the parent window itself does not show up in the blurred image) | |
popMatrix() | |
end | |
--------------------------------------------------------------------------- | |
Shadow = class(Gaussian) | |
function Shadow:init(t) | |
self.parent = t.parent | |
self.falloff = 1.3 | |
self.off = math.max(2, self.parent.w * 0.015, self.parent.h * 0.015) | |
-- print(self.parent.title, "offset", self.off) | |
self.mesh = mesh() | |
self.mesh:addRect(0,0,0,0) | |
self:setMesh() | |
end | |
function Shadow:setMesh() | |
self.mesh.texture = self:setImage() | |
-- self.mesh:setRect(1, self.parent.x + self.off,self.parent.y - self.off,self.ww, self.hh) --nb, rect is set in draw function, for animation purposes | |
end | |
function Shadow:drawImage() | |
pushStyle() | |
pushMatrix() | |
translate((self.ww-self.parent.w)*0.45, (self.hh-self.parent.h)*0.45) | |
self.parent:drawShape({Soda.style.shadow}) | |
popMatrix() | |
popStyle() | |
end | |
Gaussian.shader = { | |
vert = { -- horizontal pass vertex shader | |
[[ | |
uniform mat4 modelViewProjection; | |
uniform vec2 am; // ammount of blur, inverse aspect ratio (so that oblong shapes still produce round blur) | |
attribute vec4 position; | |
attribute vec2 texCoord; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_Position = modelViewProjection * position; | |
vTexCoord = texCoord; | |
v_blurTexCoords[ 0] = vTexCoord + vec2(-0.028 * am.x, 0.0); | |
v_blurTexCoords[ 1] = vTexCoord + vec2(-0.024 * am.x, 0.0); | |
v_blurTexCoords[ 2] = vTexCoord + vec2(-0.020 * am.x, 0.0); | |
v_blurTexCoords[ 3] = vTexCoord + vec2(-0.016 * am.x, 0.0); | |
v_blurTexCoords[ 4] = vTexCoord + vec2(-0.012 * am.x, 0.0); | |
v_blurTexCoords[ 5] = vTexCoord + vec2(-0.008 * am.x, 0.0); | |
v_blurTexCoords[ 6] = vTexCoord + vec2(-0.004 * am.x, 0.0); | |
v_blurTexCoords[ 7] = vTexCoord + vec2( 0.004 * am.x, 0.0); | |
v_blurTexCoords[ 8] = vTexCoord + vec2( 0.008 * am.x, 0.0); | |
v_blurTexCoords[ 9] = vTexCoord + vec2( 0.012 * am.x, 0.0); | |
v_blurTexCoords[10] = vTexCoord + vec2( 0.016 * am.x, 0.0); | |
v_blurTexCoords[11] = vTexCoord + vec2( 0.020 * am.x, 0.0); | |
v_blurTexCoords[12] = vTexCoord + vec2( 0.024 * am.x, 0.0); | |
v_blurTexCoords[13] = vTexCoord + vec2( 0.028 * am.x, 0.0); | |
}]] | |
--[[ | |
, | |
-- vertical pass vertex shader | |
[[ | |
uniform mat4 modelViewProjection; | |
uniform vec2 am; // ammount of blur | |
attribute vec4 position; | |
attribute vec2 texCoord; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_Position = modelViewProjection * position; | |
vTexCoord = texCoord; | |
v_blurTexCoords[ 0] = vTexCoord + vec2(0.0, -0.028 * am.y); | |
v_blurTexCoords[ 1] = vTexCoord + vec2(0.0, -0.024 * am.y); | |
v_blurTexCoords[ 2] = vTexCoord + vec2(0.0, -0.020 * am.y); | |
v_blurTexCoords[ 3] = vTexCoord + vec2(0.0, -0.016 * am.y); | |
v_blurTexCoords[ 4] = vTexCoord + vec2(0.0, -0.012 * am.y); | |
v_blurTexCoords[ 5] = vTexCoord + vec2(0.0, -0.008 * am.y); | |
v_blurTexCoords[ 6] = vTexCoord + vec2(0.0, -0.004 * am.y); | |
v_blurTexCoords[ 7] = vTexCoord + vec2(0.0, 0.004 * am.y); | |
v_blurTexCoords[ 8] = vTexCoord + vec2(0.0, 0.008 * am.y); | |
v_blurTexCoords[ 9] = vTexCoord + vec2(0.0, 0.012 * am.y); | |
v_blurTexCoords[10] = vTexCoord + vec2(0.0, 0.016 * am.y); | |
v_blurTexCoords[11] = vTexCoord + vec2(0.0, 0.020 * am.y); | |
v_blurTexCoords[12] = vTexCoord + vec2(0.0, 0.024 * am.y); | |
v_blurTexCoords[13] = vTexCoord + vec2(0.0, 0.028 * am.y); | |
}]] | |
--[[ | |
}, | |
--fragment shader | |
frag = [[precision mediump float; | |
uniform lowp sampler2D texture; | |
varying vec2 vTexCoord; | |
varying vec2 v_blurTexCoords[14]; | |
void main() | |
{ | |
gl_FragColor = vec4(0.0); | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 0])*0.0044299121055113265; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 1])*0.00895781211794; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 2])*0.0215963866053; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 3])*0.0443683338718; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 4])*0.0776744219933; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 5])*0.115876621105; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 6])*0.147308056121; | |
gl_FragColor += texture2D(texture, vTexCoord )*0.159576912161; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 7])*0.147308056121; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 8])*0.115876621105; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[ 9])*0.0776744219933; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[10])*0.0443683338718; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[11])*0.0215963866053; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[12])*0.00895781211794; | |
gl_FragColor += texture2D(texture, v_blurTexCoords[13])*0.0044299121055113265; | |
}]] | |
--[[ | |
} | |
]] | |
--# Utilities | |
-- setReporting &c handles control whether or not report(string) commands get printed | |
function setReporting(shouldReport) | |
if shouldReport then | |
reporting = true | |
else | |
reporting = false | |
end | |
end | |
function report(x) | |
if reporting == nil then | |
print("reporting not set") | |
elseif reporting == false then | |
return | |
else | |
print(x) | |
end | |
end | |
--lets just consolidate pushStyle() and popStyle() here | |
function styleSafe(functionToCall) | |
pushStyle() | |
functionToCall() | |
popStyle() | |
end | |
--need an easy boolean-to-string thingy | |
function boolToString(boolean) | |
if boolean == true then | |
return "TRUE" | |
elseif boolean == false then | |
return "FALSE" | |
else | |
return "NOT A BOOLEAN" | |
end | |
end | |
--tintScreen applies given color as semitransparent tint to a CargoBot full-screen sprite | |
function tintScreen(tintColor) | |
--enforce a minimum opacity of 191 | |
if tintColor.a > 191 then | |
tintColor.a = 191 | |
end | |
tint(tintColor) | |
sprite("Cargo Bot:Game Lower BG", WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) | |
noTint() | |
end | |
--# uiPieceTables | |
uiPieceHandler.buttons['to editable mode'] = | |
{x = 811.5, y = 702.5, | |
width=300, height=55, | |
fontColor=color(109.0,223.0,112.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['sample game start screen'] = | |
{x = 811.5, y = 429.0, | |
width=400, height=300, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['you won sample game'] = | |
{x = 811.5, y = 429.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['welcome'] = | |
{x = 502.5, y = 384.5, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['lose sample game'] = | |
{x = 811.5, y = 157.0, | |
width=400, height=55, | |
fontColor=color(160.0,173.0,223.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['to fixed mode'] = | |
{x = 811.5, y = 702.5, | |
width=300, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['reset sample game'] = | |
{x = 811.5, y = 232.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['you lost sample game'] = | |
{x = 811.5, y = 429.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['win sample game'] = | |
{x = 811.5, y = 232.0, | |
width=400, height=55, | |
fontColor=color(160.0,173.0,223.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
--# defaults | |
--[[ paste imto uiPieceTables to reset buttons if you've messed with em | |
uiPieceHandler.buttons['to editable mode'] = | |
{x = 811.5, y = 702.5, | |
width=300, height=55, | |
fontColor=color(109.0,223.0,112.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['sample game start screen'] = | |
{x = 811.5, y = 429.0, | |
width=400, height=300, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['you won sample game'] = | |
{x = 811.5, y = 429.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['welcome'] = | |
{x = 502.5, y = 384.5, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['lose sample game'] = | |
{x = 811.5, y = 157.0, | |
width=400, height=55, | |
fontColor=color(160.0,173.0,223.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['to fixed mode'] = | |
{x = 811.5, y = 702.5, | |
width=300, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['reset sample game'] = | |
{x = 811.5, y = 232.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['you lost sample game'] = | |
{x = 811.5, y = 429.0, | |
width=160, height=55, | |
fontColor=color(253.0,253.0,253.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
uiPieceHandler.buttons['win sample game'] = | |
{x = 811.5, y = 232.0, | |
width=400, height=55, | |
fontColor=color(160.0,173.0,223.0,255.0), | |
action = uiPieceHandler.defaultButtonAction} | |
]] | |
--# Tests | |
function tests() | |
--testTouch and a function to reset it | |
local testTouch = {} | |
local resetTestTouch = function() | |
testTouch = {} | |
end | |
--when in playModeUI, and a touch on the editable mode button is of state BEGIN | |
showPlayModeUI() | |
local detectedTestTouch, correctButtonActivated = false, false | |
local editModeButtonName = "to editable mode" | |
local buttonTable = uiPieceHandler.buttons["to editable mode"] | |
local testTouch = {x=buttonTable.x, y=buttonTable.y} | |
testTouch.state = BEGAN | |
--then if it is passed to touchIsInside | |
detectedTestTouch = uiPieceHandler.touchIsInside(editModeButtonName, testTouch) | |
--result is a true value for detectedTestTouch | |
print("detectedTestTouch: "..boolToString(detectedTestTouch)) | |
--and then if it is passed to evaluateTouchFor | |
uiPieceHandler.evaluateTouchFor(editModeButtonName, testTouch) | |
--result is the correct activatedButton | |
correctButtonActivated = activatedButton == editModeButtonName | |
print("correctButtonActivated: "..boolToString(correctButtonActivated)) | |
--and when the touch moves over a different object | |
local playModeButtonName = "to fixed mode" | |
local playModeButton = uiPieceHandler.buttons[playModeButtonName] | |
testTouch.x, testTouch.y = playModeButton.x, playModeButton.y | |
testTouch.state = MOVING | |
--then if it is passed to evaluateTouchFor | |
uiPieceHandler.evaluateTouchFor(playModeButtonName, testTouch) | |
--result is the first object remaining the activatedButton | |
correctButtonActivated = activatedButton == editModeButtonName | |
print("touching second object preserves activatedButton: ".. | |
boolToString(correctButtonActivated)) | |
--and when the touch ends outside the button | |
local outsideOffsetX, outsideOffsetY = buttonTable.width, buttonTable.height | |
local startingX, startingY = buttonTable.x, buttonTable.y | |
testTouch.x = buttonTable.x+outsideOffsetX | |
testTouch.y = playModeButton.y+outsideOffsetY | |
testTouch.state = ENDED | |
--then if it is passed to evaluateTouchFor | |
uiPieceHandler.evaluateTouchFor(editModeButtonName, testTouch) | |
--result is that activatedButton is now nil | |
local activatedButtonIsNil = activatedButton == nil | |
print("touch ending outside button erases activatedButton: ".. | |
boolToString(activatedButtonIsNil)) | |
--and result is that the button has NOT moved | |
local buttonInRightPlace = buttonTable.x == startingX and buttonTable.y == startingY | |
print("button did not move when it shouldn't: "..boolToString(buttonInRightPlace)) | |
--and result is button action NOT performed (action = setting editable mode) | |
local actionPerformed = currentUI == editModeUI | |
print("action not performed when it shouldn't: ".. | |
boolToString(actionPerformed == false)) | |
--when playModeUI & NOT buttons_are_draggable & touch starts on editable mode button | |
showPlayModeUI() | |
resetTestTouch() | |
buttons_are_draggable = false | |
testTouch.state = BEGAN | |
testTouch.x, testTouch.y = buttonTable.x, buttonTable.y | |
uiPieceHandler.evaluateTouchFor(editModeButtonName, testTouch) | |
--then if it also ends on that button | |
testTouch.state = ENDED | |
uiPieceHandler.evaluateTouchFor(editModeButtonName, testTouch) | |
--result is that activatedButton is now nil | |
activatedButtonIsNil = activatedButton == nil | |
print("touch ending inside button erases activatedButton: ".. | |
boolToString(activatedButtonIsNil)) | |
--and result is UI is in editable mode | |
actionPerformed = currentUI == editModeUI | |
print("action performed when it should in fixed mode: ".. | |
boolToString(actionPerformed)) | |
--and when buttons are draggable and a touch starts on the fixed mode button | |
resetTestTouch() | |
showEditModeUI() | |
testTouch = {x=buttonTable.x, y=buttonTable.y} | |
testTouch.state = BEGAN | |
uiPieceHandler.evaluateTouchFor(playModeButtonName, testTouch) | |
--then if the touch moves | |
testTouch.x = playModeButton.x-outsideOffsetX | |
testTouch.y = playModeButton.y-outsideOffsetY | |
testTouch.state = MOVING | |
uiPieceHandler.evaluateTouchFor(playModeButtonName, testTouch) | |
--result is that button has moved along with it | |
local rightX = playModeButton.x == testTouch.x | |
local rightY = playModeButton.y == testTouch.y | |
buttonInRightPlace = rightX and rightY | |
print("button moved when it should for MOVING state: ".. | |
boolToString(buttonInRightPlace)) | |
--then if the touch moves more and ends | |
startingX, startingY = playModeButton.x, playModeButton.y | |
testTouch.x, testTouch.y = testTouch.x+outsideOffsetX, testTouch.y+outsideOffsetY | |
testTouch.state = ENDED | |
uiPieceHandler.evaluateTouchFor(playModeButtonName, testTouch) | |
--result is that button has moved along with it | |
buttonInRightPlace = playModeButton.x == startingX and playModeButton.y == startingY | |
print("button didn't move for ENDED state: "..boolToString(buttonInRightPlace)) | |
--at the end of tests, reset all the default button values | |
defineMainButtons() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment