-- ===================================================== -- -- ____ _ _ ____ _ -- | _ \(_)_ __ ___ __ _ _ __ _ __ | | ___ | _ \(_)__________ _ -- | |_) | | '_ \ / _ \/ _` | '_ \| '_ \| |/ _ \ | |_) | |_ /_ / _` | -- | __/| | | | | __/ (_| | |_) | |_) | | __/ | __/| |/ / / / (_| | -- |_| |_|_| |_|\___|\__,_| .__/| .__/|_|\___| |_| |_/___/___\__,_| -- |_| |_| -- Made for the the Linux Game Jam March 2017 -- Requires love2d 0.10 (Super Toast) -- -- A simple game about protecting pizza from yourself -- -- This is a propaganga piece made to show pineapples -- ruin pizza. Don't deny it, you know it to be true -- -- Also, it's in space -- -- The game quits when the pineapple touches a pizza -- as what's the point anymore if pizza has been ruined -- -- Controls : WASD and Space, P to pause and ESC to exit -- -- ===================================================== -- -- -- Images cliparts.co -- BG spacetelescope.org/images/potw1006a -- Music toneden.io/mi77ermusic/post/stardust -- Sound freesound.org/people/greenvwbeetle/sounds/244654 -- -- ===================================================== -- -- ===================================================== -- -- Settings -- Whole scene properties kppm = 64 -- Pixels per metre kwidth = 0 kheight = 0 -- player properties kplayerThrust = 30000 kplayerMaxV = 350 kplayerFriction = 5 -- Bullet info knumBullets = 3 kbullRadius = 10 kbulletReturnForce = 300 kbulletMaxV = 400 -- Enemy Info knumEnemies = 50 kenemySpawnStartRate = 2 -- Music volume kmusicVolume = 0.05 -- Settings kdifficultyFactor = 1.02 -- ===================================================== -- -- Objects -- The physics world world = {} -- Arena Stuff bounds = {} bounds.ground = {} bounds.lwall = {} bounds.rwall = {} bounds.ceil = {} -- The player ktypePlayer = {} player = {} player.type = ktypePlayer -- Bullets ktypeBullet = {} bullets = {} for i=1,knumBullets do table.insert(bullets, {}) end for key,bull in pairs(bullets) do bull.projectile = false bull.returning = false bull.type = ktypeBullet end -- Enemies ktypeEnemy = {} enemySpawnRate = kenemySpawnStartRate enemies = {} for i=1,knumEnemies do table.insert(enemies, {}) end for key,enemy in pairs(enemies) do enemy.alive =false enemy.type = ktypeEnemy end -- Score score = 0 paused = true -- ===================================================== -- -- Load function love.load() -- Store some variables kwidth, kheight = love.graphics.getDimensions() -- Create images imageBG = love.graphics.newImage("space.png") imagePlayer = love.graphics.newImage("pineapple.png") imageBullet = love.graphics.newImage("fireball.png") imageEnemy = love.graphics.newImage("pizza.png") -- Load sound music = love.audio.newSource("Stardust.ogg") music:setLooping(true) music:setVolume(kmusicVolume) music:play() soundPop = love.audio.newSource("pop.ogg","static") -- Create a physics world love.physics.setMeter(kppm) world = love.physics.newWorld( 0 , 0, true ) world:setCallbacks(beginContact, endConact, preSolve, postSolve) -- Create the ground (and walls) bounds.ground.body = love.physics.newBody(world, kwidth/2, kheight) bounds.ground.shape = love.physics.newRectangleShape( kwidth, 1 ) bounds.lwall.body = love.physics.newBody(world, 0, kheight/2) bounds.lwall.shape = love.physics.newRectangleShape( 1, kheight ) bounds.rwall.body = love.physics.newBody(world, kwidth, kheight/2) bounds.rwall.shape = love.physics.newRectangleShape( 1, kheight ) bounds.ceil.body = love.physics.newBody(world, kwidth/2, 0) bounds.ceil.shape = love.physics.newRectangleShape( kwidth, 1 ) for key,bound in pairs(bounds) do bound.fixture = love.physics.newFixture( bound.body, bound.shape ) bound.fixture:setCategory(1) end -- Create the player player.body = love.physics.newBody(world, kwidth/2, kheight-40, "dynamic") player.shape = love.physics.newRectangleShape(0, 0, 20, 40) player.fixture = love.physics.newFixture(player.body, player.shape ) player.body:setFixedRotation(true) player.body:setLinearDamping(kplayerFriction) player.fixture:setCategory(2) player.fixture:setUserData(player) -- Create the bullets for key,bull in pairs(bullets) do x, y = player.body:getPosition() x, y = x + math.random(-30,30), y + math.random(-30,30) bull.body = love.physics.newBody(world, x, y, "dynamic") bull.shape = love.physics.newCircleShape(kbullRadius) bull.fixture = love.physics.newFixture(bull.body, bull.shape) bull.fixture:setCategory(3) bull.fixture:setMask(1,2,3) -- bullets don't hit wall, the player, or eachother bull.fixture:setUserData(bull) bull.image = imageBullet end -- Create the enemies enemyTimer = love.timer.getTime() enemyScale = 1 for key,enemy in pairs(enemies) do enemy.body = love.physics.newBody(world, kwidth/2, -100, "dynamic") enemy.shape = love.physics.newCircleShape(10 * enemyScale) enemy.scale = enemyScale enemy.fixture = love.physics.newFixture(enemy.body, enemy.shape) enemy.fixture:setCategory(4) enemy.fixture:setMask(1,4) -- enemies don't hit wall or eachother enemy.fixture:setUserData(enemy) enemyScale = enemyScale + 0.1 end -- Load in save file local savedatachunk = love.filesystem.load( "savedata" ) if savedatachunk then savedata = savedatachunk() else savedata = {} savedata.highscore = 0 savedata.fails = 0 end end -- ===================================================== -- -- Update function love.update(dt) if paused then music:pause() return else music:resume() end -- Keyboard controls for player local dx, dy = 0, 0 if love.keyboard.isDown("left") then dx = dx - kplayerThrust end if love.keyboard.isDown("right") then dx = dx + kplayerThrust end if love.keyboard.isDown("up") then dy = dy - kplayerThrust end if love.keyboard.isDown("down") then dy = dy + kplayerThrust end player.body:applyForce( dx*dt, dy*dt ) -- Limit player max velocity local vx, vy = player.body:getLinearVelocity() local vel = math.sqrt(vx*vx + vy*vy) if vel > kplayerMaxV then vx = vx/vel * kplayerMaxV vy = vy/vel * kplayerMaxV player.body:setLinearVelocity(vx,vy) end -- handle the enemies local spawnEnemy = love.timer.getTime() - enemyTimer > enemySpawnRate for key,enemy in pairs(enemies) do -- alive enemies should slowly drop if enemy.alive then local x, y = enemy.body:getPosition() if y > kheight then enemy.alive = false end else enemy.body:setPosition(-100,-100) -- innactive enemies off screen if spawnEnemy then spawnEnemy = false enemyTimer = love.timer.getTime() -- reset the timer enemy.body:setPosition( math.random(0,kwidth), 0 ) enemy.body:setLinearVelocity(math.random(-20,20),math.random(50,200)) enemy.alive = true end end end -- Sort out the bullets local px, py = player.body:getPosition() for key,bull in pairs(bullets) do local bx, by = bull.body:getPosition() -- non projectiles orbit the player if not bull.projectile then -- Get the delta to the player local dx, dy = px-bx, py-by bull.body:applyForce( dx * kbulletReturnForce * dt, dy * kbulletReturnForce * dt ) -- Account for returned bullets local dmag = math.sqrt(dx*dx + dy*dy) if dmag < bull.shape:getRadius()*3 then bull.returning = false end -- limit vel local vx, vy = bull.body:getLinearVelocity() local vel = math.sqrt(vx*vx + vy*vy) if vel > kbulletMaxV then vx = vx/vel * kbulletMaxV vy = vy/vel * kbulletMaxV bull.body:setLinearVelocity(vx,vy) end -- otherwise they fly and come back else if by < 0 then bull.projectile = false bull.returning = true end end end -- Update the physics world last world:update(dt) end -- ===================================================== -- -- Key presses function love.keypressed( key, sc, isrepeat ) -- Fire if key == "space" then -- find a bullet for key,bull in pairs(bullets) do if not bull.projectile and not bull.returning then bull.projectile = true bull.body:setPosition(player.body:getPosition()) bull.body:setLinearVelocity( 0, -1000 ) break end end -- Pause elseif key == "p" then paused = not paused -- Quit elseif key == "escape" then love.event.quit() end end -- ===================================================== -- -- Draw function love.draw() -- Draw the BG love.graphics.setColor( 128,128,128,256 ) love.graphics.draw( imageBG, kwidth/2, kheight/2, love.timer.getTime()/10, 0.8, 0.8, 600, 600) -- If we're paused if paused then love.graphics.setColor( 256,256,256,256 ) love.graphics.print( " Paused!\n[P] to unpause", kwidth/2, kheight/2, 0, 1, 1, 40 ) end -- Draw the player local x,y = player.body:getPosition() love.graphics.setColor( 256,256,256,256 ) love.graphics.draw( imagePlayer, x, y+5, 0, 0.2, 0.2, 72,170 ) -- Draw the enemies love.graphics.setColor( 256,256,256,256 ) for key,enemy in pairs(enemies) do if enemy.alive then love.graphics.draw( imageEnemy, enemy.body:getX(), enemy.body:getY(), enemy.scale-1, 0.2*enemy.scale, 0.2*enemy.scale, 60, 60 ) end end -- Draw the bullets for key,bull in pairs(bullets) do if bull.projectile then love.graphics.setColor( 256,256,256,256 ) elseif bull.returning then love.graphics.setColor( 128,128,128,64 ) else love.graphics.setColor( 200,200,200,180 ) end love.graphics.draw( bull.image, bull.body:getX(), bull.body:getY(), love.timer.getTime()*4, 0.2, 0.2, 60, 60 ) end -- Draw the UI love.graphics.setColor( 256,256,256,256 ) love.graphics.print( string.format("Pizzas Saved: %i\nHigh Score: %i\nRuined Pizzas: %i", score, savedata.highscore, savedata.fails), 1, 1 ) end -- ===================================================== -- -- Quit function love.quit() -- Save out the data local highest = score if highest < savedata.highscore then highest = savedata.highscore end love.filesystem.write( "savedata", string.format("return {\nhighscore = %i,\nfails = %i\n}", highest, savedata.fails) ) end -- ===================================================== -- -- Physics callbacks -- ie if a and be are type x and y -- if so, returns them in correct order function abxy( a, b, x, y ) if not a or not b then return end local at, bt = a.type, b.type if not at or not bt then return elseif ( at == x and bt == y) then return a, b elseif ( bt == x and at == y) then return b, a else return end end -- called at start of overlap (always) function beginContact(first, second, collision) local fd, sd = first:getUserData(), second:getUserData() -- Enemies and bullets local bullet, enemy = abxy( fd, sd, ktypeBullet, ktypeEnemy ) if bullet and enemy then if bullet.projectile and enemy.alive then enemy.alive = false bullet.projectile = false bullet.returning = true score = score + 1 soundPop:play() enemySpawnRate = enemySpawnRate/kdifficultyFactor -- speed up spawns end end local enemy, player = abxy( fd, sd, ktypeEnemy, ktypePlayer ) if enemy and player then savedata.fails = savedata.fails + 1 love.event.quit() end end -- called after overlap (only if overlap occured) function endContact(first, second, collision) end -- called before the collision gets resolved function preSolve(first, second, collision) local fd, sd = first:getUserData(), second:getUserData() -- Don't do any physics collisions for bullets and enemies local bullet, enemy = abxy( fd, sd, ktypeBullet, ktypeEnemy ) if bullet and enemy then collision:setEnabled(false) end end -- called after collision resolved, with details function postSolve(first, second, collision, normalimpulse, tangentimpulse) -- Not needed yet end