lovexp/asteroids/main.lua

203 lines
6.5 KiB
Lua
Raw Normal View History

2025-11-12 21:31:35 -05:00
local love = require("love")
2025-11-14 21:06:24 -05:00
local function initGame()
return {
width = 800,
height = 600,
ship = {
2025-11-14 17:10:40 -05:00
radius = 30,
2025-11-14 21:06:24 -05:00
bullet = {
radius = 5,
2025-11-14 21:38:46 -05:00
speed = 500,
time = 4,
2025-11-15 20:46:59 -05:00
sound = love.sound.newSoundData('resources/bullet.mp3'),
2025-11-14 21:35:05 -05:00
},
2025-11-15 20:32:13 -05:00
-- 99x75
sprite = love.graphics.newImage('resources/ship.png'),
2025-11-14 16:33:24 -05:00
},
2025-11-14 21:06:24 -05:00
asteroids = {
stages = {
{ speed = 120, radius = 15 },
{ speed = 70, radius = 30 },
{ speed = 50, radius = 50 },
{ speed = 20, radius = 80 },
},
2025-11-14 17:10:40 -05:00
},
2025-11-14 21:35:05 -05:00
controls = {
ship = {
turnRate = 10,
maxThrust = 200,
2025-11-14 21:35:05 -05:00
},
},
2025-11-14 16:33:24 -05:00
}
2025-11-14 21:06:24 -05:00
end
2025-11-14 17:10:40 -05:00
2025-11-14 21:06:24 -05:00
local game = initGame()
2025-11-14 21:27:55 -05:00
local function initState()
local asteroids = {
{
x = 100,
y = 100,
},
{
x = game.width - 100,
y = 100,
},
{
x = game.width / 2,
y = game.height - 100,
2025-11-14 17:10:40 -05:00
}
2025-11-14 21:27:55 -05:00
}
for _, asteroid in ipairs(asteroids) do
asteroid.angle = love.math.random() * (2 * math.pi)
asteroid.stage = #game.asteroids.stages
2025-11-14 16:33:24 -05:00
end
local joystick = nil
if love.joystick.getJoystickCount() == 1 then
joystick = love.joystick.getJoysticks()[1]
end
2025-11-14 21:27:55 -05:00
return {
ship = {
x = game.width / 2,
y = game.height / 2,
2025-11-15 20:32:13 -05:00
angle = 3 * math.pi / 2,
2025-11-14 21:27:55 -05:00
speed = {
x = 0,
y = 0,
}
},
bullets = {},
asteroids = asteroids,
controls = {
joystick = joystick,
}
2025-11-14 21:27:55 -05:00
}
end
local state = {}
local function reset()
state = initState()
end
function love.load()
2025-11-14 17:10:40 -05:00
reset()
2025-11-12 21:35:42 -05:00
end
2025-11-12 21:31:35 -05:00
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
2025-11-15 16:29:07 -05:00
local spin = state.controls.joystick:getGamepadAxis('leftx') * game.controls.ship.turnRate
state.ship.angle = (state.ship.angle + spin * dt) % (2 * math.pi)
2025-11-12 21:31:35 -05:00
end
2025-11-14 21:27:55 -05:00
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
2025-11-13 16:29:57 -05:00
2025-11-14 16:50:50 -05:00
local function areCirclesIntersecting(aX, aY, aRadius, bX, bY, bRadius)
return (aX - bX) ^ 2 + (aY - bY) ^ 2 <= (aRadius + bRadius) ^ 2
end
2025-11-14 21:27:55 -05:00
for bulletIndex = #state.bullets, 1, -1 do
local bullet = state.bullets[bulletIndex]
2025-11-13 16:35:51 -05:00
bullet.timeLeft = bullet.timeLeft - dt
if bullet.timeLeft <= 0 then
2025-11-14 21:27:55 -05:00
table.remove(state.bullets, bulletIndex)
2025-11-13 16:35:51 -05:00
else
2025-11-14 21:38:46 -05:00
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
2025-11-13 16:35:51 -05:00
end
2025-11-14 21:27:55 -05:00
for asteroidIndex = #state.asteroids, 1, -1 do
local asteroid = state.asteroids[asteroidIndex]
2025-11-14 21:06:24 -05:00
if areCirclesIntersecting(bullet.x, bullet.y, game.ship.bullet.radius, asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) then
2025-11-14 21:27:55 -05:00
table.remove(state.bullets, bulletIndex)
2025-11-14 17:10:40 -05:00
if asteroid.stage > 1 then
local angle1 = love.math.random() * (2 * math.pi)
local angle2 = (angle1 - math.pi) % (2 * math.pi)
2025-11-14 21:27:55 -05:00
table.insert(state.asteroids, {
2025-11-14 17:10:40 -05:00
x = asteroid.x,
y = asteroid.y,
angle = angle1,
stage = asteroid.stage - 1,
})
2025-11-14 21:27:55 -05:00
table.insert(state.asteroids, {
2025-11-14 17:10:40 -05:00
x = asteroid.x,
y = asteroid.y,
angle = angle2,
stage = asteroid.stage - 1,
})
end
2025-11-14 21:27:55 -05:00
table.remove(state.asteroids, asteroidIndex)
2025-11-14 16:50:50 -05:00
break
end
end
2025-11-13 16:29:57 -05:00
end
2025-11-14 21:27:55 -05:00
for _, asteroid in ipairs(state.asteroids) do
2025-11-14 21:06:24 -05:00
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
2025-11-14 16:41:04 -05:00
2025-11-14 21:27:55 -05:00
if areCirclesIntersecting(state.ship.x, state.ship.y, game.ship.radius, asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius) then
2025-11-14 17:10:40 -05:00
reset()
2025-11-14 16:41:04 -05:00
break
end
2025-11-14 16:33:24 -05:00
end
2025-11-14 17:10:40 -05:00
2025-11-14 21:27:55 -05:00
if #state.asteroids == 0 then
2025-11-14 17:10:40 -05:00
reset()
end
2025-11-12 21:31:35 -05:00
end
2025-11-15 16:42:02 -05:00
function love.gamepadpressed(joystick, button)
if joystick ~= state.controls.joystick then
return
end
if button == "b" then
-- debounce, perhaps
2025-11-15 20:46:59 -05:00
local bullet = {
2025-11-15 16:42:02 -05:00
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,
2025-11-15 20:46:59 -05:00
sound = love.audio.newSource(game.ship.bullet.sound),
}
table.insert(state.bullets, bullet)
bullet.sound:play()
2025-11-15 16:42:02 -05:00
end
end
2025-11-12 21:31:35 -05:00
function love.draw()
for y = -1, 1 do
for x = -1, 1 do
love.graphics.origin()
2025-11-14 21:06:24 -05:00
love.graphics.translate(x * game.width, y * game.height)
2025-11-15 20:32:13 -05:00
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
2025-11-12 21:31:35 -05:00
)
2025-11-12 21:35:42 -05:00
2025-11-14 21:27:55 -05:00
for _, bullet in ipairs(state.bullets) do
2025-11-12 21:35:42 -05:00
love.graphics.setColor(0, 1, 0)
2025-11-14 21:06:24 -05:00
love.graphics.circle('fill', bullet.x, bullet.y, game.ship.bullet.radius)
2025-11-12 21:35:42 -05:00
end
2025-11-14 16:33:24 -05:00
2025-11-14 21:27:55 -05:00
for _, asteroid in ipairs(state.asteroids) do
2025-11-14 16:33:24 -05:00
love.graphics.setColor(1, 1, 0)
2025-11-14 21:06:24 -05:00
love.graphics.circle('fill', asteroid.x, asteroid.y, game.asteroids.stages[asteroid.stage].radius)
2025-11-14 16:33:24 -05:00
end
2025-11-12 21:31:35 -05:00
end
end
end