From 9f78b280cda4277d41d50cadf3d74df173606d72 Mon Sep 17 00:00:00 2001 From: Donald Ball Date: Fri, 14 Nov 2025 21:27:55 -0500 Subject: [PATCH] coalesce state --- asteroids/main.lua | 129 +++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/asteroids/main.lua b/asteroids/main.lua index 81d8882..b9fca5e 100644 --- a/asteroids/main.lua +++ b/asteroids/main.lua @@ -24,123 +24,138 @@ end local game = initGame() -function love.load() - function reset() - shipX = game.width / 2 - shipY = game.height / 2 - shipAngle = 0 - shipSpeedX = 0 - shipSpeedY = 0 - bullets = {} - bulletTimer = game.ship.bullet.timerLimit - asteroids = { - { - x = 100, - y = 100, - }, - { - x = game.width - 100, - y = 100, - }, - { - x = game.width / 2, - y = game.height - 100, - } +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 + } + 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) local turnSpeed = 10 if love.keyboard.isDown('right') then - shipAngle = shipAngle + turnSpeed * dt + state.ship.angle = state.ship.angle + turnSpeed * dt end if love.keyboard.isDown('left') then - shipAngle = shipAngle - turnSpeed * dt + state.ship.angle = state.ship.angle - turnSpeed * dt end - shipAngle = shipAngle % (2 * math.pi) + state.ship.angle = state.ship.angle % (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 + state.ship.speed.x = state.ship.speed.x + math.cos(state.ship.angle) * shipSpeed * dt + state.ship.speed.y = state.ship.speed.y + math.sin(state.ship.angle) * shipSpeed * dt end - shipX = (shipX + shipSpeedX * dt) % game.width - shipY = (shipY + shipSpeedY * dt) % game.height + 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 = #bullets, 1, -1 do - local bullet = bullets[bulletIndex] + for bulletIndex = #state.bullets, 1, -1 do + local bullet = state.bullets[bulletIndex] bullet.timeLeft = bullet.timeLeft - dt if bullet.timeLeft <= 0 then - table.remove(bullets, bulletIndex) + table.remove(state.bullets, bulletIndex) else local bulletSpeed = 500 bullet.x = (bullet.x + math.cos(bullet.angle) * bulletSpeed * dt) % game.width bullet.y = (bullet.y + math.sin(bullet.angle) * bulletSpeed * dt) % game.height end - for asteroidIndex = #asteroids, 1, -1 do - local asteroid = asteroids[asteroidIndex] + 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(bullets, bulletIndex) + 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(asteroids, { + table.insert(state.asteroids, { x = asteroid.x, y = asteroid.y, angle = angle1, stage = asteroid.stage - 1, }) - table.insert(asteroids, { + table.insert(state.asteroids, { x = asteroid.x, y = asteroid.y, angle = angle2, stage = asteroid.stage - 1, }) end - table.remove(asteroids, asteroidIndex) + table.remove(state.asteroids, asteroidIndex) break end end end - bulletTimer = bulletTimer + dt + state.bulletTimer = state.bulletTimer + dt if love.keyboard.isDown('s') then - if bulletTimer >= game.ship.bullet.timerLimit then - bulletTimer = 0 - table.insert(bullets, { - x = shipX + math.cos(shipAngle) * game.ship.radius, - y = shipY + math.sin(shipAngle) * game.ship.radius, - angle = shipAngle, + 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 = 4, }) end end - for asteroidIndex, asteroid in ipairs(asteroids) do + 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(shipX, shipY, game.ship.radius, asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) then + 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 #asteroids == 0 then + if #state.asteroids == 0 then reset() end end @@ -151,22 +166,22 @@ function love.draw() love.graphics.origin() love.graphics.translate(x * game.width, y * game.height) love.graphics.setColor(0, 0, 1) - love.graphics.circle('fill', shipX, shipY, game.ship.radius) + 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', - shipX + math.cos(shipAngle) * shipCircleDistance, - shipY + math.sin(shipAngle) * shipCircleDistance, + state.ship.x + math.cos(state.ship.angle) * shipCircleDistance, + state.ship.y + math.sin(state.ship.angle) * shipCircleDistance, 5 ) - for _, bullet in ipairs(bullets) do + 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(asteroids) do + 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