pineapple-pizza/main.lua

443 lines
12 KiB
Lua
Raw Permalink Normal View History

2017-03-19 14:48:01 +00:00
-- ===================================================== --
-- ____ _ _ ____ _
-- | _ \(_)_ __ ___ __ _ _ __ _ __ | | ___ | _ \(_)__________ _
-- | |_) | | '_ \ / _ \/ _` | '_ \| '_ \| |/ _ \ | |_) | |_ /_ / _` |
-- | __/| | | | | __/ (_| | |_) | |_) | | __/ | __/| |/ / / / (_| |
-- |_| |_|_| |_|\___|\__,_| .__/| .__/|_|\___| |_| |_/___/___\__,_|
-- |_| |_|
-- 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