diff --git a/asteroids/main.lua b/asteroids/main.lua new file mode 100644 index 0000000..3003812 --- /dev/null +++ b/asteroids/main.lua @@ -0,0 +1,196 @@ +local love = require("love") + +local function initGame() + return { + width = 800, + height = 600, + ship = { + radius = 30, + bullet = { + timerLimit = 0.5, + radius = 5, + speed = 500, + time = 4, + }, + }, + asteroids = { + stages = { + { speed = 120, radius = 15 }, + { speed = 70, radius = 30 }, + { speed = 50, radius = 50 }, + { speed = 20, radius = 80 }, + }, + }, + controls = { + ship = { + turnRate = 10, + thrustRate = 100, + }, + }, + } +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 + + return { + ship = { + x = game.width / 2, + y = game.height / 2, + angle = 0, + speed = { + x = 0, + y = 0, + } + }, + -- the time after which the ship can fire another bullet + bulletTimer = game.ship.bullet.timerLimit, + bullets = {}, + asteroids = asteroids, + } +end + +local state = {} + +local function reset() + state = initState() +end + +function love.load() + reset() +end + +function love.update(dt) + if love.keyboard.isDown('right') then + state.ship.angle = state.ship.angle + game.controls.ship.turnRate * dt + end + if love.keyboard.isDown('left') then + state.ship.angle = state.ship.angle - game.controls.ship.turnRate * dt + end + state.ship.angle = state.ship.angle % (2 * math.pi) + + if love.keyboard.isDown('up') then + local shipSpeed = 100 + state.ship.speed.x = state.ship.speed.x + math.cos(state.ship.angle) * game.controls.ship.thrustRate * dt + state.ship.speed.y = state.ship.speed.y + math.sin(state.ship.angle) * game.controls.ship.thrustRate * dt + 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 + + state.bulletTimer = state.bulletTimer + dt + if love.keyboard.isDown('s') then + if state.bulletTimer >= game.ship.bullet.timerLimit then + state.bulletTimer = 0 + 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 + + 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.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(0, 0, 1) + love.graphics.circle('fill', state.ship.x, state.ship.y, game.ship.radius) + local shipCircleDistance = 20 + love.graphics.setColor(0, 1, 1) + love.graphics.circle( + 'fill', + state.ship.x + math.cos(state.ship.angle) * shipCircleDistance, + state.ship.y + math.sin(state.ship.angle) * shipCircleDistance, + 5 + ) + + 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 diff --git a/main.lua b/main.lua deleted file mode 100644 index 50c97cc..0000000 --- a/main.lua +++ /dev/null @@ -1,93 +0,0 @@ -local love = require("love") - -function love.load() - arenaWidth = 800 - arenaHeight = 600 - shipX = arenaWidth / 2 - shipY = arenaHeight / 2 - shipAngle = 0 - shipSpeedX = 0 - shipSpeedY = 0 - shipRadius = 30 - - bullets = {} - bulletTimerLimit = 0.5 - bulletTimer = bulletTimerLimit -end - -function love.update(dt) - local turnSpeed = 10 - if love.keyboard.isDown('right') then - shipAngle = shipAngle + turnSpeed * dt - end - if love.keyboard.isDown('left') then - shipAngle = shipAngle - turnSpeed * dt - end - shipAngle = shipAngle % (2 * math.pi) - - if love.keyboard.isDown('up') then - local shipSpeed = 100 - shipSpeedX = shipSpeedX + math.cos(shipAngle) * shipSpeed * dt - shipSpeedY = shipSpeedY + math.sin(shipAngle) * shipSpeed * dt - end - - shipX = (shipX + shipSpeedX * dt) % arenaWidth - shipY = (shipY + shipSpeedY * dt) % arenaHeight - - for bulletIndex = #bullets, 1, -1 do - local bullet = bullets[bulletIndex] - bullet.timeLeft = bullet.timeLeft - dt - if bullet.timeLeft <= 0 then - table.remove(bullets, bulletIndex) - else - local bulletSpeed = 500 - bullet.x = (bullet.x + math.cos(bullet.angle) * bulletSpeed * dt) % arenaWidth - bullet.y = (bullet.y + math.sin(bullet.angle) * bulletSpeed * dt) % arenaHeight - end - end - - bulletTimer = bulletTimer + dt - if love.keyboard.isDown('s') then - if bulletTimer >= bulletTimerLimit then - bulletTimer = 0 - table.insert(bullets, { - x = shipX + math.cos(shipAngle) * shipRadius, - y = shipY + math.sin(shipAngle) * shipRadius, - angle = shipAngle, - timeLeft = 4, - }) - end - end -end - -function love.draw() - for y = -1, 1 do - for x = -1, 1 do - love.graphics.origin() - love.graphics.translate(x * arenaWidth, y * arenaHeight) - love.graphics.setColor(0, 0, 1) - love.graphics.circle('fill', shipX, shipY, shipRadius) - local shipCircleDistance = 20 - love.graphics.setColor(0, 1, 1) - love.graphics.circle( - 'fill', - shipX + math.cos(shipAngle) * shipCircleDistance, - shipY + math.sin(shipAngle) * shipCircleDistance, - 5 - ) - - for bulletIndex, bullet in ipairs(bullets) do - love.graphics.setColor(0, 1, 0) - love.graphics.circle('fill', bullet.x, bullet.y, 5) - end - end - end - - love.graphics.origin() - love.graphics.setColor(1, 1, 1) - love.graphics.print(table.concat({ - 'shipAngle:' .. shipAngle, - 'shipX: ' .. shipX, - 'shipSpeedX: ' .. shipSpeedX, - }, '\n')) -end