coalesce state

This commit is contained in:
Donald Ball 2025-11-14 21:27:55 -05:00
parent 46dc6d16f6
commit 9f78b280cd

View file

@ -24,16 +24,8 @@ end
local game = initGame() local game = initGame()
function love.load() local function initState()
function reset() local asteroids = {
shipX = game.width / 2
shipY = game.height / 2
shipAngle = 0
shipSpeedX = 0
shipSpeedY = 0
bullets = {}
bulletTimer = game.ship.bullet.timerLimit
asteroids = {
{ {
x = 100, x = 100,
y = 100, y = 100,
@ -51,96 +43,119 @@ function love.load()
asteroid.angle = love.math.random() * (2 * math.pi) asteroid.angle = love.math.random() * (2 * math.pi)
asteroid.stage = #game.asteroids.stages asteroid.stage = #game.asteroids.stages
end end
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() reset()
end end
function love.update(dt) function love.update(dt)
local turnSpeed = 10 local turnSpeed = 10
if love.keyboard.isDown('right') then if love.keyboard.isDown('right') then
shipAngle = shipAngle + turnSpeed * dt state.ship.angle = state.ship.angle + turnSpeed * dt
end end
if love.keyboard.isDown('left') then if love.keyboard.isDown('left') then
shipAngle = shipAngle - turnSpeed * dt state.ship.angle = state.ship.angle - turnSpeed * dt
end end
shipAngle = shipAngle % (2 * math.pi) state.ship.angle = state.ship.angle % (2 * math.pi)
if love.keyboard.isDown('up') then if love.keyboard.isDown('up') then
local shipSpeed = 100 local shipSpeed = 100
shipSpeedX = shipSpeedX + math.cos(shipAngle) * shipSpeed * dt state.ship.speed.x = state.ship.speed.x + math.cos(state.ship.angle) * shipSpeed * dt
shipSpeedY = shipSpeedY + math.sin(shipAngle) * shipSpeed * dt state.ship.speed.y = state.ship.speed.y + math.sin(state.ship.angle) * shipSpeed * dt
end end
shipX = (shipX + shipSpeedX * dt) % game.width state.ship.x = (state.ship.x + state.ship.speed.x * dt) % game.width
shipY = (shipY + shipSpeedY * dt) % game.height state.ship.y = (state.ship.y + state.ship.speed.y * dt) % game.height
local function areCirclesIntersecting(aX, aY, aRadius, bX, bY, bRadius) local function areCirclesIntersecting(aX, aY, aRadius, bX, bY, bRadius)
return (aX - bX) ^ 2 + (aY - bY) ^ 2 <= (aRadius + bRadius) ^ 2 return (aX - bX) ^ 2 + (aY - bY) ^ 2 <= (aRadius + bRadius) ^ 2
end end
for bulletIndex = #bullets, 1, -1 do for bulletIndex = #state.bullets, 1, -1 do
local bullet = bullets[bulletIndex] local bullet = state.bullets[bulletIndex]
bullet.timeLeft = bullet.timeLeft - dt bullet.timeLeft = bullet.timeLeft - dt
if bullet.timeLeft <= 0 then if bullet.timeLeft <= 0 then
table.remove(bullets, bulletIndex) table.remove(state.bullets, bulletIndex)
else else
local bulletSpeed = 500 local bulletSpeed = 500
bullet.x = (bullet.x + math.cos(bullet.angle) * bulletSpeed * dt) % game.width bullet.x = (bullet.x + math.cos(bullet.angle) * bulletSpeed * dt) % game.width
bullet.y = (bullet.y + math.sin(bullet.angle) * bulletSpeed * dt) % game.height bullet.y = (bullet.y + math.sin(bullet.angle) * bulletSpeed * dt) % game.height
end end
for asteroidIndex = #asteroids, 1, -1 do for asteroidIndex = #state.asteroids, 1, -1 do
local asteroid = asteroids[asteroidIndex] 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 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 if asteroid.stage > 1 then
local angle1 = love.math.random() * (2 * math.pi) local angle1 = love.math.random() * (2 * math.pi)
local angle2 = (angle1 - math.pi) % (2 * math.pi) local angle2 = (angle1 - math.pi) % (2 * math.pi)
table.insert(asteroids, { table.insert(state.asteroids, {
x = asteroid.x, x = asteroid.x,
y = asteroid.y, y = asteroid.y,
angle = angle1, angle = angle1,
stage = asteroid.stage - 1, stage = asteroid.stage - 1,
}) })
table.insert(asteroids, { table.insert(state.asteroids, {
x = asteroid.x, x = asteroid.x,
y = asteroid.y, y = asteroid.y,
angle = angle2, angle = angle2,
stage = asteroid.stage - 1, stage = asteroid.stage - 1,
}) })
end end
table.remove(asteroids, asteroidIndex) table.remove(state.asteroids, asteroidIndex)
break break
end end
end end
end end
bulletTimer = bulletTimer + dt state.bulletTimer = state.bulletTimer + dt
if love.keyboard.isDown('s') then if love.keyboard.isDown('s') then
if bulletTimer >= game.ship.bullet.timerLimit then if state.bulletTimer >= game.ship.bullet.timerLimit then
bulletTimer = 0 state.bulletTimer = 0
table.insert(bullets, { table.insert(state.bullets, {
x = shipX + math.cos(shipAngle) * game.ship.radius, x = state.ship.x + math.cos(state.ship.angle) * game.ship.radius,
y = shipY + math.sin(shipAngle) * game.ship.radius, y = state.ship.y + math.sin(state.ship.angle) * game.ship.radius,
angle = shipAngle, angle = state.ship.angle,
timeLeft = 4, timeLeft = 4,
}) })
end end
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) % asteroid.x = (asteroid.x + math.cos(asteroid.angle) * game.asteroids.stages[asteroid.stage].speed * dt) %
game.width game.width
asteroid.y = (asteroid.y + math.sin(asteroid.angle) * game.asteroids.stages[asteroid.stage].speed * dt) % asteroid.y = (asteroid.y + math.sin(asteroid.angle) * game.asteroids.stages[asteroid.stage].speed * dt) %
game.height 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() reset()
break break
end end
end end
if #asteroids == 0 then if #state.asteroids == 0 then
reset() reset()
end end
end end
@ -151,22 +166,22 @@ function love.draw()
love.graphics.origin() love.graphics.origin()
love.graphics.translate(x * game.width, y * game.height) love.graphics.translate(x * game.width, y * game.height)
love.graphics.setColor(0, 0, 1) 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 local shipCircleDistance = 20
love.graphics.setColor(0, 1, 1) love.graphics.setColor(0, 1, 1)
love.graphics.circle( love.graphics.circle(
'fill', 'fill',
shipX + math.cos(shipAngle) * shipCircleDistance, state.ship.x + math.cos(state.ship.angle) * shipCircleDistance,
shipY + math.sin(shipAngle) * shipCircleDistance, state.ship.y + math.sin(state.ship.angle) * shipCircleDistance,
5 5
) )
for _, bullet in ipairs(bullets) do for _, bullet in ipairs(state.bullets) do
love.graphics.setColor(0, 1, 0) love.graphics.setColor(0, 1, 0)
love.graphics.circle('fill', bullet.x, bullet.y, game.ship.bullet.radius) love.graphics.circle('fill', bullet.x, bullet.y, game.ship.bullet.radius)
end end
for _, asteroid in ipairs(asteroids) do for _, asteroid in ipairs(state.asteroids) do
love.graphics.setColor(1, 1, 0) love.graphics.setColor(1, 1, 0)
love.graphics.circle('fill', asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) love.graphics.circle('fill', asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius)
end end