Created
March 22, 2017 18:40
-
-
Save shakesoda/fee00d0ce0d85318b364ba50756fe120 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
-- Basic ring buffer utility, to spare the hassle. | |
local ringbuffer = {} | |
local ringbuffer_mt = {} | |
local function new(_items) | |
local t = { | |
items = _items or {}, | |
current = 1 | |
} | |
return setmetatable(t, ringbuffer_mt) | |
end | |
ringbuffer_mt.__index = ringbuffer | |
ringbuffer_mt.__call = function(_, ...) | |
return new(...) | |
end | |
function ringbuffer:get() | |
return self.items[self.current] | |
end | |
function ringbuffer:next() | |
self.current = (self.current % #self.items) + 1 | |
return self:get() | |
end | |
function ringbuffer:prev() | |
self.current = self.current - 1 | |
if self.current < 1 then | |
self.current = #self.items | |
end | |
return self:get() | |
end | |
function ringbuffer:reset() | |
self.current = 1 | |
end | |
function ringbuffer:insert(item, ...) | |
if not item then | |
return | |
end | |
self:insert(...) | |
table.insert(self.items, self.current + 1, item) | |
end | |
function ringbuffer:append(item, ...) | |
if not item then | |
return | |
end | |
self.items[#self.items + 1] = item | |
return self:append(...) | |
end | |
function ringbuffer:remove(k) | |
if not k then | |
return table.remove(self.items, self.current) | |
end | |
-- same as vrld's | |
local pos = (self.current + k) % #self.items | |
while pos < 1 do pos = pos + #self.items end | |
local item = table.remove(self.items, pos) | |
if pos < self.current then self.current = self.current - 1 end | |
if self.current > #self.items then self.current = 1 end | |
return item | |
end | |
return setmetatable({ new = new }, ringbuffer_mt) |
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
local timer = require "timer" | |
local ringbuffer = require "utils.ringbuffer" | |
local cpml = require "cpml" | |
local scroller = {} | |
local scroller_mt = {} | |
local function default_transform(self, offset, count, index) | |
local spacing = love.window.toPixels(50) | |
self.x = math.floor(math.cos(offset / (count / 2)) * love.window.toPixels(50)) | |
self.y = math.floor(offset * spacing) | |
end | |
local function default_position(_) | |
return 0, 0 | |
end | |
local default_sounds = { | |
prev = false, | |
next = false, | |
select = false | |
} | |
local function new(items, options) | |
local t = { | |
fixed = options.fixed or false, | |
switch_time = options.switch_time or 0.2, | |
size = options.size or false, | |
sounds = options.sounds or default_sounds, | |
transform = options.transform_fn or default_transform, | |
position = options.position_fn or default_position, | |
cursor_data = {}, | |
data = {}, | |
_timer = timer.new(), | |
_rb = ringbuffer(items), | |
_pos = 1, | |
_tween = false, | |
_last_hit = { love.mouse.getPosition() } | |
} | |
t = setmetatable(t, scroller_mt) | |
t:reset() | |
return t | |
end | |
scroller_mt.__index = scroller | |
scroller_mt.__call = function(_, ...) | |
return new(...) | |
end | |
local function tween(self) | |
if self._tween then | |
self._timer:cancel(self._tween) | |
end | |
self._tween = self._timer:tween(self.switch_time, self, { _pos = self._rb.current }, "out-back") | |
end | |
function scroller:get() | |
return self._rb.items[self._rb.current] | |
end | |
function scroller:prev(n) | |
if self.sounds.prev then | |
self.sounds.prev:stop() | |
self.sounds.prev:play() | |
end | |
for _ = 1, (n or 1) do self._rb:prev() end | |
local item = self:get() | |
if item.skip then | |
self:prev() | |
else | |
tween(self) | |
end | |
end | |
function scroller:next(n) | |
if self.sounds.next then | |
self.sounds.next:stop() | |
self.sounds.next:play() | |
end | |
for _ = 1, (n or 1) do self._rb:next() end | |
local item = self:get() | |
if item.skip then | |
self:next() | |
else | |
tween(self) | |
end | |
end | |
function scroller:reset() | |
self._rb:reset() | |
-- If you manage to land on a skip that is bad mojo, go to the next one | |
local item = self:get() | |
while item.skip do | |
self:next() | |
item = self:get() | |
end | |
-- throw in a big number to force an initial skip to not animate | |
self:update(math.huge) | |
end | |
function scroller:hit(x, y, click) | |
if not self.size or (not self.fixed and not click) then | |
self._last_hit = false | |
return false | |
end | |
if self._last_hit and self._last_hit[1] == x and self._last_hit[2] == y then | |
if not click then | |
return false | |
end | |
end | |
self._last_hit = { x, y } | |
local p = cpml.vec3(x, y, 0) | |
for i, item in ipairs(self._rb.items) do | |
local b = { | |
min = cpml.vec3(self.data[i].x, self.data[i].y, 0), | |
max = cpml.vec3(self.data[i].x + self.size.w, self.data[i].y + self.size.h, 0) | |
} | |
if not item.skip and cpml.intersect.point_aabb(p, b) then | |
self._rb.current = i | |
tween(self) | |
return true | |
end | |
end | |
return false | |
end | |
function scroller:update(dt) | |
self._timer:update(dt) | |
local x, y = self:position() | |
for i, v in ipairs(self._rb.items) do | |
self.data[i] = setmetatable({ x = 0, y = 0 }, { __index = v }) | |
local ipos = i | |
if not self.fixed then | |
ipos = ipos - self._pos | |
end | |
self.transform(self.data[i], ipos, #self._rb.items, i) | |
self.data[i].x = self.data[i].x + x | |
self.data[i].y = self.data[i].y + y | |
end | |
self.transform(self.cursor_data, self.fixed and self._pos or 0, #self._rb.items, 1) | |
self.cursor_data.x = self.cursor_data.x + x | |
self.cursor_data.y = self.cursor_data.y + y | |
while #self.data > #self._rb.items do | |
table.remove(self.data) | |
end | |
end | |
return setmetatable({ new = new }, scroller_mt) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment