diff --git a/src/main.lua b/src/main.lua index 19779aa..137f27f 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,6 +1,8 @@ local screen_width, screen_height = 960, 540 love.window.setMode(screen_width, screen_height) -math.randomseed(os.time()) +love.math.setRandomSeed(os.time()) + +-- TODO make an object generator that adds all required properties with a default value -- returns selected_object, distance_squared_to_object (if object_list is empty, returns nil, math.huge) local function get_closest_object(object_list, current_object) @@ -23,6 +25,28 @@ local function get_closest_object(object_list, current_object) return selected_object, distance_squared_to_object end +-- returns selected_object, distance_to_orbit (if object_list is empty, returns nil, math.huge) +-- object_list must be of objects orbiting the same parent_object or results will be wrong +local function get_closest_orbit(object_list, current_object) + local selected_object, distance_to_orbit = nil, math.huge + for i = 1, #object_list do + local function compare_object() + local comparison_object = object_list[i] + if comparison_object == current_object then + return + end + local comparison_distance = math.abs(current_object.orbital_radius - comparison_object.orbital_radius) + if comparison_distance < distance_to_orbit then + selected_object = comparison_object + distance_to_orbit = comparison_distance + end + end + compare_object() + end + + return selected_object, distance_to_orbit +end + -- source_object and destination_object can be nil to create/delete resources -- returns cargo_amount (actual amount transferred) local function transfer_cargo(source_object, destination_object, cargo_type, cargo_amount) @@ -33,9 +57,13 @@ local function transfer_cargo(source_object, destination_object, cargo_type, car destination_object = { cargo_contents = {}, cargo_free_space = math.huge, } end - if not source_object.cargo_contents[cargo_type] then + if (not source_object.cargo_contents) or (not source_object.cargo_contents[cargo_type]) then return 0 end + if not destination_object.cargo_contents then + destination_object.cargo_contents = {} + destination_object.cargo_free_space = 0 + end if not destination_object.cargo_contents[cargo_type] then destination_object.cargo_contents[cargo_type] = 0 end @@ -55,11 +83,17 @@ local function transfer_cargo(source_object, destination_object, cargo_type, car if source_object.cargo_contents[cargo_type] <= 0 then source_object.cargo_contents[cargo_type] = nil end + if destination_object.cargo_contents[cargo_type] <= 0 then + destination_object.cargo_contents[cargo_type] = nil + end return cargo_amount end local function check_cargo_amount(source_object, cargo_type, cargo_amount) + if not source_object.cargo_contents then + return false + end if not source_object.cargo_contents[cargo_type] then return false end @@ -70,13 +104,6 @@ local function check_cargo_amount(source_object, cargo_type, cargo_amount) end local ore_types = { "iron ore", "copper ore", "warp fuel", } --- local cargo_types = {} --- for i = 1, #ore_types do --- cargo_types[#cargo_types + 1] = ore_types[i] --- end --- for i = 1, #cargo_types do --- cargo_types[cargo_types[i]] = i --- end local player_ship = { position_x = 100, @@ -99,32 +126,37 @@ local player_ship = { } player_ship.orbital_radius = math.sqrt(player_ship.position_x^2 + player_ship.position_y^2) +-- TODO this just needs to be a list of all objects - including the player local resource_points = {} -- NOTE they're "planets" but I intend for them to be multiple things tbh local function make_resource_point(x, y) - local current_point = { - position_x = x or math.random() * screen_width / 2, - position_y = y or math.random() * screen_height / 2, + local current_object = { + position_x = x or love.math.random() * screen_width / 2, + position_y = y or love.math.random() * screen_height / 2, radar_size = 7, cargo_max_space = 100000, cargo_free_space = 100000, cargo_contents = {}, } - -- TODO exclude orbits that would collide - current_point.orbital_radius = math.sqrt(current_point.position_x^2 + current_point.position_y^2) - current_point.rotation_offset = math.atan2(current_point.position_y, current_point.position_x) - - -- NOTE can select literally anything - local selected_type = ore_types[math.random(#ore_types)] - local cargo_amount = math.random() * 10000 - transfer_cargo(nil, current_point, selected_type, cargo_amount) - - local closest_object, distance_squared_to_object = get_closest_object(resource_points, current_point) - if closest_object and distance_squared_to_object <= (closest_object.radar_size^2 + current_point.radar_size^2) * 1.5 then + current_object.orbital_radius = math.sqrt(current_object.position_x^2 + current_object.position_y^2) + -- pretty sure this offset is only correct because game_time starts at 0 + current_object.rotation_offset = math.atan2(current_object.position_y, current_object.position_x) + -- exclude orbits that would collide + local closest_object, distance_to_orbit = get_closest_orbit(resource_points, current_object) + if closest_object and distance_to_orbit <= (closest_object.radar_size + current_object.radar_size) * 1.5 then return end - table.insert(resource_points, current_point) + local selected_type = ore_types[love.math.random(#ore_types)] + local cargo_amount = love.math.random() * 10000 + transfer_cargo(nil, current_object, selected_type, cargo_amount) + + local closest_object, distance_squared_to_object = get_closest_object(resource_points, current_object) + if closest_object and distance_squared_to_object <= (closest_object.radar_size^2 + current_object.radar_size^2) * 1.5 then + return + end + + table.insert(resource_points, current_object) return true end @@ -135,19 +167,40 @@ local function add_resource_points(point_count) end end end --- add_resource_points(8) +add_resource_points(8) -- DEBUG hardcoded points to compare against (except they can still fail to spawn if something else is too close) -make_resource_point(10, 0) +make_resource_point(15, 0) make_resource_point(screen_width / 2 - 10, 0) +-- NOTE this object doesn't have "necessary" values because it isn't in resource_points +local core_object = { + position_x = 0, position_y = 0, orbital_radius = 0, radar_size = 7, rotation_offset = 0, + children = resource_points, -- TEMP all objects are orbitng the core_object +} + local last_message = "" local game_time = 0 --- local orbital_speed_constant = 1 -- ironically, I think 1 is exactly the speed I want +-- local orbital_speed_constant = 1 -- ironically, I think 1 is exactly the speed I want (that was before the new orbit system) local orbital_speed_constant = 50 function love.update(dt) game_time = game_time + dt + local update_object_position + update_object_position = function(current_object, parent_x, parent_y, parent_mass) + local argument = game_time / current_object.orbital_radius^1.337 * orbital_speed_constant * parent_mass + current_object.rotation_offset + if (argument == math.huge) or (argument ~= argument) then + argument = 0 + end + current_object.position_x, current_object.position_y = parent_x + current_object.orbital_radius * math.cos(argument), parent_y + current_object.orbital_radius * math.sin(argument) + if current_object.children then + for i = 1, #current_object.children do + update_object_position(current_object.children[i], current_object.position_x, current_object.position_y, current_object.radar_size^2) + end + end + end + update_object_position(core_object, 0, 0, 0) + -- NOTE this control scheme makes diagonal travel faster than horizontal/vertical if love.keyboard.isDown("w") or love.keyboard.isDown("up") then player_ship.velocity_y = player_ship.velocity_y - player_ship.acceleration * dt @@ -187,21 +240,6 @@ function love.update(dt) player_ship.position_x = x * player_ship.orbital_radius player_ship.position_y = y * player_ship.orbital_radius - for i = 1, #resource_points do - local current_point = resource_points[i] - local x, y = math.cos(game_time / current_point.orbital_radius / (1 / orbital_speed_constant) + current_point.rotation_offset), math.sin(game_time / current_point.orbital_radius / (1 / orbital_speed_constant) + current_point.rotation_offset) - current_point.position_x = x * current_point.orbital_radius - current_point.position_y = y * current_point.orbital_radius - end - - -- NOTE this fails to account for parent movement I think? either way, it doesn't orbit correctly - -- local closest_object, distance_squared_to_object = get_closest_object(resource_points, player_ship) - -- player_ship.orbital_radius = math.sqrt(distance_squared_to_object) - -- local player_rotation_offset = math.atan2(player_ship.position_y - closest_object.position_y, player_ship.position_x - closest_object.position_x) - -- local x, y = math.cos(dt / player_ship.orbital_radius / (1 / orbital_speed_constant) + player_rotation_offset), math.sin(dt / player_ship.orbital_radius / (1 / orbital_speed_constant) + player_rotation_offset) - -- player_ship.position_x = x * player_ship.orbital_radius + closest_object.position_x - -- player_ship.position_y = y * player_ship.orbital_radius + closest_object.position_y - -- TODO make this toggleable instead of requiring holding a key if love.keyboard.isDown("space") then local function collect_resource() @@ -247,15 +285,20 @@ function love.draw() love.graphics.translate(camera_offset.x, camera_offset.y) love.graphics.rectangle("line", player_ship.position_x - player_ship.radar_size / 2, player_ship.position_y - player_ship.radar_size / 2, player_ship.radar_size, player_ship.radar_size) - for i = 1, #resource_points do - local current_point = resource_points[i] - love.graphics.circle("line", current_point.position_x, current_point.position_y, current_point.radar_size) - - -- TODO make this "behind" other objects (and toggleable? and a different color?) - love.graphics.circle("line", 0, 0, current_point.orbital_radius) - end love.graphics.circle("line", 0, 0, player_ship.orbital_radius) + local draw_object + draw_object = function(current_object, parent_x, parent_y) + love.graphics.circle("fill", current_object.position_x, current_object.position_y, math.max(current_object.radar_size, 0.8)) + love.graphics.circle("line", parent_x, parent_y, current_object.orbital_radius) + if current_object.children then + for i = 1, #current_object.children do + draw_object(current_object.children[i], current_object.position_x, current_object.position_y) + end + end + end + draw_object(core_object, 0, 0) + -- NOTE if player is orbiting another object -- local closest_object = get_closest_object(resource_points, player_ship) -- love.graphics.circle("line", closest_object.position_x, closest_object.position_y, player_ship.orbital_radius) @@ -309,6 +352,6 @@ function love.keypressed(key) player_ship.position_x = screen_width / 2 player_ship.position_y = screen_height / 2 resource_points = {} - add_resource_points(math.random(5)) + add_resource_points(love.math.random(5)) end end