local love = require("love") local function initGame() return { width = 800, height = 600, ship = { radius = 30, bullet = { radius = 5, speed = 500, time = 4, }, -- 99x75 sprite = love.graphics.newImage('resources/ship.png'), }, asteroids = { stages = { { speed = 120, radius = 15 }, { speed = 70, radius = 30 }, { speed = 50, radius = 50 }, { speed = 20, radius = 80 }, }, }, controls = { ship = { turnRate = 10, maxThrust = 200, }, }, } end local game = initGame() local function initState() local asteroids = { { x = 100, y = 100, }, { x = game.width - 100, y = 100, }, { x = game.width / 2, y = game.height - 100, } } for _, asteroid in ipairs(asteroids) do asteroid.angle = love.math.random() * (2 * math.pi) asteroid.stage = #game.asteroids.stages end local joystick = nil if love.joystick.getJoystickCount() == 1 then joystick = love.joystick.getJoysticks()[1] end return { ship = { x = game.width / 2, y = game.height / 2, angle = 3 * math.pi / 2, speed = { x = 0, y = 0, } }, bullets = {}, asteroids = asteroids, controls = { joystick = joystick, } } end local state = {} local function reset() state = initState() end function love.load() reset() end function love.update(dt) if state.controls.joystick ~= nil then local thrust = state.controls.joystick:getGamepadAxis('triggerright') * game.controls.ship.maxThrust state.ship.speed.x = state.ship.speed.x + math.cos(state.ship.angle) * thrust * dt state.ship.speed.y = state.ship.speed.y + math.sin(state.ship.angle) * thrust * dt local spin = state.controls.joystick:getGamepadAxis('leftx') * game.controls.ship.turnRate state.ship.angle = (state.ship.angle + spin * dt) % (2 * math.pi) end state.ship.x = (state.ship.x + state.ship.speed.x * dt) % game.width state.ship.y = (state.ship.y + state.ship.speed.y * dt) % game.height local function areCirclesIntersecting(aX, aY, aRadius, bX, bY, bRadius) return (aX - bX) ^ 2 + (aY - bY) ^ 2 <= (aRadius + bRadius) ^ 2 end for bulletIndex = #state.bullets, 1, -1 do local bullet = state.bullets[bulletIndex] bullet.timeLeft = bullet.timeLeft - dt if bullet.timeLeft <= 0 then table.remove(state.bullets, bulletIndex) else bullet.x = (bullet.x + math.cos(bullet.angle) * game.ship.bullet.speed * dt) % game.width bullet.y = (bullet.y + math.sin(bullet.angle) * game.ship.bullet.speed * dt) % game.height end for asteroidIndex = #state.asteroids, 1, -1 do local asteroid = state.asteroids[asteroidIndex] if areCirclesIntersecting(bullet.x, bullet.y, game.ship.bullet.radius, asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) then table.remove(state.bullets, bulletIndex) if asteroid.stage > 1 then local angle1 = love.math.random() * (2 * math.pi) local angle2 = (angle1 - math.pi) % (2 * math.pi) table.insert(state.asteroids, { x = asteroid.x, y = asteroid.y, angle = angle1, stage = asteroid.stage - 1, }) table.insert(state.asteroids, { x = asteroid.x, y = asteroid.y, angle = angle2, stage = asteroid.stage - 1, }) end table.remove(state.asteroids, asteroidIndex) break end end end for _, asteroid in ipairs(state.asteroids) do asteroid.x = (asteroid.x + math.cos(asteroid.angle) * game.asteroids.stages[asteroid.stage].speed * dt) % game.width asteroid.y = (asteroid.y + math.sin(asteroid.angle) * game.asteroids.stages[asteroid.stage].speed * dt) % game.height if areCirclesIntersecting(state.ship.x, state.ship.y, game.ship.radius, asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) then reset() break end end if #state.asteroids == 0 then reset() end end function love.gamepadpressed(joystick, button) if joystick ~= state.controls.joystick then return end if button == "b" then -- debounce, perhaps table.insert(state.bullets, { x = state.ship.x + math.cos(state.ship.angle) * game.ship.radius, y = state.ship.y + math.sin(state.ship.angle) * game.ship.radius, angle = state.ship.angle, timeLeft = game.ship.bullet.time, }) end end function love.draw() for y = -1, 1 do for x = -1, 1 do love.graphics.origin() love.graphics.translate(x * game.width, y * game.height) love.graphics.setColor(1, 1, 1) local scale = 2 * game.ship.radius / math.max(game.ship.sprite:getWidth(), game.ship.sprite:getHeight()) love.graphics.draw(game.ship.sprite, state.ship.x, state.ship.y, (state.ship.angle + math.pi / 2) % (math.pi * 2), scale, scale, game.ship.sprite:getWidth() / 2, game.ship.sprite:getHeight() / 2 ) for _, bullet in ipairs(state.bullets) do love.graphics.setColor(0, 1, 0) love.graphics.circle('fill', bullet.x, bullet.y, game.ship.bullet.radius) end for _, asteroid in ipairs(state.asteroids) do love.graphics.setColor(1, 1, 0) love.graphics.circle('fill', asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) end end end end