From 255283455e200af063833db21c74fbd3cb507532 Mon Sep 17 00:00:00 2001 From: Tangent Date: Thu, 27 Nov 2025 15:51:29 -0700 Subject: [PATCH] prep for stage 3 --- src/main.lua | 194 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 143 insertions(+), 51 deletions(-) diff --git a/src/main.lua b/src/main.lua index 653cdbd..a6d6c2f 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,6 +1,60 @@ local screen_width, screen_height = love.graphics.getDimensions() math.randomseed(os.time()) +-- 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) + local selected_object, distance_squared_to_object = 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_squared = (current_object.position_x - comparison_object.position_x)^2 + (current_object.position_y - comparison_object.position_y)^2 + if comparison_distance_squared < distance_squared_to_object then + selected_object = comparison_object + distance_squared_to_object = comparison_distance_squared + end + end + compare_object() + end + + return selected_object, distance_squared_to_object +end + +-- returns cargo_amount (actual amount transferred) +local function transfer_cargo(source_object, destination_object, cargo_type, cargo_amount) + if not source_object.cargo_contents[cargo_type] then + return 0 + end + if not destination_object.cargo_contents[cargo_type] then + destination_object.cargo_contents[cargo_type] = 0 + end + + cargo_amount = math.min(cargo_amount, source_object.cargo_contents[cargo_type]) + destination_object.cargo_contents[cargo_type] = destination_object.cargo_contents[cargo_type] + cargo_amount + destination_object.cargo_free_space = destination_object.cargo_free_space - cargo_amount + source_object.cargo_contents[cargo_type] = source_object.cargo_contents[cargo_type] - cargo_amount + source_object.cargo_free_space = source_object.cargo_free_space + cargo_amount + + if source_object.cargo_contents[cargo_type] <= 0 then + source_object.cargo_contents[cargo_type] = nil + end + + return cargo_amount +end + +-- The resources collected by the player can be spent on something, +-- like improving the ship. Speed, capacity, collection speed, etc. +-- TODO future upgrade: range upgrade ? +-- right now: iron -> caoacity, copper -> acceleration + +local cargo_types = { "iron ore", "copper ore", } + +-- TODO review my previous orbits code to add extremely slow background orbits to this +-- planets/stars/stations always have fixed orbits; ships have a fixed orbital acceleration but have their own additional +-- the "zero relative velocity" key will be a burn whatever amount of fuel/acceleration necessary to match local acceleration +-- which.. since the currently stored velocity is a COMPLETELY SEPARATE SYSTEM - is literally just zeroing velocity which makes it even simpler to execute local player_ship = { position_x = screen_width / 2, position_y = screen_height / 2, @@ -10,35 +64,53 @@ local player_ship = { radar_size = 10, + cargo_max_space = 100, cargo_free_space = 100, cargo_contents = {}, cargo_fill_speed = 10, + + -- TODO fuel capacity and use (idle and while acceleration) + -- TODO cargo / mass affects acceleration } local resource_points = {} -- NOTE they're "planets" but I intend for them to be multiple things tbh -for i = 1, 3 do - local resource_point = { - position_x = math.random() * screen_width, - position_y = math.random() * screen_height, - radar_size = 10, +local function spawn_3_points() + for i = 1, 3 do + local function make_resource_point() + local current_point = { + position_x = math.random() * screen_width, + position_y = math.random() * screen_height, + radar_size = 10, - cargo_free_space = 100000, - cargo_contents = {}, - } + cargo_max_space = 100000, + cargo_free_space = 100000, + cargo_contents = {}, + } - local cargo_types = { "iron ore", "copper ore", } -- TODO use a proper enumeration - local selected_type = cargo_types[math.random(2)] - local cargo_amount = math.random() * 10000 - -- TODO utility function to handle transferring cargo - resource_point.cargo_contents[selected_type] = cargo_amount - resource_point.cargo_free_space = resource_point.cargo_free_space - cargo_amount + -- NOTE can select literally anything + local selected_type = cargo_types[math.random(#cargo_types)] + local cargo_amount = math.random() * 10000 + transfer_cargo({ cargo_contents = { [selected_type] = cargo_amount, }, cargo_free_space = 0, }, current_point, selected_type, cargo_amount) - -- TODO make sure it is not placed on top of another one or too close - table.insert(resource_points, resource_point) + 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 + return + end + + table.insert(resource_points, current_point) + return true + end + + if not make_resource_point() then + i = i - 1 + end + end end +spawn_3_points() local last_message = "" function love.update(dt) + -- NOTE this control scheme makes diagonal travel faster than horizontal/vertical if love.keyboard.isDown("w") then player_ship.velocity_y = player_ship.velocity_y - player_ship.acceleration * dt end @@ -52,52 +124,59 @@ function love.update(dt) player_ship.velocity_x = player_ship.velocity_x + player_ship.acceleration * dt end + -- NOTE this zeros out diagonal velocities faster than horizontal/vertical + if love.keyboard.isDown("x") then + if player_ship.velocity_x > 0 then + player_ship.velocity_x = math.max(0, player_ship.velocity_x - player_ship.acceleration * dt) + elseif player_ship.velocity_x < 0 then + player_ship.velocity_x = math.min(0, player_ship.velocity_x + player_ship.acceleration * dt) + end + + if player_ship.velocity_y > 0 then + player_ship.velocity_y = math.max(0, player_ship.velocity_y - player_ship.acceleration * dt) + elseif player_ship.velocity_y < 0 then + player_ship.velocity_y = math.min(0, player_ship.velocity_y + player_ship.acceleration * dt) + end + end + player_ship.position_x = player_ship.position_x + player_ship.velocity_x * dt player_ship.position_y = player_ship.position_y + player_ship.velocity_y * dt - -- TODO there needs to be a way to zero out relative velocity? (I don't think so yet) - if love.keyboard.isDown("space") then - -- TODO this whole thing should be a function, especially cause it uses return shortcutting - local selected_point, distance_to_point_squared = nil, math.huge - for i = 1, #resource_points do - local resource_point = resource_points[i] - local distance_squared = (player_ship.position_x - resource_point.position_x)^2 + (player_ship.position_y - resource_point.position_y)^2 - if distance_squared < distance_to_point_squared then - selected_point = resource_point - distance_to_point_squared = distance_squared + local function collect_resource() + local closest_object, distance_squared_to_object = get_closest_object(resource_points, player_ship) + -- TODO ideally, there should be an indicator that you're close enough instead of relying on messages (to be fair, the radius is the indicator) + if distance_squared_to_object > closest_object.radar_size^2 then + last_message = "Too far to pick up cargo." + return end + if player_ship.cargo_free_space <= 0 then + last_message = "No cargo space left." + return + end + -- TODO allow selecting cargo type + local cargo_type = next(closest_object.cargo_contents) + if not cargo_type then + last_message = "There is nothing here." + return + end + local cargo_amount = math.min(player_ship.cargo_fill_speed * dt, closest_object.cargo_contents[cargo_type]) + if cargo_amount <= 0 then + last_message = "There is no cargo to pick up." + return + end + + cargo_amount = transfer_cargo(closest_object, player_ship, cargo_type, cargo_amount) + last_message = "Transfered " .. math.floor(cargo_amount * 100) / 100 .. " " .. cargo_type .. "." end - -- TODO ideally, there should be an indicator that you're close enough instead of relying on messages (to be fair, the radius is the indicator) - if distance_to_point_squared > selected_point.radar_size^2 then - last_message = "Too far to pick up cargo." - return - end - -- TODO there should be a persistent indicator of cargo capacity and how full it is - if player_ship.cargo_free_space <= 0 then - last_message = "No cargo space left." - return - end - local cargo_type = next(selected_point.cargo_contents) -- TODO handle the possibility of this being empty - local cargo_amount = math.min(player_ship.cargo_fill_speed * dt, selected_point.cargo_contents[cargo_type]) - if cargo_amount <= 0 then - last_message = "There is no cargo to pick up." - return - end - if not player_ship.cargo_contents[cargo_type] then - player_ship.cargo_contents[cargo_type] = 0 - end - player_ship.cargo_contents[cargo_type] = player_ship.cargo_contents[cargo_type] + cargo_amount - player_ship.cargo_free_space = player_ship.cargo_free_space - cargo_amount - selected_point.cargo_contents[cargo_type] = selected_point.cargo_contents[cargo_type] - cargo_amount - selected_point.cargo_free_space = selected_point.cargo_free_space + cargo_amount - last_message = "Transfered " .. cargo_amount .. " " .. cargo_type .. "." + collect_resource() end end +local font = love.graphics.getFont() +local font_height = font:getHeight() function love.draw() love.graphics.setColor(1, 1, 1, 1) - love.graphics.print(last_message, 1, 1) 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) @@ -105,6 +184,19 @@ function love.draw() local resource_point = resource_points[i] love.graphics.circle("line", resource_point.position_x, resource_point.position_y, resource_point.radar_size) end + + love.graphics.print(last_message, 1, 1) + + local inventory_status = {} + for cargo_type, cargo_amount in pairs(player_ship.cargo_contents) do + table.insert(inventory_status, { cargo_type = cargo_type, cargo_amount = cargo_amount }) + end + table.sort(inventory_status, function(A, B) return A.cargo_amount > B.cargo_amount end) + for i = 1, #inventory_status do + inventory_status[i] = inventory_status[i].cargo_type .. ": " .. math.floor(inventory_status[i].cargo_amount * 10) / 10 + end + local cargo_message = "Cargo: " .. math.min(math.floor((player_ship.cargo_max_space - player_ship.cargo_free_space) * 10) / 10, player_ship.cargo_max_space) .. "/" .. player_ship.cargo_max_space .. ". " .. table.concat(inventory_status, ", ") + love.graphics.print(cargo_message, 1, screen_height - font_height - 1) end function love.keypressed(key)