Skip to content

Instantly share code, notes, and snippets.

@juaxix
Created February 17, 2012 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juaxix/1855123 to your computer and use it in GitHub Desktop.
Save juaxix/1855123 to your computer and use it in GitHub Desktop.
Space Puzzle 8
Boss = class()
-- Bosses
BOSS_MAIN = 1
BOSS_ALT  = 2
-- Boss states
BOSS_DEAD    = 1
BOSS_ALIVE   = 2
BOSS_DAMAGED = 3
function Boss:init(_position,_type,limit_position,_velocity)
    self.position  = _position
    self.limit_pos = limit_position
    self.type      = _type
    self.velocity  = _velocity
    self.anifire   = math.random(1,6)
    self.anidead   = 16
    self.fires     = {}
    self.state     = BOSS_ALIVE
    if self.type == BOSS_MAIN then
        self.maxhealth= 21
        self.health   = 21
        self.dead_points = 666
    else
        self.maxhealth= 12
        self.health   = 12
        self.dead_points = 333
    end
end
function Boss:get_health_percentage()
    return math.floor ((self.health*100)/(self.maxhealth))
end
function Boss:update()
  local p = self:get_health_percentage()
  if p<=0 then
    if self.state == BOSS_DEAD and self.anidead<=0 then 
        return 
    end
    self.state = BOSS_DEAD
  elseif p<20 then
    self.state = BOSS_DAMAGED
  end
  if self.state ~= BOSS_DEAD then
    self.position = self.position + self.velocity
    local x0,xx0,y,xx1 = self.position.x,self.limit_pos.x,self.position.y,self.limit_pos.y
    if x0<xx0 or x0>xx1 then
        --self.position.x = xx0
        self.velocity.x = -self.velocity.x
        self.position.x = self.position.x + self.velocity.x*2
    end
    local y1 = HEIGHT/2
    if  ( (y>(y1+333)) or (y<(y1-100))  ) then
        self.velocity.y = -self.velocity.y
    end
    -- attack
    self.anifire = self.anifire - 1/33
    if self.anifire<=0 and (#self.fires)<7 then
        self.anifire = math.random(1,6)
        table.insert(self.fires, BossFire({
            position = self.position,
            creator  = self
        }))
        sound(SOUND_SHOOT, 239)
    end
  end
end
function Boss:draw()
    self:update()
    if self.state == BOSS_DEAD then
        if self.anidead<=0 then 
            return 
        else
            self.anidead = self.anidead - 1/23
            if self.type == BOSS_ALT then 
                tint(243, 61, 30, 255)
                sprite("Tyrian Remastered:Space Ice "..math.random(1,6),
                self.position.x,self.position.y)
                noTint()
            elseif self.type==BOSS_MAIN then
                local r = math.random(1,3)
                if r == 1 then
                    sprite("Tyrian Remastered:Explosion Huge",self.position.x,self.position.y)
                elseif r == 2 then
                    sprite("Tyrian Remastered:Fire Rock",self.position.x,self.position.y)
                else
                    sprite("Tyrian Remastered:Firestroid",self.position.x,self.position.y)
                end
            end
        end
        return
        --sprite("Tyrian Remastered:Explosion Huge",self.position.x,self.position.y)
    end
    pushMatrix()
    translate(self.position.x,self.position.y)
    if self.type == BOSS_ALT then 
        rotate(180)
        if self.state == BOSS_DAMAGED then
            sprite("Tyrian Remastered:Boss D Destroyed")
        else
            sprite("Tyrian Remastered:Boss D")
        end
    elseif self.type==BOSS_MAIN then
        if self.state == BOSS_DAMAGED then
            sprite("Tyrian Remastered:Blimp Boss Destroyed")
        else
            sprite("Tyrian Remastered:Blimp Boss")
        end
    end
    popMatrix()
    -- boss fires:
    for i,f in ipairs(self.fires) do
        if f.anidead <= 0 then
            table.remove(self.fires, i)
        else
            f:draw()
        end
    end
end
---------------------- Fires for the bosses
BossFire = class ()
BOSS_FIRE_ACTIVE = 1
function BossFire:init(args)
    self.position = args.position
    self.creator  = args.creator
    self.state    = BOSS_FIRE_ACTIVE
    self.anidead  = 4
end
function BossFire:update()
    -- check collision:
    if self.state == BOSS_FIRE_ACTIVE then 
     self.position.y = self.position.y - 1
     if self.position.y < (puzzle.initHeight+107) then
        self.state = BOSS_FIRE_END
         -- life:
        if self.creator.type == BOSS_MAIN then
            puzzle.health = puzzle.health - 6
        else
            puzzle.health = puzzle.health - 3
        end
        print(puzzle.health)
        if puzzle.health<=0 then
            puzzle:GameOver()
            return
        end
        sound(SOUND_EXPLODE)
     end
    elseif self.state == BOSS_FIRE_END then
        self.anidead = self.anidead - 1/33
    end
end
function BossFire:draw()
    self:update()
    if self.state == BOSS_FIRE_ACTIVE then
     if self.creator.type == BOSS_MAIN then
        sprite("Tyrian Remastered:Bullet Fire D",self.position.x,self.position.y)
     elseif self.creator.type == BOSS_ALT then
        sprite("Tyrian Remastered:Bullet Streak",self.position.x,self.position.y)
     end
    elseif self.state == BOSS_FIRE_END then
     if self.creator.type == BOSS_MAIN then
        sprite("Tyrian Remastered:Flame "..math.random(1,2),self.position.x,self.position.y)
     elseif self.creator.type == BOSS_ALT then
        sprite("Tyrian Remastered:Energy Orb "..math.random(1,2),self.position.x,self.position.y)
     end
    end
end
Bubble = class()
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11
-- http://xixgames.com
-- 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 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
    self.angle    = 0
    self.rotate   = 1
    if math.random(1,10)<5 then
        self.rotate = -1
    end
    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
    self.iposition= vec2(0,0)
    self.isizex   = self.size - 5
    self.isizey   = self.size - 5
    if puzzle and puzzle.bubbleSprite then
        self.image    = puzzle.bubbleSprite
    else
        self.image    = generate_random_bubble_sprite(puzzle)
    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:Rock 4",0,0,self.size/2,self.size/2)
        popMatrix()
        if self.position.y < puzzle.initHeight+puzzle.tileSize*3 then
            noTint()
            sprite("Tyrian Remastered:Space Ice "..math.random(1,4),self.position.x,
            puzzle.initHeight+100)
        end
    else -- attached or flying
        pushMatrix()
        --stroke(self.bcolor)
        --strokeWidth(3)
        --fill(self.color)
        --ellipse(self.position.x,self.position.y,self.size,self.size)
        tint(self.tint)
        self.angle = self.angle + (math.random(1,6)/10)*self.rotate
        if self.state==BUBBLE_FLYING then -- more speed
            self.angle = self.angle + (self.rotate*27)
        end
        if math.abs(self.angle)>=360 then
            self.angle = 0
        end
        translate(self.iposition.x + self.position.x,self.iposition.y + self.position.y)
        rotate(self.angle)
        sprite(self.image,0,0 , 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.c    = args.color
    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
        fill(self.c)
        self.c.a = self.c.a - 10
        text(self.text,self.x, self.y)
    end
end
-- Main
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11
-- http://xixgames.com
-- GAME MODES
GAME_MODE_MENU = 1
GAME_MODE_PLAY = 2
GAME_MODE_XIX  = 3
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}
 }
-- after levels the boss level appears, it is unique
}
supportedOrientations(LANDSCAPE_ANY)
function setup()
    displayMode(FULLSCREEN)
    highscore = readLocalData("highscore",0)
    change_Game_Mode( GAME_MODE_MENU )
end
function draw_xix_games()
    noTint()
    pushStyle()
    font("Futura-CondensedExtraBold")
    fontSize(266)
    fill(16, 196, 243, 255)
    text("6",WIDTH/2,HEIGHT/2)
    sprite("Tyrian Remastered:Chest Mecha",WIDTH/2,HEIGHT/2,195,152)
    fontSize(66)
    pushMatrix()
    fill(127, 127, 127, 255)
    translate(WIDTH/2+3,HEIGHT/2+3)
    text("Created by juaxix - XIXGAMES.COM")
    popMatrix()
    fill(255)
    fontSize(66)
    text("OK", WIDTH-233,HEIGHT/2 - 94)
    popStyle()
end
-- draw Game
function draw()
    background(0)
    if Game_Mode == GAME_MODE_MENU then
        menu:draw()
    elseif Game_Mode == GAME_MODE_XIX then
        draw_xix_games()
    elseif Game_Mode == GAME_MODE_PLAY then
        puzzle:draw()
    end
end
function touched(touch)
    if Game_Mode == GAME_MODE_MENU then
        menu:touched(touch)
    elseif Game_Mode == GAME_MODE_PLAY then
        puzzle:touched(touch)
    elseif Game_Mode == GAME_MODE_XIX then
        if touch.state ~= ENDED then return end
        if touch.x>=666 and touch.x<=910 and touch.y<=329 and touch.y>=250 then
            change_Game_Mode(GAME_MODE_MENU)
        end
    end
end
function change_Game_Mode(new_Game_Mode)
    Game_Mode = new_Game_Mode
    -- alloc and free mem
    currentColors = {}
    if new_Game_Mode == GAME_MODE_MENU then
        puzzle        = nil
        menu          = Menu()
    elseif new_Game_Mode == GAME_MODE_XIX then
        menu          = nil  
    elseif new_Game_Mode == GAME_MODE_PLAY then
        level         = 9 -- start level
        score         = 0 -- user score
        menu          = nil
        puzzle        = Puzzle(8,12,false) -- width, height, load level
        OrientAngle   = 0
    end
end
Menu = class()
-- 2/2012
-- xixgames.com
function Menu:init()
    self.stars    = Stars()
    self.fires    = {}
    set_all_colors()
    local i 
    for i = 1,(#levels) do 
        local b = Bubble(
            vec2(math.random(1,WIDTH),math.random(1,HEIGHT)),
            166,
            nil)
        b.speed = vec2(b.rotate,-b.rotate
        table.insert(self.fires, b)
    end
    self.ty = 0
    self.tx = 0
end
function Menu:draw()
    self.stars:draw()
    for i,f in ipairs(self.fires) do
        f.position = f.position + math.random(1,6)*f.speed
        if f.position.x>WIDTH -f.size or f.position.x<f.size then
            f.speed.x = -f.speed.x
        elseif f.position.y>HEIGHT-f.size or f.position.y<f.size then
            f.speed.y = -f.speed.y
        end  
        f:draw()
    end
    noTint()
    pushStyle()
    font("Futura-CondensedExtraBold")
    fill(127, 127, 127, 255)
    sprite("Tyrian Remastered:Icon", WIDTH-200,HEIGHT/2,166,166)
    fontSize(133)
    pushMatrix()
    
    translate(WIDTH/2+3,HEIGHT/2+3)
    rotate(45)
    text("SPACE PUZZLE "..(#levels))
    fill(math.random(166,255),math.random(166,255),math.random(166,255),255)
    --translate(WIDTH/2,HEIGHT/2)
   -- rotate(0)
    text("SPACE PUZZLE "..(#levels),3,3)
    popMatrix()
    fill(255)
    fontSize(66)
    text("PLAY", WIDTH-120,HEIGHT/2+100)
    text("CREDITS", WIDTH-233,HEIGHT/2 - 94)
    text("Highscore:"..highscore, WIDTH-233,HEIGHT/2 - 166)
    popStyle()
end
function Menu:touched(touch)
    --self.tx = touch.x
    -- self.ty = touch.y
    if touch.state ~= ENDED then return end
    if touch.x>=832 and touch.x<=1006 and touch.y>=444 and touch.y<=520 then
        change_Game_Mode(GAME_MODE_PLAY)
    elseif touch.x>=666 and touch.x<=910 and touch.y<=329 and touch.y>=250 then
        change_Game_Mode(GAME_MODE_XIX)
    end
end
Puzzle = class()
-- Magic Puzzle Bubble by @juaxix - LGPL
-- 11/11/11 
-- re-edit on 1/1/12 , 1/2/2012 -- for new contest 
-- http://xixgames.com
-- states
PUZZLE_PLAYING   = 1
PUZZLE_LOADING   = 2
PUZZLE_NEXT      = 3
PUZZLE_END       = 4
PUZZLE_BOSS      = 5 
PUZZLE_WIN       = 6
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  = {}
    self.time      = os.time()
    
    self.bosses_score = 0
    -- 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("Tyrian Remastered:Rock 5")
    self.st = ScrollingTexture()
    self.rs = RoundScreen(60)
    self.fas= {} -- font anim
end
function Puzzle:loadPuzzle()
    print("Loading level "..level)
    self.bubbleSprite = generate_random_bubble_sprite(nil)
    if level > (#levels) then
        self.state = PUZZLE_BOSS
        -- free mem
        self.nextBubble = nil
        self.bubbles = nil
        self:createBosses()
        set_all_colors()
        self.bubbleSprite = nil
        self.health = 100
        return
    end
    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
    self.time = os.time()
    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 = vec2(Gravity.x*27,self.shootSpeed*DeltaTime*69*23)
        -- new maths - 12/02/2012
        self.nextBubble.velocity = vec2(
            Gravity.x*12+math.tan(OrientAngle)*12,
            self.shootSpeed*DeltaTime*69*23
        )
        
        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: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 not a then
                return self:attachBubble(i,j,BUBBLE_DOWN_LEFT)
            else
                self.nextBubble = nil
            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,
            color = self.bubbles[b.x][b.y].bcolor
        }))
        score = score + (3*i)
    end 
    -- explore adjacents to find attached falling bubbles 
    
 -- new algorithm- 1/2/2012
    self:exploreNonAdjscentFallingBubblesFromFirstLine()
   
    self:addNotConnectedBubblesAdjacentsToAnima()
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 and 
            not self:isBubbleInGroup(vec2(i,j),self.animaBubbs)
        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,
                color = self.bubbles[i][j].bcolor
            }))
            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:createCurrentColorsList()
    if self.bubbles==nil then return 0 end
    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:createBosses()
    self.bosses = {}
    self.bosses_explosions = {}
    
    -- Main Boss at the center
    table.insert(self.bosses, Boss(
     vec2(self.tileSize * (self.width/2) + self.initWidth,HEIGHT/2+6),
     BOSS_MAIN,
      vec2(
        -- left
        self.initWidth+6,
        -- right
        self.initWidth+(self.tileSize*(self.width))
     ) ,
     vec2(-1,math.random(0.3,1.6)) -- velocity
    ))
    -- Right alt boss 
    table.insert(self.bosses, Boss(
        vec2(self.initWidth+(self.tileSize*(self.width)), HEIGHT/2),
        BOSS_ALT,
        vec2(
         -- left
         self.tileSize * (self.width/2) + self.initWidth,
         -- right
         self.initWidth+(self.tileSize*(self.width))
        ) ,
        vec2(-1,math.random(0.3,1.6))   -- velocity
    ))
    -- Left alt boss
    table.insert(self.bosses, Boss(
         vec2(self.initWidth+6,HEIGHT/2),
        BOSS_ALT,
        vec2(
         -- left
         self.initWidth+6,
         -- right
         self.tileSize * (self.width/2) + self.initWidth
        ) ,
         vec2(1,math.random(0.3,1.6)) -- velocity
    ))
end
function Puzzle:checkNextBubbleColliding()
    local r = {}
    local aux = nil
    local nb  = self.nextBubble
    local k,t = 0,0
    local r   = self.tileSize-10
    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
        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: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:check_nextfire_collision()
    local r = {}
    local aux = nil
    local nb  = self.nextBubble
    local k,t = 0,0
    local r   = nb.size-6
    local q   = 0
    local p   = nb.position
    local d   = 99999
    
    for i,b in ipairs(self.bosses) do
     if b~= nil then
       if b.state ~= BOSS_DEAD then
          -- check collision with bosses fires
            local t = 9999
            local v
            for j,f in ipairs(b.fires) do
             if f.state ~= BOSS_FIRE_END then
                local fx,fy = f.position.x,f.position.y
                v = math.sqrt
                    (nb.position.x-fx)*(nb.position.x-fx) +
                    (nb.position.y-fy)*(nb.position.y-fy
                )
                
                if v<r and v<t then
                    -- explode fire
                    f.state = BOSS_FIRE_END
                    self.nextBubble = nil
                   
                    return
                end
            end
          end
        -- check collision with bosses:
          q = math.sqrt
            (b.position.x-p.x)*(b.position.x-p.x) +
            (b.position.y-p.y)*(b.position.y-p.y
          )
          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 dead
     end -- if nil
    end -- for i,b
    if aux ~= nil then
        sound(SOUND_HIT, 473)
        aux.health = aux.health - 1
        if aux.health<=0 then
            aux.state = BOSS_DEAD
            self.bosses_score = self.bosses_score + aux.dead_points
            sound(SOUND_EXPLODE, 1212)
            table.insert(self.fas, FontAnim({
            text=aux.dead_points,
            x=aux.position.x,
            y=aux.position.y,
            color = color(255, 255, 255, 255)
            }))
            
        elseif aux:get_health_percentage()<18 then
            aux.state = BOSS_DAMAGED
        end
        self.nextBubble  = nil
    elseif p.y > (HEIGHT-12) then
        self.nextBubble = nil
    end
    
end
function Puzzle:updateNextBubbleFire()
    if self.animating or self.nextBubble==nil or self.nextBubble.state ~= BUBBLE_FLYING then
        return 
    end
    self.nextBubble.position = self.nextBubble.position   + self.nextBubble.velocity
    -- check collision with bosses:
    self:check_nextfire_collision()
        
end
function Puzzle:updatePuzzleBubbles()
    --self:updateBubbleExplosions()
    if self.animating then
        self:animateBubbles()
    end
end
function Puzzle:goToNextLevel()
    sound(SOUND_POWERUP, 33773)
    level = level + 1
    --if level>#levels then
       -- self:loadPuzzle()
      --  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 or self.state==PUZZLE_BOSS) and 
        self.nextBubble == nil 
    then
        self.timeNextBu = self.timeNextBu - self.nextBuFram
        if self.timeNextBu <= 0 then
            self.timeNextBu = self.BubbleCool
            self.nextBubble = Bubble(vec2(self.tileSize * (self.width/2) + self.initWidth
                ,self.initHeight + 43),self.tileSize,nil
        end
    end
end
function Puzzle:drawArrow()
    local middle = self.tileSize * (self.width/2) + self.initWidth
    noTint()
    stroke(255, 255, 255, 102)
    strokeWidth(15)
    lineCapMode(ROUND)
    pushMatrix()
    translate(middle, self.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))
    OrientAngle = orient
    pushMatrix()
    resetMatrix()
    translate(middle,self.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()
    -- draw the base for next bubble:
    pushMatrix()
    translate(middle,self.initHeight+50)
    rotate(-90)
    sprite("Tyrian Remastered:Satellite",0,0,133,133)
    popMatrix()
end
function Puzzle:drawBubbles()
    if self.bubbles==nil then return end
    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, 30)
    local color2 = color(56, 56, 114, 230)
    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)
    noTint()
    noFill()
    stroke(58, 58, 102, 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
    local middle= self.tileSize * (self.width/2) + self.initWidth
    if self.state == PUZZLE_PLAYING then
        -- 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)
    end
    -- Draw eyes
    pushMatrix()
    translate(self.initWidth-52, 132)
    rotate(90)
    sprite("Tyrian Remastered:Eye Mecha",0,0,133,133)
    popMatrix()
    pushMatrix()
    translate(self.initWidth+(self.tileSize*self.width)+52, 132)
    rotate(-90)
    sprite("Tyrian Remastered:Eye Mecha",0,0,133,133)
    popMatrix()
    -- limit line
    strokeWidth(23)
    stroke(19, 178, 228, 200)
    line(left,bottom+self.tileSize*2,right,bottom+self.tileSize*2)
    -- custom scenario
    sprite("Tyrian Remastered:Part B",middle,top,(middle)+66,35)
    sprite("Tyrian Remastered:Part A 1",right,top,46*2,33)
    sprite("Tyrian Remastered:Part A 2",left,top,46*2,33)
    sprite("Tyrian Remastered:Bad Case",middle,top+6,46*2,33)
    font("AmericanTypewriter-Condensed")
    fontSize(44)
    fill(255)
    
    --text("Level "..level.."         Score: "..score,middle-6,top)
    --text("Angle: "..OrientAngle,middle-6,top)
    sprite("Tyrian Remastered:Boss B",right+210,(top/2)-117)
    sprite("Tyrian Remastered:Panel Opening 5",right+210,(top/2)-223,200)
    
    sprite("Tyrian Remastered:Boss A",right+210,top-280,200)
    sprite("Tyrian Remastered:Panel Opening 5",right+210,top/2+10,200)
    sprite("Tyrian Remastered:Boss B",right+210,top-66)
    sprite("Tyrian Remastered:Panel Opening 5",right+210,top-166,200)
    if self.state == PUZZLE_PLAYING then
        if score>999 then
            text(score,right+210,top-175)
        else
            text("Score:"..(score),right+210,top-175)
        end
        text("Colors:"..(#currentColors),right+210,(top/2)-223)
        text("Level:"..(level),right+210,top/2)
    elseif self.state == PUZZLE_BOSS then
        -- life percents
        local deaths = 0
        if self.bosses[1] ~= nil and self.bosses[1].state~=BOSS_DEAD then
            text("Main:"..(self.bosses[1]:get_health_percentage()).."%",right+210,top-175)
        else
            text("Done",right+210,top-175)
            deaths = deaths + 1
        end
        if self.bosses[2] ~= nil and self.bosses[2].state~=BOSS_DEAD  then
            text("Left:"..(self.bosses[2]:get_health_percentage()).."%",right+210,top/2)
        else
            text("Done",right+210,top/2)
            deaths = deaths + 1
        end
        if self.bosses[3] ~= nil and self.bosses[3].state~=BOSS_DEAD then
            text("Right:"..(self.bosses[3]:get_health_percentage()).."%",right+210,(top/2)-227)
        else
            text("Done",right+210,(top/2)-227)
            deaths = deaths + 1
        end
        if deaths == (#self.bosses) then
            self.state = PUZZLE_WIN
            self.animaTime = 0
        end
        -- health bar
        stroke(37, 255, 0, 255)
        fontSize(33)
        text("Ship",right+123,(top/2)-323)
        line(right+177,(top/2)-323,right+177+self.health,(top/2)-323)
    
    end
    --local t = os.difftime( self.time / 100000,os.time()/100000 )
    --local t = os.time()/10000
    --text(t, right+210, 66)
end
function Puzzle:drawWin()
    noTint()
    background(183, 185, 189, 255)
    --self:drawBgRocks()
    self.st:draw()
    self.animaTime = self.animaTime + 0.1
    if self.animaTime>=66 then
        score = score + self.bosses_score
        if highscore<score then
            saveLocalData("highscore",score)
            highscore = score
        end
        change_Game_Mode(GAME_MODE_MENU)
        return
    end
    pushStyle()
    font("Futura-CondensedExtraBold")
    fontSize(133)
    pushMatrix()
    
    fill(math.random(66,255),255,math.random(66,255),255)
    translate(WIDTH/2+3,HEIGHT/2+66)
    rotate(math.random(-6,6))
    text("WINNER ")
    fill(math.random(66,255),255,math.random(66,255),255)
    popMatrix()
    fontSize(33)
    text("Thank you for playing!. xixgames.com ",WIDTH/2,(HEIGHT/2)-66)
    text("Score:"..(score+self.bosses_score),WIDTH/2,(HEIGHT/2) - 166)
    if highscore<(score+self.bosses_score) then
        text("Congrats!!, you did a highscore!!",WIDTH/2,(HEIGHT/2) - 190)
    end
    popStyle()
end
function Puzzle:drawNextLevel()
    noTint()
    
   -- self:drawBgRocks()
    --sprite("Tyrian Remastered:Arrow Right",WIDTH/2,self.initHeight+43,31*2,66)
   -- self.st:draw()
    if self.stars == nil then
        self.stars = Stars()
        self.stars.angle = 0
    end
    self.animaTime = self.animaTime + 0.1
    if self.animaTime>=12 then
        self.stars = nil
        self:init(self.width,self.height,true)
        return
    end
    self.stars:draw()
    noFill()
    pushStyle()
    stroke(204, 208, 224, 128)
   -- lineCapMode(SQUARE)
    strokeWidth(66)
    line(-66,HEIGHT/2,WIDTH+66,HEIGHT/2)
    font("Futura-CondensedExtraBold")
    fontSize(133)
    pushMatrix()
    fill(127, 127, 127, 255)
    translate(WIDTH/2+3,HEIGHT/2+3)
    --rotate(45)
    
    --translate(WIDTH/2,HEIGHT/2)
   -- rotate(0)
    
    if level > (#levels) then
        fill(math.random(66,255),255,math.random(66,255),233)
        text("BOSS LEVEL "..level,3,3)
        
        popMatrix()
        popStyle()
        noTint()
        tint(math.random(66,255),255,math.random(66,255),math.random(255))
        sprite("Tyrian Remastered:Warning Arrow",WIDTH/2+66,HEIGHT/2-166,360,230)
    else
        text("LEVEL "..level)
        fill(math.random(66,255),55,255,255)
        text("LEVEL "..level,3,3)
        popMatrix()
        popStyle()
    end
    
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("Futura-CondensedExtraBold")
    fontSize(166)
    pushMatrix()
    fill(math.random(1,66), math.random(255), math.random(255),232)
    
    translate(WIDTH/2,HEIGHT/2)
    
    text("TRY AGAIN")
    
    popMatrix()
    popStyle()
end
function Puzzle:drawTexts()
    noTint()
    noStroke()
    fill(255)
    fontSize(33)
    font("Futura-Medium")
    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:drawBgRocks()
    local i,j 
    noTint()
    noFill()
    
    for i=1,24 do
        for j=1,17 do
            pushMatrix()
            translate(41*i,(52*j))
            rotate(math.random(6,12))
            tint(94, 63, 43, math.random(66,255))
            sprite("Tyrian Remastered:Rock 4")
            popMatrix()
        end
    end
end
function Puzzle:drawNextBubble()
    self.nextBubble:draw()
    if self.nextBubble.state == BUBBLE_FLYING then
        pushMatrix()
        noTint()
        translate(self.nextBubble.position.x,self.nextBubble.position.y-50)
        rotate(180-(OrientAngle*10))
        sprite("Tyrian Remastered:Bullet Streak")
        popMatrix()
    end
end
function Puzzle:drawBoss()
    -- draw all the live bosses
    for i,b in ipairs(self.bosses) do
        b:draw()
    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_WIN then
        self:drawWin()
    elseif self.state == PUZZLE_BOSS then
        self:updateNextBubbleFire()
        self:drawBackGroundTiles()
        self:drawBorders()
        self:drawBoss()
        self:drawTexts()
        self:generateNextBubble()
        self:drawArrow()
        if self.nextBubble ~= nil then
            self:drawNextBubble()
        end
    elseif self.state == PUZZLE_PLAYING then
        self:update()
        self:createCurrentColorsList()
        if currentColors == {} then
            self:goToNextLevel()
            return 
        end
        background(26, 27, 36, 36)
        --self:drawBgRocks() -- efficience related
        self:drawBackGroundTiles()
        self:drawBorders()
        self:generateNextBubble() 
        self:drawBubbles()
        self:drawTexts()
        self:drawArrow()
        if self.nextBubble ~= nil then
            self:drawNextBubble()
        end
    end
    -- Round Screen
    self.rs:draw() 
end
function Puzzle:touched(touch)
    if touch.state == ENDED and self.nextBubble~= nil then
        self:launchBubble()
    end
end
function generate_random_bubble_sprite()
    local r = math.random(1,15)
    if r<6 then
        return "Tyrian Remastered:Rock 3"
    elseif r<11 then
        return "Tyrian Remastered:Blades"
    else
        return "Tyrian Remastered:Mine Spiked Huge"
    end
end
function set_all_colors()
    currentColors = {
                     BUBBLE_RED,BUBBLE_YELLOW,BUBBLE_GREEN,
                     BUBBLE_BLUE,BUBBLE_PURPLE,BUBBLE_ORANGE,
                     BUBBLE_GRAY
                    }
end
RoundScreen = class()
-- by Simeon from 2livesLeft
-- 2/2012
-- xixgames.com
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
-- 2/2012
-- xixgames.com
function ScrollingTexture:get_img_texture()
local img = image(32, 32)
img:set(2,7,127,127,127,255)
img:set(2,8,127,127,127,255)
img:set(3,6,127,127,127,255)
img:set(3,7,127,127,127,255)
img:set(3,8,127,127,127,255)
img:set(3,9,127,127,127,255)
img:set(3,10,127,127,127,255)
img:set(3,11,127,127,127,255)
img:set(4,5,127,127,127,255)
img:set(4,6,255,255,255,255)
img:set(4,7,255,255,255,255)
img:set(4,8,255,255,255,255)
img:set(4,9,255,255,255,255)
img:set(4,10,255,255,255,255)
img:set(4,11,127,127,127,255)
img:set(4,12,127,127,127,255)
img:set(4,13,127,127,127,255)
img:set(4,14,127,127,127,255)
img:set(5,4,127,127,127,255)
img:set(5,5,255,255,255,255)
img:set(5,6,255,255,255,255)
img:set(5,7,255,255,255,255)
img:set(5,8,255,255,255,255)
img:set(5,9,255,255,255,255)
img:set(5,10,255,255,255,255)
img:set(5,11,255,255,255,255)
img:set(5,12,255,255,255,255)
img:set(5,13,127,127,127,255)
img:set(5,14,127,127,127,255)
img:set(5,15,127,127,127,255)
img:set(6,3,127,127,127,255)
img:set(6,4,255,255,255,255)
img:set(6,5,255,255,255,255)
img:set(6,6,255,255,255,255)
img:set(6,7,255,255,0,255)
img:set(6,8,255,255,0,255)
img:set(6,9,255,255,0,255)
img:set(6,10,255,255,0,255)
img:set(6,11,255,255,255,255)
img:set(6,12,255,255,255,255)
img:set(6,13,255,255,255,255)
img:set(6,14,255,255,255,255)
img:set(6,15,255,255,255,255)
img:set(6,16,127,127,127,255)
img:set(6,17,127,127,127,255)
img:set(7,3,127,127,127,255)
img:set(7,4,255,255,255,255)
img:set(7,5,255,255,255,255)
img:set(7,6,255,255,255,255)
img:set(7,7,255,255,0,255)
img:set(7,8,255,128,0,255)
img:set(7,9,255,128,0,255)
img:set(7,10,255,128,0,255)
img:set(7,11,255,128,0,255)
img:set(7,12,255,255,0,255)
img:set(7,13,255,255,255,255)
img:set(7,14,255,255,255,255)
img:set(7,15,255,255,255,255)
img:set(7,16,255,255,255,255)
img:set(7,17,127,127,127,255)
img:set(7,18,127,127,127,255)
img:set(8,3,127,127,127,255)
img:set(8,4,255,255,255,255)
img:set(8,5,255,255,255,255)
img:set(8,6,255,255,0,255)
img:set(8,7,255,128,0,255)
img:set(8,8,255,128,0,255)
img:set(8,9,255,0,0,255)
img:set(8,10,255,0,0,255)
img:set(8,11,255,128,0,255)
img:set(8,12,255,128,0,255)
img:set(8,13,255,255,0,255)
img:set(8,14,255,255,255,255)
img:set(8,15,255,255,255,255)
img:set(8,16,255,255,255,255)
img:set(8,17,255,255,255,255)
img:set(8,18,127,127,127,255)
img:set(8,19,127,127,127,255)
img:set(9,3,127,127,127,255)
img:set(9,4,255,255,255,255)
img:set(9,5,255,255,255,255)
img:set(9,6,255,255,0,255)
img:set(9,7,255,128,0,255)
img:set(9,8,255,0,0,255)
img:set(9,9,255,0,0,255)
img:set(9,10,255,0,0,255)
img:set(9,11,255,0,0,255)
img:set(9,12,255,128,0,255)
img:set(9,13,255,128,0,255)
img:set(9,14,255,255,0,255)
img:set(9,15,255,255,255,255)
img:set(9,16,255,255,255,255)
img:set(9,17,255,255,255,255)
img:set(9,18,255,255,255,255)
img:set(9,19,127,127,127,255)
img:set(9,20,127,127,127,255)
img:set(10,3,127,127,127,255)
img:set(10,4,255,255,255,255)
img:set(10,5,255,255,255,255)
img:set(10,6,255,255,0,255)
img:set(10,7,255,255,0,255)
img:set(10,8,255,128,0,255)
img:set(10,9,255,0,0,255)
img:set(10,10,255,0,0,255)
img:set(10,11,255,0,0,255)
img:set(10,12,255,0,0,255)
img:set(10,13,255,128,0,255)
img:set(10,14,255,0,0,255)
img:set(10,15,255,255,0,255)
img:set(10,16,255,255,0,255)
img:set(10,17,255,255,255,255)
img:set(10,18,255,255,255,255)
img:set(10,19,255,255,255,255)
img:set(10,20,127,127,127,255)
img:set(10,21,127,127,127,255)
img:set(11,3,127,127,127,255)
img:set(11,4,255,255,255,255)
img:set(11,5,255,255,255,255)
img:set(11,6,255,255,0,255)
img:set(11,7,255,255,0,255)
img:set(11,8,255,128,0,255)
img:set(11,9,255,0,0,255)
img:set(11,10,255,0,0,255)
img:set(11,11,255,0,0,255)
img:set(11,12,255,0,0,255)
img:set(11,13,255,128,0,255)
img:set(11,14,255,128,0,255)
img:set(11,15,255,255,0,255)
img:set(11,16,255,255,0,255)
img:set(11,17,255,255,255,255)
img:set(11,18,255,255,255,255)
img:set(11,19,255,255,255,255)
img:set(11,20,255,255,255,255)
img:set(11,21,127,127,127,255)
img:set(12,3,127,127,127,255)
img:set(12,4,255,255,255,255)
img:set(12,5,255,255,255,255)
img:set(12,6,255,255,0,255)
img:set(12,7,255,255,0,255)
img:set(12,8,255,255,0,255)
img:set(12,9,255,128,0,255)
img:set(12,10,255,0,0,255)
img:set(12,11,255,0,0,255)
img:set(12,12,255,0,0,255)
img:set(12,13,255,0,0,255)
img:set(12,14,255,0,0,255)
img:set(12,15,255,128,0,255)
img:set(12,16,255,255,0,255)
img:set(12,17,255,255,0,255)
img:set(12,18,255,255,255,255)
img:set(12,19,255,255,255,255)
img:set(12,20,255,255,255,255)
img:set(12,21,127,127,127,255)
img:set(12,22,127,127,127,255)
img:set(13,4,127,127,127,255)
img:set(13,5,255,255,255,255)
img:set(13,6,255,255,255,255)
img:set(13,7,255,255,0,255)
img:set(13,8,255,255,0,255)
img:set(13,9,255,255,0,255)
img:set(13,10,255,128,0,255)
img:set(13,11,255,128,0,255)
img:set(13,12,255,0,0,255)
img:set(13,13,255,0,0,255)
img:set(13,14,255,0,0,255)
img:set(13,15,255,0,0,255)
img:set(13,16,255,128,0,255)
img:set(13,17,255,255,0,255)
img:set(13,18,255,255,0,255)
img:set(13,19,255,255,255,255)
img:set(13,20,255,255,255,255)
img:set(13,21,127,127,127,255)
img:set(13,22,127,127,127,255)
img:set(13,23,127,127,127,255)
img:set(14,4,127,127,127,255)
img:set(14,5,255,255,255,255)
img:set(14,6,255,255,255,255)
img:set(14,7,255,255,0,255)
img:set(14,8,255,255,0,255)
img:set(14,9,255,255,0,255)
img:set(14,10,255,255,0,255)
img:set(14,11,255,128,0,255)
img:set(14,12,255,128,0,255)
img:set(14,13,255,0,0,255)
img:set(14,14,255,0,0,255)
img:set(14,15,255,0,0,255)
img:set(14,16,255,128,0,255)
img:set(14,17,255,255,0,255)
img:set(14,18,255,255,0,255)
img:set(14,19,255,255,0,255)
img:set(14,20,255,255,255,255)
img:set(14,21,127,127,127,255)
img:set(14,22,127,127,127,255)
img:set(14,24,127,127,127,255)
img:set(15,4,127,127,127,255)
img:set(15,5,127,127,127,255)
img:set(15,6,255,255,255,255)
img:set(15,7,255,255,255,255)
img:set(15,8,255,255,0,255)
img:set(15,9,255,255,0,255)
img:set(15,10,255,255,0,255)
img:set(15,11,255,255,0,255)
img:set(15,12,255,128,0,255)
img:set(15,13,255,128,0,255)
img:set(15,14,255,128,0,255)
img:set(15,15,255,128,0,255)
img:set(15,16,255,0,0,255)
img:set(15,17,255,128,0,255)
img:set(15,18,255,255,0,255)
img:set(15,19,255,255,0,255)
img:set(15,20,255,255,0,255)
img:set(15,21,127,127,127,255)
img:set(15,22,127,127,127,255)
img:set(15,23,127,127,127,255)
img:set(15,25,127,127,127,255)
img:set(15,26,127,127,127,255)
img:set(16,5,127,127,127,255)
img:set(16,6,255,255,255,255)
img:set(16,7,255,255,255,255)
img:set(16,8,255,255,255,255)
img:set(16,9,255,255,0,255)
img:set(16,10,255,255,0,255)
img:set(16,11,255,128,0,255)
img:set(16,12,255,255,0,255)
img:set(16,13,255,255,0,255)
img:set(16,14,255,255,0,255)
img:set(16,15,255,128,0,255)
img:set(16,16,255,128,0,255)
img:set(16,17,255,128,0,255)
img:set(16,18,255,128,0,255)
img:set(16,19,255,255,0,255)
img:set(16,20,255,255,0,255)
img:set(16,21,255,255,255,255)
img:set(16,22,255,255,255,255)
img:set(16,23,127,127,127,255)
img:set(16,24,127,127,127,255)
img:set(16,26,127,127,127,255)
img:set(17,5,127,127,127,255)
img:set(17,6,127,127,127,255)
img:set(17,7,255,255,255,255)
img:set(17,8,255,255,255,255)
img:set(17,9,255,255,255,255)
img:set(17,10,255,255,0,255)
img:set(17,11,255,255,0,255)
img:set(17,12,255,128,0,255)
img:set(17,13,255,128,0,255)
img:set(17,14,255,255,0,255)
img:set(17,15,255,255,0,255)
img:set(17,16,255,255,0,255)
img:set(17,17,255,255,0,255)
img:set(17,18,255,128,0,255)
img:set(17,19,255,128,0,255)
img:set(17,20,255,255,0,255)
img:set(17,21,255,255,0,255)
img:set(17,22,255,255,255,255)
img:set(17,23,255,255,255,255)
img:set(17,24,127,127,127,255)
img:set(18,7,127,127,127,255)
img:set(18,8,255,255,255,255)
img:set(18,9,255,255,255,255)
img:set(18,10,255,255,255,255)
img:set(18,11,255,255,0,255)
img:set(18,12,255,128,0,255)
img:set(18,13,255,0,0,255)
img:set(18,14,255,128,0,255)
img:set(18,15,255,255,0,255)
img:set(18,16,255,255,0,255)
img:set(18,17,255,255,0,255)
img:set(18,18,255,255,0,255)
img:set(18,19,255,255,0,255)
img:set(18,20,255,128,0,255)
img:set(18,21,255,255,0,255)
img:set(18,22,255,255,0,255)
img:set(18,23,255,255,255,255)
img:set(18,24,255,255,255,255)
img:set(18,25,127,127,127,255)
img:set(19,7,127,127,127,255)
img:set(19,8,127,127,127,255)
img:set(19,9,255,255,255,255)
img:set(19,10,255,255,255,255)
img:set(19,11,255,255,255,255)
img:set(19,12,255,255,0,255)
img:set(19,13,255,128,0,255)
img:set(19,14,255,0,0,255)
img:set(19,15,255,128,0,255)
img:set(19,16,255,255,0,255)
img:set(19,17,255,128,0,255)
img:set(19,18,255,255,255,255)
img:set(19,19,255,255,0,255)
img:set(19,20,255,255,0,255)
img:set(19,21,255,255,0,255)
img:set(19,22,255,255,0,255)
img:set(19,23,255,255,255,255)
img:set(19,24,255,255,255,255)
img:set(19,25,255,255,255,255)
img:set(19,26,127,127,127,255)
img:set(20,9,127,127,127,255)
img:set(20,10,255,255,255,255)
img:set(20,11,255,255,255,255)
img:set(20,12,255,255,0,255)
img:set(20,13,255,128,0,255)
img:set(20,14,255,128,0,255)
img:set(20,15,255,128,0,255)
img:set(20,16,255,255,0,255)
img:set(20,17,255,255,0,255)
img:set(20,18,255,255,255,255)
img:set(20,19,255,255,255,255)
img:set(20,20,255,255,255,255)
img:set(20,21,255,255,0,255)
img:set(20,22,255,255,0,255)
img:set(20,23,255,255,0,255)
img:set(20,24,255,255,255,255)
img:set(20,25,255,255,255,255)
img:set(20,26,127,127,127,255)
img:set(20,27,127,127,127,255)
img:set(21,9,127,127,127,255)
img:set(21,10,127,127,127,255)
img:set(21,11,255,255,255,255)
img:set(21,12,255,255,255,255)
img:set(21,13,255,255,0,255)
img:set(21,14,255,255,0,255)
img:set(21,15,255,128,0,255)
img:set(21,16,255,255,0,255)
img:set(21,17,255,255,0,255)
img:set(21,18,255,255,255,255)
img:set(21,19,255,255,255,255)
img:set(21,20,255,255,255,255)
img:set(21,21,255,255,255,255)
img:set(21,22,255,255,255,255)
img:set(21,23,255,255,0,255)
img:set(21,24,255,255,0,255)
img:set(21,25,255,255,255,255)
img:set(21,26,127,127,127,255)
img:set(21,27,127,127,127,255)
img:set(21,28,127,127,127,255)
img:set(22,10,127,127,127,255)
img:set(22,11,255,255,255,255)
img:set(22,12,255,255,255,255)
img:set(22,13,255,255,0,255)
img:set(22,14,255,255,0,255)
img:set(22,15,255,255,0,255)
img:set(22,16,255,255,255,255)
img:set(22,17,255,255,255,255)
img:set(22,18,255,255,0,255)
img:set(22,19,255,255,255,255)
img:set(22,20,255,255,255,255)
img:set(22,21,255,255,255,255)
img:set(22,22,255,255,255,255)
img:set(22,23,255,255,255,255)
img:set(22,24,255,255,0,255)
img:set(22,25,255,255,0,255)
img:set(22,26,255,255,255,255)
img:set(22,27,127,127,127,255)
img:set(22,28,127,127,127,255)
img:set(23,12,127,127,127,255)
img:set(23,13,255,255,255,255)
img:set(23,14,255,255,0,255)
img:set(23,15,255,255,0,255)
img:set(23,16,127,127,127,255)
img:set(23,17,127,127,127,255)
img:set(23,18,255,255,255,255)
img:set(23,19,255,255,255,255)
img:set(23,20,255,255,255,255)
img:set(23,21,255,255,255,255)
img:set(23,22,255,255,255,255)
img:set(23,23,255,255,255,255)
img:set(23,24,255,255,255,255)
img:set(23,25,255,255,0,255)
img:set(23,26,255,255,0,255)
img:set(23,27,255,255,255,255)
img:set(23,28,127,127,127,255)
img:set(23,29,127,127,127,255)
img:set(24,12,127,127,127,255)
img:set(24,13,255,255,255,255)
img:set(24,14,255,255,255,255)
img:set(24,15,255,255,0,255)
img:set(24,16,127,127,127,255)
img:set(24,18,127,127,127,255)
img:set(24,19,255,255,255,255)
img:set(24,20,255,255,255,255)
img:set(24,21,255,255,255,255)
img:set(24,22,255,255,255,255)
img:set(24,23,255,255,255,255)
img:set(24,24,255,255,255,255)
img:set(24,25,255,255,255,255)
img:set(24,26,255,255,255,255)
img:set(24,27,255,255,255,255)
img:set(24,28,127,127,127,255)
img:set(24,29,127,127,127,255)
img:set(24,30,127,127,127,255)
img:set(25,12,127,127,127,255)
img:set(25,13,127,127,127,255)
img:set(25,14,127,127,127,255)
img:set(25,15,255,255,255,255)
img:set(25,16,255,255,255,255)
img:set(25,17,127,127,127,255)
img:set(25,19,127,127,127,255)
img:set(25,20,127,127,127,255)
img:set(25,21,255,255,255,255)
img:set(25,22,255,255,255,255)
img:set(25,23,255,255,255,255)
img:set(25,24,255,255,255,255)
img:set(25,25,255,255,255,255)
img:set(25,26,255,255,255,255)
img:set(25,27,255,255,255,255)
img:set(25,28,255,255,255,255)
img:set(25,29,127,127,127,255)
img:set(25,30,127,127,127,255)
img:set(26,15,127,127,127,255)
img:set(26,16,255,255,255,255)
img:set(26,17,127,127,127,255)
img:set(26,21,127,127,127,255)
img:set(26,22,127,127,127,255)
img:set(26,23,255,255,255,255)
img:set(26,24,255,255,255,255)
img:set(26,25,255,255,255,255)
img:set(26,26,255,255,255,255)
img:set(26,27,255,255,255,255)
img:set(26,28,255,255,255,255)
img:set(26,29,255,255,255,255)
img:set(26,30,127,127,127,255)
img:set(26,31,127,127,127,255)
img:set(27,16,127,127,127,255)
img:set(27,17,127,127,127,255)
img:set(27,18,127,127,127,255)
img:set(27,19,127,127,127,255)
img:set(27,22,127,127,127,255)
img:set(27,23,255,255,255,255)
img:set(27,24,127,127,127,255)
img:set(27,25,255,255,255,255)
img:set(27,26,255,255,255,255)
img:set(27,27,255,255,255,255)
img:set(27,28,255,255,255,255)
img:set(27,29,255,255,255,255)
img:set(27,30,127,127,127,255)
img:set(27,31,127,127,127,255)
img:set(27,32,127,127,127,255)
img:set(28,16,127,127,127,255)
img:set(28,18,127,127,127,255)
img:set(28,19,127,127,127,255)
img:set(28,23,127,127,127,255)
img:set(28,24,127,127,127,255)
img:set(28,25,127,127,127,255)
img:set(28,26,255,255,255,255)
img:set(28,27,127,127,127,255)
img:set(28,28,255,255,255,255)
img:set(28,29,255,255,255,255)
img:set(28,30,255,255,255,255)
img:set(28,31,255,255,255,255)
img:set(28,32,127,127,127,255)
img:set(29,17,127,127,127,255)
img:set(29,19,127,127,127,255)
img:set(29,25,127,127,127,255)
img:set(29,26,127,127,127,255)
img:set(29,27,255,255,255,255)
img:set(29,28,127,127,127,255)
img:set(29,29,255,255,255,255)
img:set(29,30,255,255,255,255)
img:set(29,31,255,255,255,255)
img:set(29,32,127,127,127,255)
img:set(30,19,127,127,127,255)
img:set(30,25,127,127,127,255)
img:set(30,26,127,127,127,255)
img:set(30,27,127,127,127,255)
img:set(30,28,127,127,127,255)
img:set(30,29,255,255,255,255)
img:set(30,30,127,127,127,255)
img:set(30,31,127,127,127,255)
img:set(31,26,127,127,127,255)
img:set(31,30,127,127,127,255)
img:set(31,31,127,127,127,255)
img:set(31,32,127,127,127,255)
img:set(32,30,255,255,255,255)
img:set(32,31,127,127,127,255)
img:set(32,32,127,127,127,255)
return img
end
function ScrollingTexture:init(args)
    -- you can accept and set parameters here
    self.mesh = mesh()
    --self.texName = args.texName
    --self.mesh.texture = self.texName
    self.mesh.texture = self:get_img_texture()
    self.width =  WIDTH*2
    self.height = HEIGHT
    self.texOffset = 0
    
   -- local w,h = spriteSize(self.texName)
    local w,h=128,128
    -- 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
-- This class draws the lines streaming past in the background
-- of the game. We spawn and delete them in the self.lines table
-- 2/2012
-- xixgames.com
----------------------------------------------
-- Star
----------------------------------------------
Star = class()
function Star:init(pos, vel, angl)
    self.position = pos
    self.velocity = vel
    self.angle    = angl
end
function Star:update()
    self.position.x = self.position.x - self.velocity
end
function Star:draw()
    p = self.position
    pushMatrix()
    if self.angle ~= 0 then
        translate(WIDTH/3,-HEIGHT/3)
    end
    rotate(self.angle)
    line(p.x-self.velocity,p.y,p.x,p.y)
    popMatrix()
end
function Star:shouldCull()
    -- Check if off the left of the screen
    if (self.position.x - self.velocity) < 0 then
        return true
    end 
    return false
end
----------------------------------------------
-- All stars
----------------------------------------------
Stars = class()
function Stars:init()
    self.minSpeed  = 6
    self.speed     = 23
    self.spawnRate = 1
    self.stars     = {}
    self.angle     = 45
end
function Stars:updateAndCull()
    toCull = {}
    for i,star in ipairs(self.stars) do
        if star:shouldCull() then
            table.remove( self.stars, i )
        else
            star:update()
        end
    end
end
function Stars:update()
    -- Create spawnRate lines per update
    for i = 1,self.spawnRate do
        -- Generate random spawn location
        vel = math.random(self.minSpeed, self.speed)
        spawn = vec2( WIDTH - vel, math.random(HEIGHT) )
        table.insert(self.stars, Star(spawn, vel, self.angle))
    end
    -- Update and cull offscreen lines
    self:updateAndCull()
end
function Stars:draw()
    self:update()
    pushStyle()
    noSmooth()
    stroke(179, 153, 180, 173)
    strokeWidth(2)
    lineCapMode(SQUARE)
 
    for i,star in ipairs(self.stars) do
        star:draw()
    end
    popStyle()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment