Nicholas Hayashi
3 years ago
5 changed files with 1 additions and 299 deletions
-
3main.lua
-
89src/extra.lua
-
23src/geometry.lua
-
162src/gui.lua
-
23src/memory.lua
@ -1,89 +0,0 @@ |
|||
|
|||
-- utility functions that don't below elsewhere go here, |
|||
-- especially if they would be at home on the global 'math' or 'table' variables, or are otherwise extensions of standard lua features |
|||
-- try to avoid *too* much amulet specific stuff, but vector types are probably ok. |
|||
|
|||
function fprofile(f, ...) |
|||
local t1 = am.current_time() |
|||
local result = { f(...) } |
|||
local time = am.current_time() - t1 |
|||
--log("%f", time) |
|||
return time, unpack(result) |
|||
end |
|||
|
|||
function math.wrapf(float, range) |
|||
return float - range * math.floor(float / range) |
|||
end |
|||
|
|||
function math.lerp(v1, v2, t) |
|||
return v1 * t + v2 * (1 - t) |
|||
end |
|||
|
|||
-- don't use this with sparse arrays |
|||
function table.rchoice(t) |
|||
return t[math.floor(math.random() * #t) + 1] |
|||
end |
|||
|
|||
function table.count(t) |
|||
local count = 0 |
|||
for i,v in pairs(t) do |
|||
if v ~= nil then |
|||
count = count + 1 |
|||
end |
|||
end |
|||
return count |
|||
end |
|||
|
|||
function table.highest_index(t) |
|||
local highest = nil |
|||
for i,v in pairs(t) do |
|||
if i and not highest then |
|||
highest = i |
|||
end |
|||
|
|||
if i > highest then |
|||
highest = i |
|||
end |
|||
end |
|||
return highest |
|||
end |
|||
|
|||
function table.find(t, predicate) |
|||
for i,v in pairs(t) do |
|||
if predicate(v) then |
|||
return i,v |
|||
end |
|||
end |
|||
return nil |
|||
end |
|||
|
|||
function quicksort(t, low_index, high_index, comparator) |
|||
local function partition(t, low_index, high_index) |
|||
local i = low_index - 1 |
|||
local pivot = t[high_index] |
|||
|
|||
for j = low_index, high_index - 1 do |
|||
if comparator(t[j], t[pivot]) <= 0 then |
|||
i = i + 1 |
|||
t[i], t[j] = t[j], t[i] |
|||
end |
|||
end |
|||
|
|||
t[i + 1], t[high_index] = t[high_index], t[i + 1] |
|||
return i + 1 |
|||
end |
|||
|
|||
if #t == 1 then |
|||
return t |
|||
end |
|||
|
|||
if comparator(t[low_index], t[high_index]) < 0 then |
|||
local partition_index = partition(t, low_index, high_index) |
|||
|
|||
quicksort(t, low_index, partition_index - 1, comparator) |
|||
quicksort(t, partition_index + 1, high_index, comparator) |
|||
end |
|||
|
|||
return t |
|||
end |
|||
|
@ -1,23 +0,0 @@ |
|||
|
|||
function circles_intersect(center1, center2, radius1, radius2) |
|||
local c1, c2, r1, r2 = center1, center2, radius1, radius2 |
|||
local d = math.distance(center1, center2) |
|||
local radii_sum = r1 + r2 |
|||
-- touching |
|||
if d == radii_sum then return 1 |
|||
|
|||
-- not touching or intersecting |
|||
elseif d > radii_sum then return false |
|||
|
|||
-- intersecting |
|||
else return 2 |
|||
end |
|||
end |
|||
|
|||
function point_in_rect(point, rect) |
|||
return point.x > rect.x1 |
|||
and point.x < rect.x2 |
|||
and point.y > rect.y1 |
|||
and point.y < rect.y2 |
|||
end |
|||
|
@ -1,162 +0,0 @@ |
|||
|
|||
-- text popup in the middle of the screen that dissapates |
|||
function gui_alert(message, color, decay_time) |
|||
win.scene:append( |
|||
am.scale(3) ^ am.text(message, color or COLORS.WHITE) |
|||
:action(coroutine.create(function(self) |
|||
am.wait(am.tween(self, decay_time or 1, { color = vec4(0) }, am.ease_in_out)) |
|||
win.scene:remove(self) |
|||
end)) |
|||
) |
|||
end |
|||
|
|||
function gui_numberfield(dimensions, opts) |
|||
|
|||
end |
|||
|
|||
function gui_textfield(position, dimensions, max, disallowed_chars) |
|||
local width, height = dimensions.x, dimensions.y |
|||
local disallowed_chars = disallowed_chars or {} |
|||
local max = max or 10 |
|||
|
|||
local outer_rect = am.rect( |
|||
-width/2, |
|||
-height/2, |
|||
width/2, |
|||
height/2, |
|||
COLORS.VERY_DARK_GRAY |
|||
) |
|||
local inner_rect = am.rect( |
|||
-width/2 + 1, |
|||
-height/2 + 1, |
|||
width/2 - 2, |
|||
height/2 - 2, |
|||
COLORS.PALE_SILVER |
|||
) |
|||
|
|||
local group = am.group{ |
|||
outer_rect, |
|||
inner_rect, |
|||
am.translate(-width/2 + 5, 0) ^ am.scale(2) ^ am.text("", COLORS.BLACK, "left"), |
|||
am.translate(-width/2 + 5, -8) ^ am.line(vec2(0, 0), vec2(16, 0), 2, COLORS.BLACK) |
|||
} |
|||
|
|||
group:action(function(self) |
|||
local keys = win:keys_pressed() |
|||
if #keys == 0 then return end |
|||
|
|||
local chars = {} |
|||
local shift = win:key_down("lshift") or win:key_down("rshift") |
|||
for i,k in pairs(keys) do |
|||
if k:len() == 1 then -- @HACK alphabetical or digit characters |
|||
if string.match(k, "%a") then |
|||
if shift then |
|||
table.insert(chars, k:upper()) |
|||
else |
|||
table.insert(chars, k) |
|||
end |
|||
elseif string.match(k, "%d") then |
|||
if shift then |
|||
if k == "1" then table.insert(chars, "!") |
|||
elseif k == "2" then table.insert(chars, "@") |
|||
elseif k == "3" then table.insert(chars, "#") |
|||
elseif k == "4" then table.insert(chars, "$") |
|||
elseif k == "5" then table.insert(chars, "%") |
|||
elseif k == "6" then table.insert(chars, "^") |
|||
elseif k == "7" then table.insert(chars, "&") |
|||
elseif k == "8" then table.insert(chars, "*") |
|||
elseif k == "9" then table.insert(chars, "(") |
|||
elseif k == "0" then table.insert(chars, ")") |
|||
end |
|||
else |
|||
table.insert(chars, k) |
|||
end |
|||
end |
|||
-- begin non-alphabetical/digit |
|||
elseif k == "minus" then |
|||
if shift then table.insert(chars, "_") |
|||
else table.insert(chars, "-") end |
|||
elseif k == "equals" then |
|||
if shift then table.insert(chars, "=") |
|||
else table.insert(chars, "+") end |
|||
elseif k == "leftbracket" then |
|||
if shift then table.insert(chars, "{") |
|||
else table.insert(chars, "[") end |
|||
elseif k == "rightbracket" then |
|||
if shift then table.insert(chars, "}") |
|||
else table.insert(chars, "]") end |
|||
elseif k == "backslash" then |
|||
if shift then table.insert(chars, "|") |
|||
else table.insert(chars, "\\") end |
|||
elseif k == "semicolon" then |
|||
if shift then table.insert(chars, ":") |
|||
else table.insert(chars, ";") end |
|||
elseif k == "quote" then |
|||
if shift then table.insert(chars, "\"") |
|||
else table.insert(chars, "'") end |
|||
elseif k == "backquote" then |
|||
if shift then table.insert(chars, "~") |
|||
else table.insert(chars, "`") end |
|||
elseif k == "comma" then |
|||
if shift then table.insert(chars, "<") |
|||
else table.insert(chars, ",") end |
|||
elseif k == "period" then |
|||
if shift then table.insert(chars, ">") |
|||
else table.insert(chars, ".") end |
|||
elseif k == "slash" then |
|||
if shift then table.insert(chars, "?") |
|||
else table.insert(chars, "/") end |
|||
|
|||
-- control characters |
|||
elseif k == "backspace" then |
|||
-- @NOTE this doesn't preserve the order of chars in the array so if |
|||
-- someone presses a the key "a" then the backspace key in the same frame, in that order |
|||
-- the backspace occurs first |
|||
self"text".text = self"text".text:sub(1, self"text".text:len() - 1) |
|||
|
|||
elseif k == "tab" then |
|||
-- @TODO |
|||
|
|||
elseif k == "space" then |
|||
table.insert(chars, " ") |
|||
|
|||
elseif k == "capslock" then |
|||
-- @OTOD |
|||
end |
|||
end |
|||
|
|||
for _,c in pairs(chars) do |
|||
if not disallowed_chars[c] then |
|||
if self"text".text:len() <= max then |
|||
self"text".text = self"text".text .. c |
|||
end |
|||
end |
|||
end |
|||
end) |
|||
|
|||
return group |
|||
end |
|||
|
|||
function gui_slider(position, dimensions, bar_color, circle_color, min, max, default_value, action) |
|||
local position = position or vec2(0) |
|||
local width = dimensions.x |
|||
local height = dimensions.y |
|||
local bar_color = bar_color or COLORS.WHITE |
|||
local circle_color = circle_color or COLORS.GREEN_YELLOW |
|||
local min = min or 0 |
|||
local max = max or 100 |
|||
local default_value = math.clamp(default_value or 50, min, max) |
|||
|
|||
local slider = pack_texture_into_sprite(TEXTURES.GUI_SLIDER, width, height, bar_color) |
|||
local circle = am.circle(vec2(-width/2 + (default_value/max) * (width/2), 0), height, circle_color) |
|||
|
|||
local node = am.translate(position) ^ am.group{ |
|||
slider, |
|||
circle |
|||
} |
|||
|
|||
if action then node:action(action) end |
|||
|
|||
return node |
|||
end |
|||
|
@ -1,23 +0,0 @@ |
|||
|
|||
local garbage_collector_cycle_timing_history = {} |
|||
local garbage_collector_average_cycle_time = 0 |
|||
function run_garbage_collector_cycle() |
|||
local time, result = fprofile(collectgarbage, "collect") |
|||
|
|||
table.insert(garbage_collector_cycle_timing_history, time) |
|||
-- re-calc average gc timing |
|||
local total = 0 |
|||
for _,v in pairs(garbage_collector_cycle_timing_history) do |
|||
total = total + v |
|||
end |
|||
garbage_collector_average_cycle_time = total / #garbage_collector_cycle_timing_history |
|||
end |
|||
|
|||
function check_if_can_collect_garbage_for_free(frame_start_time, min_fps) |
|||
-- often this will be polled at the end of a frame to see if we're running fast or slow, |
|||
-- and if we have some time to kill before the start of the next frame, we could maybe run gc. |
|||
if (am.current_time() - frame_start_time) < (1 / (min_fps or 60) + garbage_collector_average_cycle_time) then |
|||
run_garbage_collector_cycle() |
|||
end |
|||
end |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue