Skip to content

Instantly share code, notes, and snippets.

@juaxix
Created February 2, 2012 20:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juaxix/1725481 to your computer and use it in GitHub Desktop.
Save juaxix/1725481 to your computer and use it in GitHub Desktop.
Magic Puzzle Bubble in Lua by juaxix ( xixgames )
Bubble = class()
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11
-- http://xixgames.com
-- video: http://www.youtube.com/watch?v=rD0fQVSj_7w
-- Bubble states
BUBBLE_EMPTY    = 0
BUBBLE_CREATED  = 1
BUBBLE_FLYING   = 2
BUBBLE_ATTACHED = 3
BUBBLE_EXPLODING= 4
BUBBLE_DESTROYED= 5
BUBBLE_FALLING  = 6
-- Bubble colors
BUBBLE_RED    = 1
BUBBLE_YELLOW = 2
BUBBLE_GREEN  = 3
BUBBLE_BLUE   = 4
BUBBLE_ORANGE = 5
BUBBLE_PURPLE = 6
BUBBLE_GRAY   = 7
-- Bubble modes 
BUBBLE_NORMAL = 1
BUBBLE_LOVE   = 2
BUBBLE_MAGIC  = 3
-- Bubble positions
BUBBLE_UP_LEFT   = 1
BUBBLE_UP_RIGHT  = 2
BUBBLE_LEFT      = 3
BUBBLE_RIGHT     = 4
BUBBLE_DOWN_LEFT = 5
BUBBLE_DOWN_RIGHT= 6
function Bubble:init(position,size,mycolor)
    self.position = position
    self.size     = size
    self.explored = false
    self.connected= false -- new algorithm 1/2/2012
    self.state    = BUBBLE_CREATED
    if mycolor == nil then
       local n = (#currentColors)
       local c = 1
       if n>0 then
         c = math.random(1,n)
         mycolor = currentColors[c]
       end
       
    end
    self.bcolor   = self:getColor(mycolor)  --self:getBorderColor(mycolor)
    self.color    = color(255,255,255,255) --self:getColor(mycolor)  
    self.mycolor  = mycolor
    self.tint     = self.bcolor --color(self.color.r,self.color.g,self.color.b,166)
    self.model    = 1--math.random(1,3)
    self.iposition= vec2(0,0)
    if self.model == BUBBLE_NORMAL then
        self.image = "Small World:Mote Sad"
        self.isizex= self.size * 2
        self.isizey= self.size * 2
    elseif self.model == BUBBLE_LOVE then
        self.image = "Small World:Mote Happy"
        self.isizex= self.size * 1.6
        self.isizey= self.size * 1.6
    else
        self.image = "Planet Cute:Star"
        self.isizex= 50.5
        self.isizey= 85.5
        self.iposition.y = 7
    end
end
function Bubble:getBorderColor(i)
    if i == BUBBLE_RED then
        return color(161, 24, 27, 255)
    elseif i == BUBBLE_YELLOW then
        return color(175, 175, 22, 255)
    elseif i == BUBBLE_GREEN then
        return color(60, 143, 28, 255)
    elseif i == BUBBLE_BLUE then
        return color(23, 125, 170, 255)
    elseif i == BUBBLE_ORANGE then
        return color(195, 121, 17, 255)
    elseif i == BUBBLE_GRAY then
        return color(45, 43, 97, 255)
    else
        return color(126, 27, 148, 255)
    end
end
function Bubble:getColor(i)
    if i == BUBBLE_RED then
        return color(255, 0, 0, 255)
    elseif i == BUBBLE_YELLOW then
        return color(203, 203, 75, 255)
    elseif i == BUBBLE_GREEN then
        return color(67, 213, 12, 255)
    elseif i == BUBBLE_BLUE then
        return color(4, 21, 241, 255)
    elseif i == BUBBLE_ORANGE then
        return color(255, 148, 0, 255)
    elseif i == BUBBLE_GRAY then
        return color(76, 83, 94, 255)
    else
        return color(208, 0, 255, 255)
    end
end
function Bubble:draw()
    if self.state ==nil or self.state == BUBBLE_EMPTY or self.state == BUBBLE_DESTROYED then 
        return 
    end
    if self.state == BUBBLE_EXPLODING then
        sprite("Tyrian Remastered:Explosion Huge",
            self.position.x,self.position.y,self.size,self.size 
        )
    elseif self.state == BUBBLE_FALLING then
        pushMatrix()
        translate(self.position.x,self.position.y)
        rotate(180)
        tint(self.tint)
        scale(1.5)
        sprite("Tyrian Remastered:Space Bug Eggs",0,0,self.size/2,self.size/2)
        popMatrix()
    else
        pushMatrix()
        --stroke(self.bcolor)
        --strokeWidth(3)
        fill(self.color)
        ellipse(self.position.x,self.position.y,self.size,self.size)
        tint(self.tint)
        
        sprite(self.image,self.iposition.x + self.position.x, 
            self.iposition.y + self.position.y, self.isizex,self.isizey)
        
        popMatrix()
    end
end
FontAnim = class()
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11
-- http://xixgames.com
function FontAnim:init(args)
    self.text = args.text
    self.x    = args.x
    self.y    = args.y
    self.time = 3
    self.face = args.face or "Futura-CondensedExtraBold"
end
function FontAnim:draw()
    self.time = self.time - 1/11
    if self.time > 0 then
        self.y = self.y + 1
        text(self.text,self.x, self.y)
    end
end
-- Main
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11
-- http://xixgames.com
levels = {
-- remember: axis are rotated 45 degrees to
-- represent the bubbles matrix
  { -- Level 1 
    -- row 1
    {BUBBLE_RED,BUBBLE_RED,BUBBLE_YELLOW,BUBBLE_YELLOW,BUBBLE_BLUE,BUBBLE_BLUE,BUBBLE_GREEN,
       BUBBLE_GREEN},
    -- row 2
    {BUBBLE_RED,BUBBLE_RED,BUBBLE_YELLOW,BUBBLE_YELLOW,BUBBLE_BLUE,BUBBLE_BLUE,BUBBLE_GREEN},
    -- row 3
    {BUBBLE_BLUE,BUBBLE_BLUE,BUBBLE_GREEN,BUBBLE_GREEN,BUBBLE_RED,BUBBLE_RED,BUBBLE_YELLOW,
       BUBBLE_YELLOW},
    -- row 4
   {BUBBLE_BLUE,BUBBLE_BLUE,BUBBLE_GREEN,BUBBLE_GREEN,BUBBLE_RED,BUBBLE_RED,BUBBLE_YELLOW}
  },
  { -- Level 2
    {nil,nil,nil,BUBBLE_GRAY,BUBBLE_GRAY},
    {nil,nil,nil,BUBBLE_BLUE},
    {nil,nil,nil,BUBBLE_GREEN},
    {nil,nil,nil,BUBBLE_BLUE},
    {nil,nil,nil,BUBBLE_PURPLE},
    {nil,nil,nil,BUBBLE_GREEN},
    {nil,nil,nil,BUBBLE_BLUE}
  },
  { -- Level 3
    {BUBBLE_GREEN, nil,nil,nil,nil,nil,nil,BUBBLE_GREEN},
    {BUBBLE_RED, BUBBLE_GREEN, BUBBLE_BLUE, BUBBLE_YELLOW, BUBBLE_RED, BUBBLE_GREEN,
         BUBBLE_BLUE},
    {BUBBLE_YELLOW,nil,nil,nil,nil,nil,nil,BUBBLE_YELLOW},
    {BUBBLE_BLUE,BUBBLE_YELLOW, BUBBLE_RED,BUBBLE_GREEN,BUBBLE_BLUE,BUBBLE_YELLOW, 
        BUBBLE_RED},
    {nil,nil,nil,BUBBLE_RED},
    {nil,nil,nil,BUBBLE_GREEN},
    {nil,nil,nil,BUBBLE_RED}
  },
  {-- Level 4
    {nil,BUBBLE_GRAY,BUBBLE_GRAY,nil,nil,BUBBLE_BLUE,BUBBLE_BLUE},
    {nil,BUBBLE_YELLOW,nil,nil,BUBBLE_PURPLE},
    {nil,BUBBLE_BLUE,nil,nil,BUBBLE_GREEN},
    {nil,BUBBLE_YELLOW,nil,nil,BUBBLE_GREEN},
    {nil,BUBBLE_YELLOW,nil,nil,BUBBLE_GREEN},
    {nil,BUBBLE_RED,nil,nil,BUBBLE_YELLOW},
    {nil,BUBBLE_YELLOW,nil,nil,BUBBLE_BLUE},
    {nil,BUBBLE_RED,nil,nil,BUBBLE_GREEN}
  },
  { -- Level 5
    {nil, BUBBLE_YELLOW,nil,BUBBLE_YELLOW,nil,BUBBLE_YELLOW,nil,BUBBLE_PURPLE},
    {BUBBLE_GREEN, nil, BUBBLE_PURPLE, nil, BUBBLE_BLUE, nil, BUBBLE_RED },
    {BUBBLE_RED, nil, BUBBLE_BLUE, nil, BUBBLE_YELLOW, nil, BUBBLE_PURPLE},
    {nil,BUBBLE_GREEN,nil,BUBBLE_YELLOW, nil, BUBBLE_BLUE},
    {nil,BUBBLE_RED, nil,BUBBLE_PURPLE, nil,BUBBLE_ORANGE},
    {BUBBLE_BLUE, nil, BUBBLE_GREEN, nil, BUBBLE_GREEN},
    {nil,nil,BUBBLE_PURPLE, nil, BUBBLE_YELLOW},
    {nil,nil,nil,BUBBLE_RED}
  },
  { -- Level 6
    {BUBBLE_RED,BUBBLE_RED,BUBBLE_GREEN,BUBBLE_RED,BUBBLE_YELLOW,BUBBLE_RED,BUBBLE_PURPLE,
        BUBBLE_GREEN},
    {BUBBLE_GREEN, nil,BUBBLE_PURPLE, nil,BUBBLE_RED, nil, BUBBLE_RED},
    {nil,BUBBLE_PURPLE, BUBBLE_BLUE,BUBBLE_RED,BUBBLE_BLUE,BUBBLE_YELLOW,BUBBLE_GRAY},
    {nil,BUBBLE_GREEN,nil,BUBBLE_YELLOW,nil,BUBBLE_RED},
    {nil,BUBBLE_RED,BUBBLE_GRAY,BUBBLE_YELLOW,BUBBLE_YELLOW,BUBBLE_YELLOW,BUBBLE_RED},
    {BUBBLE_GRAY,nil,BUBBLE_BLUE,nil,BUBBLE_RED,nil,BUBBLE_RED},
    {BUBBLE_GREEN,BUBBLE_GRAY,BUBBLE_YELLOW,BUBBLE_YELLOW,BUBBLE_GREEN,BUBBLE_BLUE,
        BUBBLE_GREEN,BUBBLE_PURPLE}
  },
 { -- Level 7
    {nil,nil,nil,BUBBLE_GREEN,BUBBLE_YELLOW},
    {nil,nil,BUBBLE_GREEN,BUBBLE_YELLOW,BUBBLE_GREEN},
    {nil,nil,nil,BUBBLE_BLUE,BUBBLE_YELLOW},
    {nil,BUBBLE_PURPLE,BUBBLE_YELLOW,nil,BUBBLE_ORANGE,BUBBLE_YELLOW},
    {nil,BUBBLE_BLUE,BUBBLE_ORANGE,BUBBLE_ORANGE,BUBBLE_BLUE,BUBBLE_PURPLE,BUBBLE_PURPLE},
    {nil,BUBBLE_BLUE,nil,nil,nil,BUBBLE_BLUE}
 },
 { -- Level 8
    {BUBBLE_RED,BUBBLE_GREEN,BUBBLE_BLUE,BUBBLE_YELLOW,BUBBLE_PURPLE,BUBBLE_GRAY,BUBBLE_RED,
        BUBBLE_GREEN},
    {BUBBLE_PURPLE,BUBBLE_GRAY,BUBBLE_RED,BUBBLE_GREEN,BUBBLE_BLUE,BUBBLE_YELLOW,
        BUBBLE_PURPLE},
    {BUBBLE_RED,BUBBLE_GREEN,BUBBLE_BLUE,BUBBLE_YELLOW,BUBBLE_PURPLE,BUBBLE_GRAY,
        BUBBLE_RED,BUBBLE_GREEN},
    {BUBBLE_PURPLE,BUBBLE_GRAY,BUBBLE_RED,BUBBLE_GREEN,BUBBLE_BLUE,BUBBLE_YELLOW,
        BUBBLE_PURPLE}
 }
}
supportedOrientations(LANDSCAPE_LEFT)
function setup()
    watch("score")
    watch("level")
    currentColors = {}
    level         = 1
    score         = 0
    puzzle        = Puzzle(8,12,false)
    
end
-- draw Game
function draw()
    background(0)
    puzzle:draw()
end
function touched(touch)
    puzzle:touched(touch)
end
Puzzle = class()
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11 
-- re-edit on 1/1/12 , 1/2/2012
-- http://xixgames.com
-- states
PUZZLE_PLAYING   = 1
PUZZLE_LOADING   = 2
PUZZLE_NEXT      = 3
PUZZLE_END       = 4
function Puzzle:init(w,h,load_puzzle)
    -- 12 tiles height x 8 tiles width
    self.initWidth = 133
    self.initHeight= 21
    self.tileSize  = 60
    self.width     = w
    self.height    = h
    self.bubbles   = {}
    self.nextBubble= nil
    self.timeNextBu= 0
    self.nextBuFram= 1/DeltaTime
    self.bubbleSize= self.tileSize/2
    self.BubbleCool= 6 -- next bubble cooldown
    self.shootSpeed= 0.66
    self.minGY     = 0.55
    self.animaBubbs= {}
    self.adyAnimBbs= {}
    self.explodeBbs= {}
    self.state     = PUZZLE_LOADING
    currentColors  = {}
    
    -- read current level
    if load_puzzle then
        self:loadPuzzle()
        self.animating = false
        
    else
        self.animating = true
        self.animaTime = 0
        self.state      = PUZZLE_NEXT
    end
   --sprite("Small World:Mote Sad")
    self.st = ScrollingTexture(
        {
         texName = "Small World:Mote Sad",
         width = WIDTH*2 ,
       --  height= 32
        }
    )
    self.rs = RoundScreen(60)
    self.fas= {} -- font anim
    
end
function Puzzle:loadPuzzle()
    print("Loading level "..level)
    self.state     = PUZZLE_LOADING
    -- create the bubbles
    local n = 0
    local k = 0
    local w = self.width
    local h = self.height
    for i=1, h do
     self.bubbles[i] = {}
     n = 0
     if levels[level][i]~=nil then
         n = #(levels[level][i])
     end
     local aux = 0
     if math.fmod(i,2)==0 then
        aux = (self.bubbleSize/2) + 16
     end
     local y = self.initHeight+self.tileSize*self.height - self.bubbleSize - (i-1)*self.tileSize
     for j=1,self.width do
        local c,state = nil,BUBBLE_EMPTY
        if nil==levels[level][i] or nil == levels[level][i][j] then 
            c = nil
            if aux>0 and j==self.width then
                state = nil
            end
        else
            c = levels[level][i][j]
            state = BUBBLE_ATTACHED
            self:addCurrentColor(c,currentColors)
        end
        self.bubbles[i][j] = Bubble(
            vec2(aux+self.initWidth+self.tileSize*j - self.bubbleSize,y),
            self.tileSize, -- bubble radius size
            c --color
         ) 
        self.bubbles[i][j].state = state 
      end 
    end
    sound(SOUND_POWERUP, 33755)
    self.state     = PUZZLE_PLAYING
    print(""..(#currentColors).." colors")
end
function Puzzle:addCurrentColor(c,cc)
    local n = 0 
    if cc ~= nil then
        n = (#cc)
    else
        cc = {}
    end
    for i=1,n do
        if cc[i]==c then
            return
        end
    end
    cc[n+1] = c
end
function Puzzle:launchBubble()
    if self.animating or self.nextBubble == nil then return end
    if self.nextBubble.state == BUBBLE_CREATED then
        self.nextBubble.state = BUBBLE_FLYING
        self.nextBubble.velocity = 29*vec2(Gravity.x,self.shootSpeed*DeltaTime*69)
        sound(SOUND_SHOOT, 16214)
    end
end
function Puzzle:clearBubbleExplorations()
    for i=1,self.height do
     local m = self.width
     
     if math.fmod(i,2) == 0 then
        m = m - 1
     end
     for j=1,m do
        self.bubbles[i][j].explored = false
     end
    end
end
function Puzzle:exploreBubble(i,j)
    local bubble = self.bubbles[i][j]
    if bubble.explored then return 0 end
    local count = 1 -- base case
    local h = self.height
    local w = self.width
    bubble.explored = true
    local a = math.fmod(i,2)==0
   
    
    -- left
    if j>1 and self.bubbles[i][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i][j-1].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i,j-1)
    end
    
    
    if a then --even row
    -- up left
        if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i-1,j)
        end
    -- up right
        if i>1 and j<w and self.bubbles[i-1][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j+1].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i-1,j+1)
        end
    
    -- down left
        if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i-1,j)
        end
    
    -- down right
        if i<h and j<w and self.bubbles[i+1][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j+1].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i+1,j+1)
    
        end
    else -- not even, odd
       -- up left
        if i>1 and j>1 and self.bubbles[i-1][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j-1].mycolor == bubble.mycolor then
            count = count + self:exploreBubble(i-1,j-1)
        end
    -- up right
        if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i-1,j)
        end
    
    -- down left
        if i>1 and j>1 and self.bubbles[i-1][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j-1].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i-1,j-1)
        end
    
    -- down right
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i+1,j)
    
        end
    end
    -- right 
    if j<w and self.bubbles[i][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i][j+1].mycolor == bubble.mycolor then
        count = count + self:exploreBubble(i,j+1)
    end
   
    
    return count
end
-- this function explores all the bubbles
function Puzzle:explorePuzzleBubbles()
    for i=1, self.height do   
     local m  = self.width
     for j=1,m do
        local b = self.bubbles[i][j]
        if not (b.explored) then
            --print("Explore "..i..",",j)
            local explode = self:exploreBubble(i,j)
            if explode>2 then
                --print("in "..i..", "..explode.." of type"..b.mycolor)
                return explode
            end
            
        end
     end
    end
    self:clearBubbleExplorations()
end
function Puzzle:findFallingBubblesFrom(i,j)
    local bubble = self.bubbles[i][j]
    if bubble.explored then return 0 end
    local b = nil -- base case
    local h = self.height
    local w = self.width
    
    table.insert(self.animaBubbs, table.maxn(self.animaBubbs)+1, vec2(i,j))
    bubble.explored = true
    local a = math.fmod(i,2)==0
    if a then
        -- up left
        if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i-1,j)
        end
        -- up right
        if i>1 and j<w and self.bubbles[i-1][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j+1].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i-1,j+1)
        end
        -- down right
        if i<h and j<w and self.bubbles[i+1][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j+1].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i+1,j+1)
        end
        -- down left
        if i<h and j>1 and self.bubbles[i+1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j].mycolor == bubble.mycolor then
         self:findFallingBubblesFrom(i+1,j)
        end
    else
        -- up left
        if i>1 and j>1 and self.bubbles[i-1][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j-1].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i-1,j-1)
        end
        -- up right
        if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i-1][j].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i-1,j)
        end
        -- down right
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j].mycolor == bubble.mycolor then
             self:findFallingBubblesFrom(i+1,j)
        end
        -- down left
        if i<h and j>1 and self.bubbles[i+1][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i+1][j-1].mycolor == bubble.mycolor then
         self:findFallingBubblesFrom(i+1,j-1)
        end
    end
    
    -- left
    if j>1 and self.bubbles[i][j-1].state==BUBBLE_ATTACHED and 
        self.bubbles[i][j-1].mycolor == bubble.mycolor then
         self:findFallingBubblesFrom(i,j-1)
    end
    
    
    -- right 
    if j<w and self.bubbles[i][j+1].state==BUBBLE_ATTACHED and 
        self.bubbles[i][j+1].mycolor == bubble.mycolor then
         self:findFallingBubblesFrom(i,j+1)
    end
    
   
   
end
function Puzzle:attachBubble(i,j,p)
    local w = self.width
    local h = self.height
    local k = 0
    local t = 0
    local a = math.fmod(i,2)==0
    
    if p == BUBBLE_DOWN_LEFT then
        if a and i<h and self.bubbles[i+1][j].state == BUBBLE_EMPTY then
            k = i+1
            t = j
        elseif i<h and j>1 and self.bubbles[i+1][j-1].state == BUBBLE_EMPTY then
            k = i+1
            t = j-1
        else
            print("error positioning down left bbl")
            return self:attachBubble(i,j,BUBBLE_DOWN_RIGHT)
        end
    elseif p == BUBBLE_UP_LEFT then
        if a and i>1 and self.bubbles[i-1][j].state == BUBBLE_EMPTY then
            k = i-1
            t = j
        elseif i>1 and j>1 and self.bubbles[i-1][j-1].state == BUBBLE_EMPTY then
            k = i-1
            t = j-1
        else
            print("error positioning up left bbl")
        end
    elseif p == BUBBLE_LEFT then
        if j>1 and self.bubbles[i][j-1].state == BUBBLE_EMPTY then
            k = i
            t = j-1
        else
            print("Error positioning left bubble")
            return self:attachBubble(i,j,BUBBLE_DOWN_LEFT)
        end
    elseif p == BUBBLE_DOWN_RIGHT then
        if a and i<h and j<w and self.bubbles[i+1][j+1].state == BUBBLE_EMPTY then  
            k = i+1
            t = j+1
        elseif i<h and self.bubbles[i+1][j].state == BUBBLE_EMPTY then  
            k = i+1
            t = j
        else
            print("error positioning down right bubble "..i..","..j)
if a then
          self.nextBubble = nil
else
self:attachBubble(i,j,BUBBLE_DOWN_LEFT)
end
            return 
        end
    elseif p == BUBBLE_UP_RIGHT then
        if a and i>1 and self.bubbles[i-1][j].state == BUBBLE_EMPTY then
            k = i-1
            t = j
        elseif i>1 and j<h and self.bubbles[i-1][j+1].state == BUBBLE_EMPTY then
            k = i-1
            t = j+1
        else
            print("error positioning left bubble")
            return self:attachBubble(i,j,BUBBLE_DOWN_LEFT)
        end
    elseif p == BUBBLE_RIGHT then
        if j<w and self.bubbles[i][j+1].state == BUBBLE_EMPTY then
            k = i
            t = j+1
        else 
            print("Error positioning right buble")
            return self:attachBubble(i,j,BUBBLE_DOWN_RIGHT)
        end
    end
    if k==0 and t==0 then
        print("error: position not found for the new bubble")
    end
    if self.bubbles[k][t].state == BUBBLE_ATTACHED then
        print("error: position is occupied by another bubble")   
    end
    local aux = 0
    if math.fmod(k,2)==0 then
        aux = (self.bubbleSize/2) + 16
    end
    
    
    self.nextBubble.position.y = self.initHeight+self.tileSize*self.height - 
                                    self.bubbleSize - (k-1)*self.tileSize
    self.nextBubble.position.x = aux+self.initWidth+self.tileSize*t - 
                                    self.bubbleSize
    self.nextBubble.state      = BUBBLE_ATTACHED
    self.bubbles[k][t]         = self.nextBubble
    self:findSolutions(k,t)
    self.nextBubble = nil
    if k == self.height-1 and self.bubbles[k][t].state==BUBBLE_ATTACHED then
        self:GameOver()
    end
end
function Puzzle:GameOver()
    sound(SOUND_RANDOM, 33465)
    self.state = PUZZLE_END
self.animaTime = 0
end
function Puzzle:findSolutions(i,j)
    self:clearBubbleExplorations()
    self.animaBubbs = {}
    self:findFallingBubblesFrom(i,j)
    if ((#self.animaBubbs)>2) then
        self:findAdjacentAnimaFallingBubbles()
        self.animating = true
        self.animaTime = 6
        sound(SOUND_EXPLODE, 46131)
    else
        sound(SOUND_HIT, 20242)
    end
end
function Puzzle:findAdjacentAnimaFallingBubbles()
    --self:clearBubbleExplorations()
    self.adyAnimBbs = {}
    local mini,minj,maxi,maxj = self.height,self.width,0,0
    for i,b in ipairs(self.animaBubbs) do
        --if b.x < mini then mini = b.x end
       -- if b.x > maxi then maxi = b.x end
        --if b.y < minj then minj = b.y end
       -- if b.y > maxj then maxj = b.y end
        table.insert(self.fas, FontAnim({
            text=(3*i),
            x=self.bubbles[b.x][b.y].position.x,
            y=self.bubbles[b.x][b.y].position.y
        }))
        score = score + (3*i)
    end 
    -- explore adjacents to find attached falling bubbles 
    --for i,b in ipairs(self.animaBubbs) do
        -- old system to find adjacents
        --self:findAdjacentBubbles(b.x,b.y,mini,minj,maxi,maxj) -- = i,j
        -- new algorithm- 1/2/2012
        self:exploreNonAdjscentFallingBubblesFromFirstLine()
   -- end
    self:addNotConnectedBubblesAdjacentsToAnima()
    -- add adjacents to the list of bubble solutions to animate and remove from puzzle board
    --for i,a in ipairs(self.adyAnimBbs) do
    --    table.insert(self.animaBubbs, table.maxn(self.animaBubbs)+1, a)
    --end
    
end
function Puzzle:addNotConnectedBubblesAdjacentsToAnima()
    for i=1,self.height do
     local m = self.width
     
     if math.fmod(i,2) == 0 then
        m = m - 1
     end
     k = 1
     for j=1,m do
        if self.bubbles[i][j].connected == false and 
            self.bubbles[i][j].state== BUBBLE_ATTACHED then
            table.insert(self.animaBubbs, vec2(i,j))
            table.insert(self.fas, FontAnim({
                text=(6*k),
                x=self.bubbles[i][j].position.x,
                y=self.bubbles[i][j].position.y
            }))
            score = score + (6*k)
            k = k + 1
        end
     end
    end
end
function Puzzle:disconnectBubbles()
    for i=1,self.height do
     local m = self.width
     
     if math.fmod(i,2) == 0 then
        m = m - 1
     end
     for j=1,m do
        self.bubbles[i][j].connected = false
     end
    end
end
function Puzzle:exploreNonAdjscentFallingBubblesFromFirstLine()
    local j
    self:disconnectBubbles()
    for j=1,self.width do
     self:markConnectedBubbles(1,j)
    end
end
    
function Puzzle:isBubbleInGroup(bubble,group)
    if group==nil or not #group then return false end
    for i,v in ipairs(group) do
        if bubble.x == v.x and bubble.y == v.y then return true end
    end
    return false
end
function Puzzle:markConnectedBubbles(i,j)
    local s = self:isBubbleInGroup(vec2(i,j),self.animaBubbs)
    if s then return end
    local y = self:isBubbleInGroup(vec2(i,j),self.adyAnimBbs)
    if y then return end
    local bubble = self.bubbles[i][j]
    if bubble.state == BUBBLE_EMPTY then return end
    if bubble.connected then
        return
    end
    bubble.connected = true
    local b = nil -- base case
    local h = self.height
    local w = self.width
    local a = math.fmod(i,2)==0
    local ok= true
    -- explore the sides 
         -- left
    if j>1 and self.bubbles[i][j-1].state==BUBBLE_ATTACHED then
        self:markConnectedBubbles(i,j-1)
    end
         -- right 
    if  j<w and self.bubbles[i][j+1].state==BUBBLE_ATTACHED then
        self:markConnectedBubbles(i,j+1)
    end
    
    if a then -- even rows
        -- down right
        if i<h and j<w and self.bubbles[i+1][j+1].state==BUBBLE_ATTACHED then
         self:markConnectedBubbles(i+1,j+1)
        end
        -- down left
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED then
         self:markConnectedBubbles(i+1,j)
        end
    else -- odd rows
         -- down right
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED then
         self:markConnectedBubbles(i+1,j)
        end
        -- down left
        if i<h and j>1 and self.bubbles[i+1][j-1].state==BUBBLE_ATTACHED then
         self:markConnectedBubbles(i+1,j-1)
        end
    end
end
function Puzzle:findAdjacentBubbles(i,j,i0,j0,i1,j1)
    local bubble = self.bubbles[i][j]
    if bubble.explored then 
        return 
    end
    bubble.explored = true
    --print(" Exploring "..i..","..j)
   
    local b = nil -- base case
    local h = self.height
    local w = self.width
    local a = math.fmod(i,2)==0
    local ok= true
    local s = self:isBubbleInGroup(bubble,self.animaBubbs)
    local y = self:isBubbleInGroup(bubble,self.adyAnimBbs)
    -- find a way from the origin group to the current i,j without sisters in solution group:
    if a then -- even rows
            -- only add if no bubble is attached up:
                -- up left
                if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and
                    not self:isBubbleInGroup(vec2(i-1,j),self.animaBubbs) 
                    and not self:isBubbleInGroup(vec2(i-1,j),self.adyAnimBbs)
                then
                    ok = false
                end
                -- up right
                if i>1 and j<w and self.bubbles[i-1][j+1].state==BUBBLE_ATTACHED and
                    not self:isBubbleInGroup(vec2(i-1,j+1),self.animaBubbs)
                    and not self:isBubbleInGroup(vec2(i-1,j+1),self.adyAnimBbs)
                then
                    ok = false
                end 
        else
            -- up left
                if i>1 and j>1 and self.bubbles[i-1][j-1].state==BUBBLE_ATTACHED and
                    not self:isBubbleInGroup(vec2(i-1,j-1),self.animaBubbs)
                    and not self:isBubbleInGroup(vec2(i-1,j-1),self.adyAnimBbs)
                then
                    ok = false
                end
                -- up right
                if i>1 and self.bubbles[i-1][j].state==BUBBLE_ATTACHED and
                    not self:isBubbleInGroup(vec2(i-1,j),self.animaBubbs)
                    and not self:isBubbleInGroup(vec2(i-1,j),self.adyAnimBbs)
                then
                    ok = false
                end 
        end
        if ok then
         -- only add if it is a new solution:
         if not s and not y then
            table.insert(self.adyAnimBbs, table.maxn(self.adyAnimBbs)+1, vec2(i,j))
         else -- solution already in the list and explored, next!
            return
         end
    end
    
    -- now, explore the sides 
         -- left
         if j>1 and self.bubbles[i][j-1].state==BUBBLE_ATTACHED and 
            not self:isBubbleInGroup(vec2(i,j-1),self.animaBubbs) and 
            (i>=i0 and i<=i1 and j)
         then
            self:findAdjacentBubbles(i,j-1,i0,j0,i1,j1)
         end
         -- right 
         if  j<w and self.bubbles[i][j+1].state==BUBBLE_ATTACHED and
            not self:isBubbleInGroup(vec2(i,j+1),self.animaBubbs)
         then
            self:findAdjacentBubbles(i,j+1,i0,j0,i1,j1)
         end
    
    if a then -- even rows
        -- down right
        if i<h and j<w and self.bubbles[i+1][j+1].state==BUBBLE_ATTACHED then
         self:findAdjacentBubbles(i+1,j+1,i0,j0,i1,j1)
        end
        -- down left
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED then
         self:findAdjacentBubbles(i+1,j,i0,j0,i1,j1)
        end
    else -- odd rows
         -- down right
        if i<h and self.bubbles[i+1][j].state==BUBBLE_ATTACHED then
         self:findAdjacentBubbles(i+1,j,i0,j0,i1,j1)
        end
        -- down left
        if i<h and j>1 and self.bubbles[i+1][j-1].state==BUBBLE_ATTACHED then
         self:findAdjacentBubbles(i+1,j-1,i0,j0,i1,j1)
        end
    end
end
  
function Puzzle:createCurrentColorsList()
    local mycolors = {}
    for i=1,self.height do
        for j=1,self.width do
            if self.bubbles[i][j].state == BUBBLE_ATTACHED then
                self:addCurrentColor(self.bubbles[i][j].mycolor, mycolors)
            end
        end
    end
    currentColors = mycolors
end
function Puzzle:checkNextBubbleColliding()
    local r = {}
    local aux = nil
    local nb  = self.nextBubble
    local k,t = 0,0
    local r   = self.tileSize
    local q   = 0
    local p   = nb.position
    local d   = 99999
    
    for i=1,self.height do
     for j=1,self.width do
       local b = self.bubbles[i][j]
       if b.state == BUBBLE_ATTACHED then
          
          q = math.sqrt( (b.position.x-p.x)*(b.position.x-p.x) +
                       (b.position.y-p.y)*(b.position.y-p.y) )
       -- if b.position:dist(p)<r then -- radius
          if q<r and q<d then
            if aux == nil then
                aux = b
                k   = i
                t   = j
            elseif aux.position.y < b.position.y then
                aux = b
                k   = i
                t   = j
                break
            end
            if aux ~= nil then break end
            d = q
        end
      end -- end if bubble attached
     end -- for j,h
    end -- for i,w
    if aux ~= nil then
        local xn,yn,xa,ya = nb.position.x,nb.position.y,aux.position.x,aux.position.y
        --print("sister of "..k..","..t.."nb="..xn..","..yn..";"..xa..","..ya)
        if xn <= xa and yn <= ya then
            --print("down left")
            self:attachBubble(k,t,BUBBLE_DOWN_LEFT)
        elseif xn <= xa and yn>= (ya+r) then
            --print("up left")
            self:attachBubble(k,t,BUBBLE_UP_LEFT)
        elseif xn <= xa and yn >= ya then
            --print("left")
            self:attachBubble(k,t,BUBBLE_LEFT)
        elseif xn >= xa and yn <= ya then
            --print("down right")
            self:attachBubble(k,t,BUBBLE_DOWN_RIGHT)
            
        elseif xn >= xa and yn >= (ya+r) then
            --print("up right")
            self:attachBubble(k,t,BUBBLE_UP_RIGHT) 
            
        else
            --print("right")
            self:attachBubble(k,t,BUBBLE_RIGHT)
            
        end
        
        return true
    end
    return false
end
function Puzzle:findRootPosition()
    local d = 9999
    local x = self.nextBubble.position.x
    local i = 1
    for k=1,self.width do
        local a = self.initWidth+self.tileSize*k - self.bubbleSize
        if (self.bubbles[1][i].state~=nil and math.abs(x-a)<d) then 
            d = x-a 
            i = k
            print(d)
        end
    end
    if d == 9999 then
        print("Cant find a top position!, a="..
         self.initWidth+self.tileSize - self.bubbleSize..", x="..
         self.nextBubble.position.x
        )
    else
        self.nextBubble.position.y = self.initHeight+self.tileSize*self.height - 
                                     self.bubbleSize
        self.nextBubble.position.x = self.initWidth+self.tileSize*i - self.bubbleSize
        self.nextBubble.state      = BUBBLE_ATTACHED  
        self.bubbles[1][i] = self.nextBubble
        self:findSolutions(1,i)
    end
    self.nextBubble = nil
end
function Puzzle:updateNextBubble()
    if self.animating or self.nextBubble == nil or 
        self.nextBubble.state == BUBBLE_ATTACHED 
    then 
        return 
    end
    if self:checkNextBubbleColliding() then
        return
    end
    if self.nextBubble.state == BUBBLE_FLYING then
        self.nextBubble.position   = self.nextBubble.position   + self.nextBubble.velocity
        --self.nextBubble.velocity.y = self.nextBubble.velocity.y + 0.1
    end
    
    local x = self.nextBubble.position.x
    local y = self.nextBubble.position.y
    local r = self.tileSize/2 - 6
    local top   = HEIGHT - self.initHeight
    local right = self.initWidth+self.width*self.tileSize    
    local left  = self.initWidth
    local bottom= self.initHeight
    
    if (x + r) > right then
        --self.nextBubble.position.x = right
        self.nextBubble.velocity.x   = -self.nextBubble.velocity.x
        sound(SOUND_PICKUP, 37987)
    elseif (x - r) <= left then
        --self.nextBubble.position.x = left
        self.nextBubble.velocity.x   = -self.nextBubble.velocity.x
        sound(SOUND_PICKUP, 37987)
    end
    if (y + r) > top then
        self:findRootPosition()
        
    end
end
function Puzzle:updateBubbleExplosions()
    for i,k in ipairs(self.explodeBbs) do
        if k.state == BUBBLE_ATTACHED then
            k.state = BUBBLE_EXPLODING 
        end
    end
end
function Puzzle:animateBubbles()
    self.animaTime = self.animaTime - 1/6
    
    if self.animaTime <= 0.333 then
        self.animaTime = 0
        self.animating = false
    end
    
    for i,k in ipairs(self.animaBubbs) do
        local b = self.bubbles[k.x][k.y]
        if b.state == BUBBLE_ATTACHED then
            b.state = BUBBLE_FALLING
        elseif not self.animating then
            b.state = BUBBLE_EMPTY
        else
            b.position.y = b.position.y - 23
        end
        
    end
    if not  self.animating then -- free mem
        self.animaBubbs = {}
    end
end
function Puzzle:updatePuzzleBubbles()
    --self:updateBubbleExplosions()
    if self.animating then
        self:animateBubbles()
    end
    for i=1,self.height do
        local m  = self.width
         if math.fmod(i,2) == 0 then
            m = m - 1
         end
         for j=1,m do
            local b = self.bubbles[i][j]
            if b.state == BUBBLE_DESTROYED then
            -- create bubble to fall down in the same position and colors
            
            end
        end
    end
end
function Puzzle:goToNextLevel()
    sound(SOUND_POWERUP, 33773)
    level = level + 1
    if level>#levels then
        self:GameOver()
        return
    end
    self.animating = true
    self.animaTime = 0
    self.state = PUZZLE_NEXT 
end
function Puzzle:update()
    if not self.animating and self.nextBubble~=nil and self.nextBubble.state == BUBBLE_FLYING then
        self:updateNextBubble()
    end
    self:updatePuzzleBubbles()
    if currentColors==nil or #currentColors==0 then
        self:goToNextLevel()
    end
end
function Puzzle:generateNextBubble()
    if not self.animating and self.state==PUZZLE_PLAYING and self.nextBubble == nil then
        self.timeNextBu = self.timeNextBu - self.nextBuFram
        if self.timeNextBu <= 0 then
            self.timeNextBu = self.BubbleCool
            self.nextBubble = Bubble(vec2(WIDTH/2,self.initHeight + 43),self.tileSize,nil) 
        end
    end
end
function Puzzle:drawArrow()
    noTint()
    stroke(255, 255, 255, 102)
    strokeWidth(15)
    lineCapMode(ROUND)
    pushMatrix()
    translate(WIDTH/2, puzzle.initHeight)
    grav = vec2(Gravity.x * 300, self.shootSpeed * 300)
    grav2= vec2(Gravity.x * 300, self.minGY * 300)
    --print(grav)
    line(0, 0, grav.x,self.minGY*300)
    -- Arrowhead
    down = vec2(0, -1)
    --orient = down:angleBetween(vec2(Gravity.x,-math.abs(Gravity.y)))
    orient = down:angleBetween(vec2(Gravity.x,-0.55))
    pushMatrix()
    resetMatrix()
    translate(WIDTH/2,puzzle.initHeight)
    translate(grav2.x,grav2.y)
    gr = -math.deg(orient) -180
    rotate(gr)
    line(0, 0, -20, 25)
    line(0, 0,  20, 25)
    popMatrix()
    -- End Arrowhead
    popMatrix()
end
function Puzzle:drawBubbles()
    ellipseMode(CENTER)
    for i=1,self.height do
        for j=1,self.width do
            self.bubbles[i][j]:draw()
        end
    end
end
function Puzzle:drawBackGroundTiles()
    local color1 = color(114, 81, 184, 255)
    local color2 = color(56, 56, 114, 255)
    local tilesz = self.tileSize
    rectMode(CORNER)
    noTint()
    strokeWidth(3)
    noFill()
    for i=0 ,self.width-1 do
        for j=0,self.height-1 do
            if math.mod((j+i),2)==0 then
                fill(color1)
            else
                fill(color2)
            end
            rect(self.initWidth+(tilesz*i),self.initHeight+(tilesz*j),tilesz,tilesz)
        end
    end
    
end
function Puzzle:drawBorders()
    --fill(214, 76, 20, 255)
    stroke(62, 56, 152, 255)
    strokeWidth(32)
    smooth()
    lineCapMode(0)
    local top   = HEIGHT - self.initHeight + 6
    local right = self.initWidth+self.width*self.tileSize+15
    local left  = self.initWidth-15
    local bottom= self.initHeight-11
    -- top line
    line(left,top+3,right,top+3)
    -- left line
    line(left,top,left,bottom)
    -- right line
    line(right,top,right,bottom)
    -- bottom line
    line(left,bottom,right,bottom)
    -- limit line
    strokeWidth(23)
    stroke(200, 181, 65, 200)
    line(left-self.tileSize,bottom+self.tileSize*2,right+self.tileSize,bottom+self.tileSize*2)
end
function Puzzle:drawNextLevel()
    noTint()
    background(0, 53, 255, 255)
    --sprite("Tyrian Remastered:Arrow Right",WIDTH/2,self.initHeight+43,31*2,66)
    self.st:draw()
    self.animaTime = self.animaTime + 0.1
    if self.animaTime>=6 then
        self:init(self.width,self.height,true)
        return
    end
    
    pushStyle()
    font("Futura-CondensedExtraBold")
    fontSize(133)
    pushMatrix()
    
    
    fill(127, 127, 127, 255)
    translate(WIDTH/2+3,HEIGHT/2+3)
    rotate(45)
    text("LEVEL "..level)
    fill(math.random(255),255,math.random(255),255)
    --translate(WIDTH/2,HEIGHT/2)
   -- rotate(0)
    text("LEVEL "..level,3,3)
    
    
    popMatrix()
    popStyle()
end
function Puzzle:drawGameOver()
    noTint()
    background(0, 53, 255, 255)
    --sprite("Tyrian Remastered:Arrow Right",WIDTH/2,self.initHeight+43,31*2,66)
    self.st:draw()
    self.animaTime = self.animaTime + 0.1
    if self.animaTime>=6 then
        self:init(self.width,self.height,true)
        self.state = PUZZLE_PLAYING
    end
    
    pushStyle()
    font("ArialRoundedMTBold")
    fontSize(66)
    pushMatrix()
    fill(224, math.random(255), math.random(255),232)
    
    translate(WIDTH/2,HEIGHT/2)
    
    text("Game Over")
    
    popMatrix()
    popStyle()
end
function Puzzle:drawTexts()
    for i,f in ipairs(self.fas) do
        if f.time<=0 then
            table.remove(self.fas,i)
        else
            f:draw()
        end
    end
end
function Puzzle:draw()
    if self.state == PUZZLE_NEXT then
        self:drawNextLevel()
    elseif self.state == PUZZLE_END then
        self:drawGameOver()
    elseif self.state == PUZZLE_PLAYING then
        self:update()
        self:createCurrentColorsList()
        if currentColors == {} then
            self:goToNextLevel()
            return 
        end
        background(71, 119, 232, 255)
        self:drawBackGroundTiles()
        self:drawBorders()
        self:generateNextBubble() 
        self:drawBubbles()
        self:drawTexts()
        self:drawArrow()
        
        sprite("Tyrian Remastered:Cracked Block",WIDTH/2,self.initHeight+43,31*2,66)
        if self.nextBubble ~= nil then
            self.nextBubble:draw()
        end
        
    end
    self.rs:draw()
end
function Puzzle:touchBubble(x,y)
    if self.state ~= PUZZLE_PLAYING then return end
    local finger = vec2(x,y)
    local radius = self.tileSize/2
    for i=1,self.height do   
        local m = self.width
        if math.mod(i,2)==0 then
            m = m - 1
        end
        for j=1, m do
            local b = self.bubbles[i][j]
            if  math.sqrt( (b.position.x-finger.x)*(b.position.x-finger.x) +
                       (b.position.y-finger.y)*(b.position.y-finger.y) ) < radius 
            then
                print("touched "..i..","..j.."("..b.position.x..","..b.position.y..".)") 
                self:clearBubbleExplorations()
                print(self:exploreBubble(i,j).." bubbles")
                return
            end
        end
    end
    
end
function Puzzle:touched(touch)
    if touch.state == ENDED then
        if touch.y > 95 then
            self:touchBubble(touch.x,touch.y)
        else
            self:launchBubble()
        end
    end
end
RoundScreen = class()
-- by Simeon from 2livesLeft
function RoundScreen:init(radius)
    -- you can accept and set parameters here
    self.image = self:setupImage(radius)
    self.radius = radius
    self.mesh = mesh()
    
    local r = {}
    local m = self.mesh
    m.texture = self.image
    
    for i = 1,4 do
        table.insert(r,m:addRect(0,0,0,0))
    end
                            
    self.rects = r
end
function RoundScreen:setupImage(radius)
    local roundImage = image(radius,radius)
    
    -- draw white circle corner
    setContext(roundImage)
    pushStyle()
    noSmooth()
    fill(0,0,0,255)
    rect(0,0,radius,radius)
    fill(255,255,255,255)
    ellipse(0,0,radius*2)
    popStyle()
    setContext()
    
    --process the image
    local w,h = roundImage.width,roundImage.height
    for x = 1,w do
        for y = 1,h do
            local r,g,b = roundImage:get(x,y)
            
            roundImage:set(x,y,0,0,0,255-r)
        end
    end
    
    return roundImage
end
function RoundScreen:draw()
    local m = self.mesh
    local r = self.rects
    local rd = self.radius
    local rd2 = rd/2 - 1
    
    m:setRect(r[1], rd2,rd2,rd,rd)
    m:setRectTex(r[1], 1,1,-1,-1)
    
    m:setRect(r[2], WIDTH - rd2,rd2,rd,rd)
    m:setRectTex(r[2], 0,1,1,-1)
    
    m:setRect(r[3], rd2,HEIGHT - rd2,rd,rd)
    m:setRectTex(r[3], 1,0,-1,1)
    
    m:setRect(r[4], WIDTH - rd2,HEIGHT - rd2,rd,rd)
    pushMatrix()
    resetMatrix()
    m:draw()
    
    popMatrix()
end
ScrollingTexture = class()
-- by Simeon
function ScrollingTexture:init(args)
    -- you can accept and set parameters here
    self.mesh = mesh()
    self.texName = args.texName
    self.mesh.texture = self.texName
    self.width = args.width or WIDTH
    self.height = args.height or HEIGHT
    self.texOffset = 0
    
    local w,h = spriteSize(self.texName)
    
    -- Allocate a mesh across the screen
    local cw = self.width / w
    local ch = self.height / h
    
    self.rects = {}
    
    local m = self.mesh
    for x = 1,cw do
        for y = 1,ch do
            local index = m:addRect((x-1)*w + w/2,(y-1)*h + h/2,w,h)
            table.insert(self.rects,index)
        end
    end
end
function ScrollingTexture:update()
    self.texOffset = self.texOffset + DeltaTime * 0.5
    local o = self.texOffset
    local m = self.mesh
    for _,v in pairs(self.rects) do
        m:setRectTex(v,o,o,1,1)
    end
end
function ScrollingTexture:draw()
    self:update()
    self.mesh:draw()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment