Skip to content

Instantly share code, notes, and snippets.

@The0x539
Last active January 2, 2017 03:50
Show Gist options
  • Save The0x539/d8b61708986f000976e56c31ce2a4362 to your computer and use it in GitHub Desktop.
Save The0x539/d8b61708986f000976e56c31ce2a4362 to your computer and use it in GitHub Desktop.
A one-by-one layer toggle library for SMBX
local poof = {}
--Version 0.2a
--By The0x539
--To poof a layer, use poof.startPoof(layer, frames, freeze) in your LunaLua file after loading the API.
--layer specifies which layer gets poof'd
--frames specifies the number of frames (give or take one or two, somebody teach The0x539 some computer science) between poofing each thing.
--freeze specifies whether time should be frozen starting when the camera moves, and ending when it's back at the player.
--If freeze == true, time is frozen. If freeze == false, player input is locked instead.
--Moving NPCs work much better when freeze == true. Results not guaranteed for moving NPCs with freeze == false.
--Should this library get fancy particles, they will work much better with freeze == false.
--If the layer's center is such that the camera would go past where it normally would, the background won't extend properly. This is just a SMBX thing.
--Multiplayer is not currently officially supported due to requiring additional camera work.
local workingLayer = nil
local timer = 0
local defaultInterval = 15
local interval = nil
local poofOut = nil
local queue = nil
local goalX = nil
local goalY = nil
local camera = Camera.get()[1]
local currentX = nil
local currentY = nil
local lockInput = false
poof.status = "idle"
function poof.onInitAPI()
registerEvent(poof, "onDraw", "handleWorld")
registerEvent(poof, "onCameraUpdate", "handleCamera")
registerEvent(poof, "onInputUpdate", "handleInput")
end
local function thingsIn(layer)
--returns all the blocks, BGOs, and NPCs in a layer, in whatever order SMBX provides them, concatenated not collated
local contents = {}
local function insert(items)
for k,item in pairs(items) do
if tostring(item.layerName) == layer then
table.insert(contents,item)
end
end
end
insert(Block.get())
insert(BGO.get())
insert(NPC.get())
return contents
end
local function bottomLeft(items)
--Gives the coordinates of the bottomleftmost point in a group of things
local x = math.huge
local y = -math.huge
for k,item in pairs(items) do
if item.x < x then x = item.x end
if item.y + item.height > y then y = item.y + item.height end
end
return {x,y}
end
local function topRight(items)
--Gives the coordinates of the upperrightmost point in a group of things
local x = -math.huge
local y = math.huge
for k,item in pairs(items) do
if item.x + item.width > x then x = item.x + item.width end
if item.y < y then y = item.y end
end
return {x,y}
end
local function between(a,b,c)
--quick inequality thing for readability in reorder
if a <= b and b <= c then return true else return false end
end
local function reorder(items)
--A bit of a misnomer, but gives, in rightward-then-upward order, the contents of the working layer in this context.
local foo = {}
for y = bottomLeft(items)[2], topRight(items)[2], -32 do
for x = bottomLeft(items)[1], topRight(items)[1], 32 do
local function conditionalInsert(group)
for k,item in pairs(group.getIntersecting(x,y-32,x+32,y)) do
if tostring(item.layerName) == workingLayer and between(x,item.x,x+32) and between(y-32,item.y+item.height,y) then
table.insert(foo,item)
end
end
end
conditionalInsert(Block)
conditionalInsert(BGO)
conditionalInsert(NPC)
end
end
return foo
end
function poof.startPoof(layer, frames, freeze)
--Kicks things into gear, filling up the item queue and telling the camera where to go
if Layer.get(layer) and queue == nil then
freeze = freeze or true
interval = frames or defaultInterval
workingLayer=layer
if freeze then
Misc.pause()
else
lockInput = true
end
poofOut = not(Layer.get(layer).isHidden)
queue = reorder(thingsIn(layer))
goalX = math.floor((bottomLeft(queue)[1]+topRight(queue)[1])/2) - 400
goalY = math.floor((bottomLeft(queue)[2]+topRight(queue)[2])/2) - 300
poof.status = "moveTo"
end
end
function poof.handleWorld()
--Makes blocks appear/vanish and pauses/unpauses time as appropriate
if poof.status == "poofing" and type(queue) == "table" then
if timer < interval then timer = timer + 1 else
if table.getn(queue) > 0 then
if queue[1].isHidden ~= poofOut then
queue[1].isHidden = poofOut
timer = 0
Audio.playSFX(27)
end
table.remove(queue,1)
elseif Layer.get(workingLayer).isHidden ~= poofOut then
Layer.get(workingLayer):toggle(true)
else
queue = nil
poof.status = "moveBack"
poofOut = nil
interval = nil
end
end
elseif poof.status == "idle" then
if Misc.isPausedByLua() then Misc.unpause()
elseif lockInput then lockInput = false end
end
end
function poof.handleCamera()
--Moves the camera and updates its status as appropriate
if poof.status == "moveTo" then
currentX = math.floor(camera.x)
currentY = math.floor(camera.y)
poof.status = "moving"
elseif poof.status == "moveBack" then
goalX = math.floor(camera.x)
goalY = math.floor(camera.y)
poof.status = "moving"
end
for i = 0,5 do
if poof.status == "moving" then
if currentX < goalX then currentX = currentX + 1
elseif currentX > goalX then currentX = currentX - 1 end
if currentY < goalY then currentY = currentY + 1
elseif currentY > goalY then currentY = currentY - 1 end
if currentX == goalX and currentY == goalY then
if queue then poof.status = "poofing" else poof.status = "idle" end
break
end
end
end
if poof.status ~= "idle" then
camera.x = currentX
camera.y = currentY
end
end
function poof.handleInput()
--Locks all player1 input as appropriate
if lockInput then
player.upKeyPressing = false
player.downKeyPressing = false
player.leftKeyPressing = false
player.rightKeyPressing = false
player.jumpKeyPressing = false
player.altJumpKeyPressing = false
player.runKeyPressing = false
player.altRunKeyPressing = false
player.dropItemKeyPressing = false
player.pauseKeyPressing = false
end
end
return poof
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment