Bullets spawning from a wave function

wave and bullet class im working on. the intent is not to have a generic bullet class, but rather customize each wave and bullet…?

anyway, added a freeze/unfreeze function after i paused and unpausrd by accident and saw something really cool!

-- bullet share

displayMode(OVERLAY)
displayMode(FULLSCREEN)
-- Use this function to perform your initial setup
function setup()
    Player = {x=100,y=200,lv=1,hp=30,blinking=false,drawing=true,
    Hurt=function(self,dmg,time) 
        if self.blinking then return end
        self.hp=math.max(self.hp-dmg,0); 
        if self.hp==0 then sound(SOUND_EXPLODE, 5503)
        else sound(SOUND_HIT); blink:start(time);
        end
    end}
    
blink = {parent = Player, time=0}
function blink:start(time)--call from Player.Hurt, call Player.Hurt in your bullet OnHit function
    self.parent.blinking = true
    self.tween=tween(time, self, {time=time},tween.easing.linear,self.finish,self)
    tween.sequence(self.tween)
end

function blink:finish()
    self.parent.blinking = false
    self.parent.drawing = true
    tween.reset(self.tween)
    --self.time = 0
    --self.tween = nil
end

function blink:update()
    if not self.parent.blinking then return end
    self.parent.drawing = self.time % 0.15 > 0.075
end
    
    wave = firewave()
end
local alpha = 1
GameOver={}
function GameOver.draw()
    background(0)

    alpha = alpha < 255 and alpha + 1 or alpha
    fill(100, alpha)
    fontSize(72)
    text('GAME OVER', WIDTH/2, HEIGHT/2)
end
function GameOver.touched(t)
    
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    if Player.hp == 0 then
        GameOver.draw()
        return
    end
    background(40, 40, 50)

    -- This sets the line thickness
    pushStyle()
    --text('LV  '..Player.lv, WIDTH/2-100, 700)
    text('HP '..Player.hp..'/'..26+Player.lv*4,WIDTH/2, 700)
    if Player.drawing then
        fill(254,112,33)
        rectMode(CENTER)
        rect(Player.x, Player.y, 24,24)
    end
    text('Score  '..math.floor(ElapsedTime), WIDTH/2,740)
    popStyle()
    -- Do your drawing here
    wave:draw()
    wave:update()
    blink:update()
    --Player can go on the one sides of the screen and come out the other side
    Player.x = Player.x > 1000 and 44 or Player.x < 24 and 980 or Player.x
    Player.y = Player.y > 744 and 44 or Player.y < 24 and 724 or Player.y
end

function touched(t)
    if t.deltaX < 0 then
        Player.x=Player.x + math.max(t.deltaX, -8)
    else
        Player.x=Player.x + math.min(t.deltaX, 8)
    end
    if t.deltaY < 0 then
        Player.y = Player.y + math.max(t.deltaY,-8)
    else
        Player.y = Player.y + math.min(t.deltaY,8)
    end
end


--THESE ARE INDIVIDUAL BULLETS AND ONLY HANDLE THEMSELVES ON AN INDIVIDUAL BASIS
--for the wave script and patterns, make your own function
Fireball = class()

--actually, a mesh would work even better for memory
--cant remember how to flip a mesh when drawing it though
--so ill make two.
--hey, I have 16x16 images, should i use (0,0,16,16) or (0,0,15,15)?
--(but nows its 32x32 )
local spriteleft = mesh()
--spriteleft.texture = readImage("Project:spr_firebullet_center2_0")
spriteleft:addRect(0,0,32,32)--,16,16)
--spriteleft:setRectTex(1,0,0,1,1)
spriteleft:setRectColor(1, 155,123,32)
local spriteright = mesh()
--spriteright.texture = readImage("Project:spr_firebullet_center2_1")
spriteright:addRect(0,0,32,32)---16,-16,16,16)
--spriteright:setRectTex(1,0,0,1,1)
spriteright:setRectColor(1, 155,123,32)
--local direction = 'RIGHT'
--local RELATIVE, ABSOLUTE = 0,1



--UNUSED UNIFNISHED HELIX LOGIC FROM DESMOS 
--[[
local d = 2.1
--local a--the variable that changes --use self.time instead
local c = 2
local b = 2
--]]
local xvelocities = {0.1,0.2}
function Fireball:init(x, y)
    self.direction = math.random(1,2) == 2 and -1 or 1
    self.time = 0
    self.pos = vec2(x,y)
    
    --try setting direction to be floats, i.e. -0.2 or 2 ;)
    
    
    --self.velocity = vec2(math.random(5,20)/10*self.direction, math.random(500,501) / 500 * self.direction)

    self.vel2 = vec2(math.random(), math.random())
    --self.maxvelocity = {positive=vec2(50,50),negative=vec2(-50,-50)} 

    --p.s. try to keep calculations in init to save cpu

end



function Fireball:update()
    self.time = self.time + DeltaTime
    if self.pauseposition then 
        --self.position.y = self.position.y 
    return 
    end
    --[[
    --simple spiral example
    self.pos.x = self.pos.x + self.time*math.sin(self.time)*self.direction
    self.pos.y = self.pos.y - self.time*math.cos(self.time)
    --]]
    
    --[[
    --fire goes down, up, down and up
    --spawns with an initial y velocity!
    --self.pos.x = self.pos.x + self.time*math.sin(self.time)*self.direction/5
    --self.pos.y = self.pos.y - (self.time+math.random(1,20)/10)*math.cos(self.time)
    
    --]]
    
    -- tighter spiral
        
    self.pos.x = self.pos.x + self.time*math.sin(self.time)*self.direction*self.vel2.x
    self.pos.y = self.pos.y - self.time*math.cos(self.time)*self.vel2.y
    
    --to do: helix 
    --self.pos.x..
    if self.pos:dist(vec2(Player.x, Player.y)) < 24 then
        self:OnHit()
    end
    
end

function Fireball:draw(x,y,w,h)
    pushMatrix()

    translate(self.pos.x, self.pos.y)

    if self.time % 0.2 > 0.1 then 
        --sprite(self.leftsprite, Arena.x + self.x, Arena.y + self.y, 16, 16)
        spriteleft:draw()
    else
        --sprite(self.rightsprite, Arena.x + self.x, Arena.y + self.y, 16, 16)
        spriteright:draw()
    end
    popMatrix()
    --clip()
end
--[[PHYSICS DOESNT WORK
function Fireball:collide(contact)
    if contact.state == BEGAN then
        self:OnHit()
    end
end
--]]
function Fireball:OnHit()
    Player:Hurt(3, 0.5)--damage,invincibility time in seconds
    --self:Remove()
end

function Fireball:Remove()
    --self.time, self.x, self.y, self.velocity = nil,nil,nil,nil  --does this actually work?
    self=nil --maybe equivalent to the above..
end

--script

firewave = class()
function firewave:init()
    self.time = 0
    self.timer =  20
    self.nextfireball_timer = 0.2
    self.bullets = {}
    self.x = WIDTH/2--Arena.x + (Arena.x2 - Arena.x) * 0.5
    self.y = HEIGHT/2--Arena.y2 - 16
    local o1=5  --offset bottom left corner
    local o2=8  --offset top right corner
    self.t1 = tween.delay(10, self.freeze, self)
    self.t2 = tween.delay(1, self.unfreeze, self)
    self.t3 = tween.delay(10, self.freeze, self)
    self.t4 = tween.delay(1, self.unfreeze, self)
    tween.sequence(self.t1, self.t2, self.t3, self.t4)
    --disabled clip for this example
    --self.clip = --{x=Arena.x+o1,y=Arena.y+o1,
                 --w=Arena.x2-Arena.x-o2, h=Arena.y2-Arena.y-o2}
    --self.coroutine = coroutine.create(self.spawn, 20)
    --coroutine.resume(self.coroutine, self, 20)
end

--currently doesn't handle its own destruction - but you can easily configure it to..
--i.e. in firewave:update say
--if self.time > self.timer then firewave:destroy() 

function firewave:update(dt)
    self:HandleMovement()
    self.time = dt and self.time + dt or self.time + DeltaTime
    if self.time >= self.nextfireball_timer then
        if not self.frozen then table.insert(self.bullets, Fireball(self.x, self.y)) end
        self.nextfireball_timer = self.nextfireball_timer + 0.4
    end
end
function firewave:draw()
    pushStyle()
    --disable clip to see fullscreen bullet pattern
    --clip(self.clip.x, self.clip.y, self.clip.w, self.clip.h)

    for i,v in ipairs(self.bullets) do
        v:draw()--self.clip.x, self.clip.y, self.clip.w, self.clip.h)
    end
    clip()
    popStyle()
end
function firewave:destroy()
    for i,v in ipairs(self.bullets) do
        v:Remove()  --in v, sets self.x, self.y, self.velocity and self.time to nil
        v = nil     --deletes all references from self.bullets
    end
    --self.coroutine = nil --doesn't kill coroutine just deletes reference; might need garbagecollect
    
    --self = nil  --is this equivalent to all of the above or would they stay in memory if i do that?
    --return 'timer ended'
end

function firewave:HandleMovement()
    for i,v in ipairs(self.bullets) do
        v:update()
        --was too lazy to code properly, please do this later
        --you might use this if you had... say, a laser that spawned a wave of bullets

        --make it fancy and cool, i.e. Touhou spellcards
    end
end


function firewave:freeze()
    self.frozen=true
    for i,v in ipairs(self.bullets) do
        v:freeze()
    end
end

function firewave:unfreeze()
    for i,v in ipairs(self.bullets) do
        --v.velocity.y = v.velocity.y + 5
        v:unfreeze()
    end
    self.frozen=false
end


function Fireball:freeze()
    self.pauseposition = vec2(self.pos.x, self.pos.y)
end
function Fireball:unfreeze()
    self.pauseposition = false
end