A present for everyone

Fun little game I made for someone who asked for a present:
http://www.youtube.com/watch?v=O_yYkEfnJJs


--# Main
-- Present

-- Use this function to perform your initial setup
function setup()
    displayMode(FULLSCREEN)
    pr1 = readImage("Dropbox:present1")
    pr2 = readImage("Dropbox:present2")
    pr3 = readImage("Dropbox:present3")
    pr4 = readImage("Dropbox:present4")
    candy = readImage("Dropbox:candy")
    presents = {}
    cdir = 1
    cpos = vec2(math.random(50,WIDTH-50),50)
    score = 0
    gameover = false
    goc = 0
    et = 0
    misses = 0
    count = 0
    fire()
end


function fire()
    if gameover then return end
    table.insert(presents,Present(math.random(1,4),cpos+vec2(0,30)))
    count = count + 1
    tween.delay(math.random(10,20)/(10+et*0.25),fire)
end

function touched(t)
    if gameover and goc>0.5 then 
        if t.state == BEGAN then
            gameover = false goc = 0 et = 0 
            presents = {}
            score = 0
            count = 0
            misses = 0
        end 
    else
        for k,v in pairs(presents) do
            v:touched(t)
        end
    end
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    if not gameover then
    et = et + DeltaTime
    background(40, 40, 50)
    fontSize(30)
    -- This sets the line thickness
    strokeWidth(5)

    for k,v in pairs(presents) do
        v:draw()
        if v.finished then
            presents[k] = nil
        end
    end
    if cpos.x>=WIDTH-50 then
        cpos.x = WIDTH-51
        cdir = -1
    end
    if cpos.x<=50 then
        cpos.x = 51
        cdir = 1
    end
    cpos.x = cpos.x + cdir*5
    sprite("Dropbox:canon",cpos.x,cpos.y)
    fill(255)
    text("Score: "..score,100,600)
        if (15/(10+et*0.25))<0.325 then
            tween.delay(1,function() 
                gameover = true
            end)
        end
    text(math.abs(math.ceil((15/(10+et*0.25)-0.325)*100)),100,100)
    else
        goc = goc + DeltaTime
        background(40,40,50)
        pushStyle()
        fontSize(65)
        text("Game over, score: "..score,WIDTH/2,HEIGHT/2)
        fontSize(25)
        text("Misses: "..misses,WIDTH/2,HEIGHT/2-100)
        text("Present total:"..count,WIDTH/2,HEIGHT/2-170)
        popStyle()
    end
end



--# Present
Present = class()

function Present:init(typ,pos)
    -- you can accept and set parameters here
    self.typ = typ
    self.pos = pos
    self.img = nil
    if self.typ == 1 then
        self.img = pr1
    end
    if self.typ == 2 then
        self.img = pr2
    end
    if self.typ == 3 then
        self.img = pr3
    end
    if self.typ == 4 then
        self.img = pr4
    end
    self.vel = vec2(0,math.random(15,22))
    self.ang = math.random(-90,90)
    self.angvel = math.random(-10,10)
    self.finished = false
    self.exploded = false
    self.etime = 1
    self.cds = {}
    self.cp1 = {}
    self.cp2 = {}
    self.m = mesh()
    self.m.texture = self.img
end

function Present:explode()
    score = score + 50+self.typ*20
    local h = 0.66
    if self.typ == 2 then
        h = 0.75
    end
    if self.typ == 3 then
        h = 0.7
    end
    self.cp1.r = self.m:addRect(self.pos.x,self.pos.y,self.img.width/3,self.img.height*(2/3)/3,math.rad(self.ang))
    self.cp1.vel = vec2(0,-4):rotate(math.rad(self.ang))+self.vel/2
    self.cp1.pos = self.pos
    self.m:setRectTex(self.cp1.r,0,0,1,h)
    self.cp2.r = self.m:addRect(self.pos.x,self.pos.y,self.img.width/3,self.img.height*(1/3)/3,math.rad(self.ang))
    self.cp2.vel = vec2(0,4):rotate(math.rad(self.ang))+self.vel/2
    self.cp2.pos = self.pos
    self.m:setRectTex(self.cp2.r,0,h,1,1)
    for i=1,math.random(20,35) do
        self.cds[i] = {}
        self.cds[i].pos = self.pos+vec2(math.random(-10,10),math.random(-10,10))
        self.cds[i].vel = -(self.pos-self.cds[i].pos)/6+self.vel/2
        self.cds[i].ang = math.random(0,360)
        self.cds[i].angvel = math.random(-5,5)
        self.cds[i].col = color(math.random(100,255),math.random(0,255),math.random(50,255))
    end
    self.exploded = true
end

function Present:draw()
    if not self.exploded then
        self.pos = self.pos + self.vel
        self.vel = self.vel*0.99
        self.vel = self.vel + vec2(0,-0.3)
        self.ang = self.ang + self.angvel
        --if self.vel.y<0 then self:explode() end
        pushMatrix()
        translate(self.pos.x,self.pos.y)
        rotate(self.ang)
        sprite(self.img,0,0,self.img.width/3,self.img.height/3)
        popMatrix()
    else
        self.etime = self.etime - DeltaTime/3
        if self.etime<=0 then
            self.finished = true
        else
            self.cp1.pos = self.cp1.pos + self.cp1.vel
            self.cp2.pos = self.cp2.pos + self.cp2.vel
            self.cp1.vel = self.cp1.vel + vec2(0,-0.1)
            self.cp2.vel = self.cp2.vel + vec2(0,-0.1)
            self.m:setRect(self.cp1.r,self.cp1.pos.x,self.cp1.pos.y,self.img.width/3,self.img.height*(2/3)/3,math.rad(self.ang))
            self.m:setRect(self.cp2.r,self.cp2.pos.x,self.cp2.pos.y,self.img.width/3,self.img.height*(1)/3,math.rad(self.ang))
            self.m:setColors(255,255,255,self.etime*255)
            for i=1,#self.cds do
                self.cds[i].ang = self.cds[i].ang + self.cds[i].angvel
                self.cds[i].pos = self.cds[i].pos + self.cds[i].vel
                self.cds[i].vel = self.cds[i].vel + vec2(0,-0.1)
                pushMatrix()
                pushStyle()
                translate(self.cds[i].pos.x,self.cds[i].pos.y)
                rotate(self.cds[i].ang)
                tint(self.cds[i].col.r,self.cds[i].col.g,self.cds[i].col.b,self.etime*255)
                sprite(candy,0,0)
                popStyle()
                popMatrix()
            end
            self.m:draw()
        end
    end
    if self.pos.y<-50 then self.finished = true score = score -100-40*self.typ misses = misses + 1 end
end

function Present:touched(t)
    if vec2(t.x,t.y):dist(self.pos)<50 and t.state == BEGAN and not self.exploded then self:explode() end
end

Sorry but you also need to download files:

https://www.dropbox.com/s/sy6ztwiulmvxjqu/candy%402x.png?dl=0
https://www.dropbox.com/s/6c1nmrhfetpjxg8/present1%402x.png?dl=0
https://www.dropbox.com/s/ceyi945ewiytjr6/present2%402x.png?dl=0
https://www.dropbox.com/s/6dyjl4hd513t8ve/present3%402x.png?dl=0
https://www.dropbox.com/s/9h1tjmuv51h4csq/present4%402x.png?dl=0
https://www.dropbox.com/s/dsh04yxar0r39cb/canon%402x.png?dl=0

They’re at 2x with the extension still on.

@Luatee “canon” on Dropbox was missing.

Line 156, img is a nil value

Oops, updated with the canon image

@luatee could we get a video?

Updated version and video in OP