diff --git a/source/balebaSprite.lua b/source/balebaSprite.lua new file mode 100644 index 0000000..ba17e57 --- /dev/null +++ b/source/balebaSprite.lua @@ -0,0 +1,58 @@ +local pd = playdate +local gfx = playdate.graphics + +class('Baleba').extends(AnimatedSprite) + +function randomFloat(lower, greater) + return lower + math.random() * (greater - lower); +end + +function Baleba:init(x, y, player) + local balebaImageTable = gfx.imagetable.new("sprites/baleba") + Baleba.super.init(self, balebaImageTable) + + self:moveTo(x, y) + + self:addState("run", 1,4, {tickStep = 2}) + + self:setDefaultState("run") + + self:playAnimation() + + self:setZIndex(11) + self:setCollideRect(3, 25, 40, 15) + + self:setTag(154) + + self.standrate = randomFloat(0.3, 2) + self.xVelocity = Baleba.standrate + self.player = player + + + self.danger = Danger(366, y, self) + self.danger:add() +end + +function Baleba:update() + self:updateAnimation() + if self.player.isMovingRight() == false then + self.xVelocity = self.standrate + else + self.xVelocity = 2 + self.standrate + end + + if self.x < 430 and self.danger ~= nil then + self.danger:remove() + self.danger = nil + elseif self.danger == nil and self.x > 430 then + self.danger = Danger(366, self.y, self) + self.danger:add() + end + + if self.x < 0 then + self.standrate = randomFloat(0.5, 6) + self:moveTo(math.random(450, 600), math.random(50, 200)) + end + + self:moveTo(self.x-self.xVelocity, self.y) +end diff --git a/source/dangerSprite.lua b/source/dangerSprite.lua new file mode 100644 index 0000000..b245e34 --- /dev/null +++ b/source/dangerSprite.lua @@ -0,0 +1,27 @@ +local pd = playdate +local gfx = playdate.graphics + +class("Danger").extends(AnimatedSprite) + +function Danger:init(x, y, baleba) + local dangerImageTable = gfx.imagetable.new("sprites/danger") + Danger.super.init(self, dangerImageTable) + + self:moveTo(x, y) + + self:addState("run", 1,5, {tickStep = 2}) + + self:setDefaultState("run") + + self:playAnimation() + + self:setZIndex(11) + + self:setTag(7) + + self.baleba = baleba +end + +function Danger:update() + self:updateAnimation() +end \ No newline at end of file diff --git a/source/level.lua b/source/level.lua index aa1a428..dde277f 100644 --- a/source/level.lua +++ b/source/level.lua @@ -4,6 +4,8 @@ local gfx = playdate.graphics import "player" import "ground" import "backgroundSprite" +import "balebaSprite" +import "dangerSprite" class("Level").extends() @@ -49,6 +51,26 @@ function Level:init() Level.telemLostSound = playdate.sound.fileplayer.new( "audio/telemko" ) Level.telemLostSoundPlayed = false + + Level.balebas = {} + + for i=1, 3 do + Level.balebas[i] = Baleba(math.random(410, 900), math.random(10, 210), player) + Level.balebas[i]:add() + end + + t = playdate.timer.new(10000) + t.repeats = true + t.timerEndedCallback = function() + if #Level.balebas >= 6 then + return + end + + local k = #Level.balebas+1 + Level.balebas[k] = Baleba(math.random(410, 900), math.random(10, 210), player) + Level.balebas[k]:add() + print("Baleba added") + end end function Level:update() diff --git a/source/lib/pdParticles.lua b/source/lib/pdParticles.lua new file mode 100644 index 0000000..ae7a7c3 --- /dev/null +++ b/source/lib/pdParticles.lua @@ -0,0 +1,626 @@ +local particles = {} +local precision = 1 + +-- base particle class +class("Particle").extends() +function Particle:init(x, y) + self.x = x or 0 + self.y = y or 0 + self.size = {1,1} + self.spread = {0,359} + self.speed = {1,1} + self.acceleration = {0, 0} + self.thickness = {0,0} + self.lifespan = {1,1} + self.decay = 1 + self.particles = {} + self.colour = playdate.graphics.kColorBlack + self.bounds = {0,0,0,0} + self.mode = 0 + if self.type == 2 then -- polys + self.points={3,3} + self.angular={0,0} + self.rotation={0,359} + elseif self.type == 3 then -- images + self.angular={0,0} + self.image = playdate.graphics.image.new(1,1) + self.table = nil + self.rotation = {0,359} + end + + particles[#particles+1] = self + +end + +function Particle:remove() + for i = 1, #particles, 1 do + if particles[i] == self then + table.remove(particles, i) + break + end + end +end + +-- [[ SETTERS AND GETTERS ]] -- + +-- movement +function Particle:moveTo(x,y) + self.x = x + self.y = y +end + +function Particle:moveBy(x,y) + self.x += x + self.y += y +end + +function Particle:getPos() + return self.x, self.y +end + +-- size +function Particle:setSize(min, max) + self.size = {min, max or min} +end + +function Particle:getSize() + return self.size[1], self.size[2] +end + +-- mode +function Particle:setMode(mode) + self.mode = mode +end + +function Particle:getMode() + return self.mode +end + +-- spread +function Particle:setSpread(min,max) + self.spread = {min, max or min} +end + +function Particle:getSpread() + return self.spread[1], self.spread[2] +end + +-- speed +function Particle:setSpeed(min,max) + self.speed = {min, max or min} +end + +function Particle:getSpeed() + return self.speed[1], self.speed[2] +end + +-- acceleration +function Particle:setAcceleration(min,max) + self.acceleration = {min, max or min} +end + +function Particle:getAcceleration() + return self.acceleration[1], self.acceleration[2] +end + +-- thickness +function Particle:setThickness(min, max) + self.thickness = {min, max or min} +end + +function Particle:getThickness() + return self.thickness[1], self.thickness[2] +end + +-- lifespan +function Particle:setLifespan(min,max) + self.lifespan = {min, max or min} +end + +function Particle:getLifespan() + return self.lifespan[1], self.lifespan[2] +end + +-- colour +function Particle:setColor(colour) + self.colour = colour +end + +function Particle:getColor() + return self.colour +end + +function Particle:setColour(colour) + self.colour = colour +end + +function Particle:getColour() + return self.colour +end + +-- bounds +function Particle:setBounds(x1, y1, x2, y2) + self.bounds = {x1,y1,x2,y2} +end + +function Particle:getBounds() + return self.bounds[1],self.bounds[2],self.bounds[3],self.bounds[4] +end + +-- decay +function Particle:setDecay(decay) + self.decay = decay +end + +function Particle:getDecay() + return self.decay +end + +-- particles +function Particle:getParticles() + return self.particles +end + +function Particle:clearParticles() + self.particles = {} +end + +function Particle:update() +end + +-- [[ PARTICLE MODES ]] -- + +local function decay(partlist, decay) + for part = 1, #partlist, 1 do + local particle = partlist[part] + particle.size -= decay + + if particle.size <= 0 then + particle.size = 0 + end + + partlist[part] = particle + end + + for part = #partlist, 1, -1 do + local particle = partlist[part] + if particle.size <= 0 then + table.remove(partlist,part) + end + end + + return partlist +end + +local function disappear(partlist) + for part = 1, #partlist, 1 do + local particle = partlist[part] + particle.lifespan -= .1 + end + for part = #partlist, 1, -1 do + local particle = partlist[part] + if particle.lifespan <= 0 then + table.remove(partlist,part) + end + end + + return partlist +end + +local function loop(partlist, bounds) + if bounds[3] > bounds[1] and bounds[4] > bounds[2] then + local xDif , yDif = bounds[3] - bounds[1], bounds[4] - bounds[2] + for part = 1, #partlist, 1 do + local particle = partlist[part] + if particle.x > bounds[3] then particle.x -= xDif + elseif particle.x < bounds[1] then particle.x += xDif end + if particle.y > bounds[4] then particle.y -= yDif + elseif particle.y < bounds[2] then particle.y += yDif end + end + end + + return partlist +end + +local function stay(partlist, bounds) + if bounds[3] > bounds[1] and bounds[4] > bounds[2] then + local xDif , yDif = bounds[3] - bounds[1], bounds[4] - bounds[2] + for part = #partlist, 1, -1 do + local particle = partlist[part] + if particle.x > bounds[3] then table.remove(partlist,part) + elseif particle.x < bounds[1] then table.remove(partlist,part) + elseif particle.y > bounds[4] then table.remove(partlist,part) + elseif particle.y < bounds[2] then table.remove(partlist,part) end + end + end + + return partlist +end + +class("ParticleCircle", {type = 1}).extends(Particle) + +function ParticleCircle:create(amount) + for i = 1, amount, 1 do + local part = { + x = self.x, + y = self.y, + dir = math.random(self.spread[1],self.spread[2]), + size = math.random(self.size[1],self.size[2]) * precision, + speed = math.random(self.speed[1],self.speed[2]) * precision, + acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision, + lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision, + thickness = math.random(self.thickness[1],self.thickness[2]), + decay = self.decay + } + + self.particles[#self.particles+1] = part + end +end + +function ParticleCircle:add(amount) + self:create(amount) +end + +function ParticleCircle:update() + local w = playdate.graphics.getLineWidth() + local c = playdate.graphics.getColor() + playdate.graphics.setColor(self.colour) + for part = 1, #self.particles, 1 do + local circ = self.particles[part] + if circ.thickness < 1 then + playdate.graphics.fillCircleAtPoint(circ.x,circ.y,circ.size) + else + playdate.graphics.setLineWidth(circ.thickness) + playdate.graphics.drawCircleAtPoint(circ.x, circ.y, circ.size) + end + + circ.x += math.sin(math.rad(circ.dir)) * circ.speed + circ.y -= math.cos(math.rad(circ.dir)) * circ.speed + + circ.speed += circ.acceleration / 100 + + self.particles[part] = circ + end + playdate.graphics.setLineWidth(w) + playdate.graphics.setColor(c) + if self.mode == 1 then + decay(self.particles, self.decay) + + elseif self.mode == 0 then + disappear(self.particles) + + elseif self.mode == 2 then + loop(self.particles, self.bounds) + + else + stay(self.particles, self.bounds) + + end +end + +class("ParticlePoly", {type = 2}).extends(Particle) + +function ParticlePoly:getPoints() + return self.points[1], self.points[2] +end + +function ParticlePoly:setPoints(min,max) + self.points = {min, max or min} +end + +-- angular +function ParticlePoly:getAngular() + return self.angular[1], self.angular[2] +end + +function ParticlePoly:setAngular(min,max) + self.angular = {min, max or min} +end + +function ParticlePoly:getRotation() + return self.rotation[1], self.rotation[2] +end + +function ParticlePoly:setRotation(min,max) + self.rotation = {min, max or min} +end + +function ParticlePoly:create(amount) + for i = 1, amount, 1 do + local part = { + x = self.x, + y = self.y, + dir = math.random(self.spread[1],self.spread[2]), + size = math.random(self.size[1],self.size[2]) * precision, + speed = math.random(self.speed[1],self.speed[2]) * precision, + acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision, + lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision, + thickness = math.random(self.thickness[1],self.thickness[2]) * precision, + angular = math.random(self.angular[1],self.angular[2]) * precision, + points = math.random(self.points[1], self.points[2]), + decay = self.decay, + rotation = math.random(self.rotation[1],self.rotation[2]) + } + + self.particles[#self.particles+1] = part + end +end + +function ParticlePoly:add(amount) + self:create(amount) +end + +function ParticlePoly:update() + local w = playdate.graphics.getLineWidth() + local c = playdate.graphics.getColor() + playdate.graphics.setColor(self.colour) + for part = 1, #self.particles, 1 do + local poly = self.particles[part] + local polygon = {} + local degrees = 360 / poly.points + for point = 1, poly.points, 1 do + polygon[#polygon+1] = poly.x + math.sin(math.rad(degrees * point + poly.rotation)) * poly.size + polygon[#polygon+1] = poly.y - math.cos(math.rad(degrees * point + poly.rotation)) * poly.size + end + if poly.thickness < 1 then + playdate.graphics.fillPolygon(table.unpack(polygon)) + else + playdate.graphics.setLineWidth(poly.thickness) + playdate.graphics.drawPolygon(table.unpack(polygon)) + end + + poly.x += math.sin(math.rad(poly.dir)) * poly.speed + poly.y = poly.y - math.cos(math.rad(poly.dir)) * poly.speed + + poly.rotation += poly.angular + + poly.speed += poly.acceleration / 100 + + self.particles[part] = poly + end + playdate.graphics.setLineWidth(w) + playdate.graphics.setColor(c) + + if self.mode == 1 then + decay(self.particles, self.decay) + + elseif self.mode == 0 then + disappear(self.particles) + + elseif self.mode == 2 then + loop(self.particles, self.bounds) + + else + stay(self.particles, self.bounds) + + end +end + +class("ParticleImage", {type = 3}).extends(Particle) + +function ParticleImage:getAngular() + return self.angular[1], self.angular[2] +end + +function ParticleImage:setAngular(min,max) + self.angular = {min, max or min} +end + +function ParticleImage:getRotation() + return self.rotation[1], self.rotation[2] +end + +function ParticleImage:setRotation(min,max) + self.rotation = {min, max or min} +end + +function ParticleImage:setImage(image) + self.image = image + self.table = nil +end + +function ParticleImage:setImageTable(image) + self.image = nil + self.table = image +end + +function ParticleImage:getImage() + return self.image +end + +function ParticleImage:getImageTable() + return self.table +end + +function ParticleImage:create(amount) + if self.image ~= nil then + for i = 1, amount, 1 do + local part = { + x = self.x, + y = self.y, + dir = math.random(self.spread[1],self.spread[2]), + size = math.random(self.size[1],self.size[2]) * precision, + speed = math.random(self.speed[1],self.speed[2]) * precision, + acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision, + lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision, + thickness = math.random(self.thickness[1],self.thickness[2]), + angular = math.random(self.angular[1],self.angular[2]) * precision, + decay = self.decay, + image = self.image, + rotation = math.random(self.rotation[1],self.rotation[2]) + } + + self.particles[#self.particles+1] = part + end + else + for i = 1, amount, 1 do + local part = { + x = self.x, + y = self.y, + dir = math.random(self.spread[1],self.spread[2]), + size = math.random(self.size[1],self.size[2]) * precision, + speed = math.random(self.speed[1],self.speed[2]) * precision, + acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision, + lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision, + thickness = math.random(self.thickness[1],self.thickness[2]), + angular = math.random(self.angular[1],self.angular[2]) * precision, + decay = self.decay, + image = self.table[math.random(#self.table)], + rotation = math.random(self.rotation[1],self.rotation[2]) + } + + self.particles[#self.particles+1] = part + end + end +end + +function ParticleImage:add(amount) + self:create(amount) +end + +function ParticleImage:update() + for part = 1, #self.particles, 1 do + local img = self.particles[part] + + img.image:drawRotated(img.x,img.y,img.rotation,img.size) + + img.rotation += img.angular + + img.x += math.sin(math.rad(img.dir)) * img.speed + img.y = img.y - math.cos(math.rad(img.dir)) * img.speed + + img.speed += img.acceleration / 100 + + self.particles[part] = img + end + + if self.mode == 1 then + decay(self.particles, self.decay) + + elseif self.mode == 0 then + disappear(self.particles) + + elseif self.mode == 2 then + loop(self.particles, self.bounds) + + else + stay(self.particles, self.bounds) + + end +end + +class("ParticleImageBasic", {type = 3}).extends(ParticleImage) + +function ParticleImageBasic:update() + for part = 1, #self.particles, 1 do + local img = self.particles[part] + + img.image:drawScaled(img.x,img.y,img.size) + + img.rotation += img.angular + + img.x += math.sin(math.rad(img.dir)) * img.speed + img.y = img.y - math.cos(math.rad(img.dir)) * img.speed + + img.speed += img.acceleration / 100 + + self.particles[part] = img + end + + if self.mode == 1 then + decay(self.particles, self.decay) + + elseif self.mode == 0 then + disappear(self.particles) + + elseif self.mode == 2 then + loop(self.particles, self.bounds) + + else + stay(self.particles, self.bounds) + + end +end + +class("ParticlePixel").extends(Particle) + +function ParticlePixel:create(amount) + for i = 1, amount, 1 do + local part = { + x = self.x, + y = self.y, + dir = math.random(self.spread[1],self.spread[2]), + speed = math.random(self.speed[1],self.speed[2]) * precision, + acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision, + lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision, + } + + self.particles[#self.particles+1] = part + end +end + +function ParticlePixel:add(amount) + self:create(amount) +end + +function ParticlePixel:update() + local c = playdate.graphics.getColor() + playdate.graphics.setColor(self.colour) + for part = 1, #self.particles, 1 do + local pix = self.particles[part] + + playdate.graphics.drawPixel(pix.x,pix.y,pix.size) + + pix.x += math.sin(math.rad(pix.dir)) * pix.speed + pix.y -= math.cos(math.rad(pix.dir)) * pix.speed + + pix.speed += pix.acceleration / 100 + + self.particles[part] = pix + end + playdate.graphics.setColor(c) + + if self.mode == 0 then + disappear(self.particles) + + elseif self.mode == 2 then + loop(self.particles, self.bounds) + + else + stay(self.particles, self.bounds) + + end +end + +-- [[ GLOBAL PARTICLE STUFF ]] -- + +class("Particles").extends() + +Particles.modes = {DISAPPEAR = 0, DECAY = 1, LOOP = 2, STAY = 3} + +function Particles:update() + for particle = 1, #particles, 1 do + particles[particle]:update() + end +end + +function Particles:clearAll() + for part = 1, #particles, 1 do + particles[part]:clearParticles() + end +end + +function Particles:removeAll() + local lb = #particles + for part = 1, #particles, 1 do + particles[part] = nil + end +end + +function Particles:setPrecision(prec) + precision = prec +end + +function Particles:getPrecision() + return precision +end \ No newline at end of file diff --git a/source/main.lua b/source/main.lua index 5b59c7b..25b811e 100644 --- a/source/main.lua +++ b/source/main.lua @@ -26,6 +26,8 @@ gfx.setFont(font) -- Libraries import "lib/AnimatedSprite" +import "lib/pdParticles" + playdate.display.setRefreshRate(50) -- Game @@ -40,6 +42,7 @@ local function initialize() -- Init all the things! level = Level() playdate.resetElapsedTime() + end initialize() @@ -48,6 +51,7 @@ function pd.update() gfx.sprite.update() pd.timer.updateTimers() pd.drawFPS(10,0) + Particles:update() if level then level.update() diff --git a/source/player.lua b/source/player.lua index 889204a..8100629 100644 --- a/source/player.lua +++ b/source/player.lua @@ -34,7 +34,8 @@ function Player:init(x, y, gameManager) self.maxXSpeed = 2 self.maxYSpeed = 5 - self.fallSpeed = 0.4 + self.fallSpeed = 0.05 + self.maxFallSpeed = 0.4 -- Player State self.touchingGround = false @@ -116,14 +117,19 @@ function Player:handleMovementAndCollisions() local collisions local length = 0 - if self.x >= 20 and self.x <= 380 then - _, _, collisions, length = self:moveWithCollisions(self.x + self.xVelocity, self.y + self.yVelocity) - elseif self.x == 380 then - self.x = 380 - else - self.x = 20 + if Player.dead then + return end + local xVel = self.xVelocity + + if (self.x < 20 and xVel < 0) or (self.x > 380 and xVel > 0) then + xVel = 0 + end + + _, _, collisions, length = self:checkCollisions(self.x + xVel, self.y + self.yVelocity) + + self.touchingGround = false self.touchingCeiling = false self.touchingWall = false @@ -145,14 +151,29 @@ function Player:handleMovementAndCollisions() end end + if collisionTag == 3 then Player.dead = true self:changeState("boom") - -- elseif collisionTag == TAGS.Pickup then - -- collisionObject:pickUp(self) + return + elseif collisionTag == 154 then + Player.dead = true + self:changeState("boom") + + local particleB = ParticlePoly(self.x, self.y) + particleB:setThickness(2) + particleB:setAngular(-15,15) + particleB:setSize(1, 2) + particleB:setSpeed(1, 3) + particleB:setMode(Particles.modes.STAY) + particleB:setBounds(0,0,400,240) + particleB:setColour(gfx.kColorXOR) + particleB:add(20) + collisionObject:remove() -- TODO: add animation + return end end - + self:moveTo(self.x + xVel, self.y + self.yVelocity) end function Player:isMovingRight() @@ -175,6 +196,11 @@ function Player:handleDischarge(state) Player.bat = 0 self.fallSpeed = 2 self:changeToDownState() + return + end + + if Player.bat < 5000 then + self.fallSpeed = self.maxFallSpeed end if state == "run" then @@ -185,11 +211,17 @@ function Player:handleDischarge(state) Player.dischargeRate = 1 end + if self.y < 5 then + Player.dischargeRate = 20 + end + Player.bat = Player.bat - Player.dischargeRate end function Player:update() self:updateAnimation() + self:handleMovementAndCollisions() + if Player.dead then return end @@ -198,6 +230,4 @@ function Player:update() self:handleDischarge(state) self:handleGroundInput(state) - - self:handleMovementAndCollisions() end \ No newline at end of file diff --git a/source/sprites/baleba-table-64-64.png b/source/sprites/baleba-table-64-64.png new file mode 100644 index 0000000..4a86467 Binary files /dev/null and b/source/sprites/baleba-table-64-64.png differ diff --git a/source/sprites/danger-table-64-64.png b/source/sprites/danger-table-64-64.png new file mode 100644 index 0000000..5894e85 Binary files /dev/null and b/source/sprites/danger-table-64-64.png differ diff --git a/source/sprites/tank.png b/source/sprites/tank.png new file mode 100644 index 0000000..04eff91 Binary files /dev/null and b/source/sprites/tank.png differ