Created
August 6, 2019 04:45
-
-
Save clarityflowers/ba770128eb473c7c2e3819ee6686d331 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Invaders! | |
-- A simple little "game" for an interview for the recurse center. | |
-- Runs uses Löve2d. | |
-- Download Löve at https://love2d.org/#download, | |
-- To run the game, rename it to "main.lua" and put it in its own folder. | |
-- Then navigate to that folder and run "love ." | |
-- All the state lives in one object. | |
-- I find that having this beforehand opens up possibilities | |
-- in the future that I always appreciate. | |
local state | |
-- CONSTANTS -- | |
-- To gracefully handle screen-resizing, I'm using an abstract | |
-- units system that defines the game world as 100 units wide with | |
-- 5 units of padding on either side. | |
-- When drawing this will be scaled to the appropriate size. | |
local WORLD_WIDTH = 100 | |
local WORLD_PADDING = 5 | |
local FULL_WORLD_WIDTH = WORLD_WIDTH + WORLD_PADDING * 2 | |
local WORLD_HEIGHT_RATIO = 0.7 | |
local FULL_WORLD_HEIGHT = FULL_WORLD_WIDTH * WORLD_HEIGHT_RATIO | |
local WORLD_HEIGHT = FULL_WORLD_HEIGHT - WORLD_PADDING * 2 | |
local PLAYER_RADIUS = 3 | |
local PLAYER_SPEED = 30.0 | |
local INVADER_RADIUS = 2 | |
local INVADER_SPACING = INVADER_RADIUS * 2 + 2 | |
local INVADER_SPEED = 10.0 | |
-- Initialize the game | |
function love.load() | |
-- Set up the window to fit in the top-right corner of | |
-- my screen. Convenient for testing! | |
love.window.setMode(666, 666 * WORLD_HEIGHT_RATIO, { | |
borderless = true, | |
centered = false, | |
x = 610, | |
y = 0 | |
}) | |
state = { | |
player = { | |
x = 50.0, | |
moving_left = false, | |
moving_right = false | |
}, | |
-- The invaders move as a unit, so they have a shared state | |
invaders = { | |
moving_right = true, | |
x = INVADER_RADIUS, | |
alive = {} | |
} | |
} | |
-- Assuming that they'll be able to be killed later, there's a 2D | |
-- array of booleans indicating Invader "alive" status. Maybe this | |
-- will want to be a full state object for each at some point! idk! | |
for _ = 1, 4, 1 do | |
local invader_row = {} | |
for _ = 1, 10, 1 do | |
table.insert(invader_row, true) | |
end | |
table.insert(state.invaders.alive, invader_row) | |
end | |
end | |
function love.keypressed(key) | |
if not state then return end | |
if key == "left" then | |
state.player.moving_left = true | |
elseif key == "right" then | |
state.player.moving_right = true | |
end | |
end | |
function love.keyreleased(key) | |
if not state then return end | |
if key == "left" then | |
state.player.moving_left = false | |
elseif key == "right" then | |
state.player.moving_right = false | |
end | |
end | |
function love.update(dt) | |
-- INVADER MOVEMENT -- | |
local invaders = state.invaders | |
local invaders_count = #invaders.alive[1] | |
-- Change direction when we hit the right or left edge | |
if invaders.moving_right then | |
local right_edge = invaders.x + INVADER_SPACING * (invaders_count - 1) + INVADER_RADIUS | |
if right_edge >= WORLD_WIDTH then | |
invaders.moving_right = false | |
end | |
else | |
local left_edge = invaders.x - INVADER_RADIUS | |
if left_edge <= 0 then | |
invaders.moving_right = true | |
end | |
end | |
-- Move the appropriate direction | |
if invaders.moving_right then | |
invaders.x = invaders.x + dt * INVADER_SPEED | |
else | |
invaders.x = invaders.x - dt * INVADER_SPEED | |
end | |
-- PLAYER MOVEMENT -- | |
local player = state.player | |
if player.moving_left then | |
player.x = math.max(player.x - dt * PLAYER_SPEED, PLAYER_RADIUS) | |
elseif player.moving_right then | |
player.x = math.min(player.x + dt * PLAYER_SPEED, WORLD_WIDTH - PLAYER_RADIUS) | |
end | |
end | |
-- Converts our abstract units to pixels | |
local function world_to_screen_distance(world_distance) | |
local screen_width = love.graphics.getWidth() | |
return world_distance * screen_width / FULL_WORLD_WIDTH | |
end | |
-- Converts a location in the world to a pixel-unit vector | |
-- padded by the world padding | |
local function world_location_to_screen(world_vector) | |
return { | |
world_to_screen_distance(world_vector[1] + WORLD_PADDING), | |
world_to_screen_distance(world_vector[2] + WORLD_PADDING) | |
} | |
end | |
function love.draw() | |
-- INVADERS -- | |
for row_i, row in pairs(state.invaders.alive) do | |
for col_i, alive in pairs(row) do | |
if alive then | |
local pos = world_location_to_screen({ | |
state.invaders.x + INVADER_SPACING * (col_i - 1), | |
INVADER_RADIUS + INVADER_SPACING * (row_i - 1) | |
}) | |
love.graphics.circle( | |
"line", | |
pos[1], | |
pos[2], | |
world_to_screen_distance(INVADER_RADIUS) | |
) | |
end | |
end | |
end | |
-- PLAYER -- | |
local player_pos = world_location_to_screen({ | |
state.player.x, | |
WORLD_HEIGHT | |
}) | |
local player_radius = world_to_screen_distance(PLAYER_RADIUS) | |
love.graphics.polygon( | |
"line", | |
player_pos[1] - player_radius, player_pos[2], | |
player_pos[1] + player_radius, player_pos[2], | |
player_pos[1], player_pos[2] - (player_radius * 2) | |
) | |
-- DEBUG -- | |
-- show the edge of the padded world, to check if things are | |
-- lining up right | |
-- local world_top_left = world_location_to_screen({0, 0}) | |
-- love.graphics.rectangle( | |
-- "line", | |
-- world_top_left[1], | |
-- world_top_left[2], | |
-- world_to_screen_distance(WORLD_WIDTH), | |
-- world_to_screen_distance(WORLD_HEIGHT) | |
-- ) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment