Fork me on GitHub
hump

hump is a collection of lightweight, yet powerful modules to speed up game development with LÖVE. It offers solutions to various small but annoyingly reccurent problems.

Download

You can download the latest packaged version of hump as zip- or tar-archive directly from github. You can also view and download the sourcecode of individual modules here.

If you use the Git command line client, you can clone the repository by running:

git clone git://github.com/vrld/hump

Once done, you can check for updates by running:

git pull

from inside the directory.

License

Copyright (c) 2010-2011 Matthias Richter

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

Except as contained in this notice, the name(s) of the above copyright holders shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

hump.gamestate^ top
Gamestate = require "hump.gamestate"

A gamestate encapsulates independant data an behaviour into a single entity.

A typical game could consist of a menu-state, a level-state and a game-over-state.

Module overview

new()
Create new gamestate.
switch()
Switch to gamestate.
update()
Manually update current gamestate.
draw()
Manually draw the current gamestate.
focus()
Inform current gamestate of a focus event.
keypressed()
Inform current gamestate of a keypressed event.
keyreleased()
Inform current gamestate of a keyreleased event.
mousepressed()
Inform current gamestate of a mousepressed event.
mousereleased()
Inform current gamestate of a mousereleased event.
joystickpressed()
Inform current gamestate of a joystickpressed event.
joystickreleased()
Inform current gamestate of a joystickreleased event.
quit()
Inform current gamestate of a quit event.
registerEvents()
Automatically do all of the above when needed.

Gamestate Callbacks

A gamestate can define (nearly) all callbacks that LÖVE defines. In addition, there are callbacks for entering and leaving a state.:

enter(previous, ...)
Called when entering the state. See switch().
leave()
Called when leaving a state. See switch().
update()
Update the game state. Called every frame.
draw()
Draw on the screen. Called every frame.
focus()
Called if the window gets or looses focus.
keypressed()
Triggered when a key is pressed.
keyreleased()
Triggered when a key is released.
mousepressed()
Triggered when a mouse button is pressed.
mousereleased()
Triggered when a mouse button is released.
joystickpressed()
Triggered when a joystick button is pressed.
joystickreleased()
Triggered when a joystick button is released.
quit()
Called on quitting the game. Only called on the active gamestate.

When using registerEvents(), all these callbacks will receive the same arguments as the LÖVE callbacks do.

Example:
menu = Gamestate.new()
function menu:enter(previous, background_image)
    self.background = background_image
    Buttons.initialize()
end

function menu:leave()
    Buttons.cleanup()
end

function menu:update(dt)
    Buttons.update(dt)
end

function menu:draw()
    love.graphics.draw(self.background, 0, 0)
    Buttons.draw()
end

function menu:keyreleased(key)
    if key == 'up' then
        Buttons.selectPrevious()
    elseif key == 'down' then
        Buttons.selectNext()
    elseif
        Buttons.active:onClick()
    end
end

function menu:mousereleased(x,y, mouse_btn)
    local button = Buttons.hovered(x,y)
    if button then
        Button.select(button)
        if mouse_btn == 'l' then
            button:onClick()
        end
    end
end
function new()^ top

Declare a new gamestate. A gamestate can define several callbacks.

Parameters:
None
Returns:
Gamestate
The new gamestate.
Example:
menu = Gamestate.new()
function switch(to, ...)^ top

Switch to a gamestate, with any additional arguments passed to the new state.

Switching a gamestate will call the leave() callback on the current gamestate, replace the current gamestate with to and finally call enter(old_state, ...) on the new gamestate.

Parameters:
Gamestate to
Target gamestate.
mixed ...
Additional arguments to pass to to:enter().
Returns:
mixed
The result of to:enter().
Example:
Gamestate.switch(game, level_two)
function update(...)^ top
function draw(...)
function focus(...)
function keypressed(...)
function keyreleased(...)
function mousepressed(...)
function mousereleased(...)
function joystickpressed(...)
function joystickreleased(...)
function quit(...)

Calls the corresponding function on the current gamestate (see callbacks).

Only needed when not using registerEvents().

Parameters:
mixed ...
Arguments to pass to the corresponding callback.
Returns:
mixed
Result of the callback function.
Example:
function love.update(dt)
    Gamestate.update(dt)
end

function love.draw()
    local mx,my = love.mouse.getPosition()
    Gamestate.draw(mx, my)
end

function love.keypressed(key, code)
    Gamestate.keypressed(key, code)
end
function registerEvents()^ top

Register all love callbacks to call Gamestate.update(), Gamestate.draw(), etc. automatically.

This is achieved by overwriting the love callbacks, e.g.:

local _update = love.update
function love.update(dt)
    _update(dt)
    Gamestate.current:update(dt)
end
Parameters:
None
Returns:
Nothing
Example:
function love.load()
    Gamestate.registerEvents()
    Gamestate.switch(menu)
end
hump.timer^ top
Timer = require "hump.timer"

hump.timer provides a simple interface to use delayed functions, i.e. functions that will only be executed after some amount time.

In addition, the module offers facilities to create functions that interpolate or oscillate over time.

Module overview

add()
Add a timed function.
addPeriodic()
Add a periodic function.
clear()
Clear all timed and periodic functions.
update()
Update timers.
Interpolator()
Create a new interpolating function.
Oscillator()
Create a new oscillating function.
function add(delay, func)^ top

Add a timed function. The function will be executed when delay seconds have elapsed.

Note that there is no guarantee that the delay will be exceeded. It is, however, guaranteed that the function will not be executed before the delay has passed.

If the function is called, it will receive itself as only parameter. This may be useful to implement the periodic behavior of Timer.addPeriodic.

Parameters:
number delay
Time to pass before the function is called.
function func
The function to be called.
Returns:
Nothing
Example:
-- grant the player 5 seconds of immortality
player:setInvincible(true)
Timer.add(5, function() player:setInvincible(false) end)
-- print "foo" every second
Timer.add(1, function(func) print("foo") Timer.add(1, func) end)
function addPeriodic(delay, func, count)^ top
function addPeriodic(delay, func)

Add a periodic timed function, i.e. a function that will be called count times every delay seconds.

If count is omitted, the function loops until clear() is called.

Parameters:
number delay
Time to pass before the function is called.
function func
The function to be called.
number count
The number of times the function is called.
Returns:
Nothing
Example:
Timer.addPeriodic(1, function() lamp:toggleLight() end)
Timer.addPeriodic(0.3, function() mothership:spawnFighter() end, 5)
function clear()^ top

Clears all timers.

Parameters:
None
Returns:
Nothing
Example:
Timer.clear()
function update(dt)^ top

Update timers and execute functions if the deadline is reached. Use this in love.update().

Parameters:
number dt
Time that has passed since the last update().
Returns:
Nothing
Example:
function love.update(dt)
    do_stuff()
    Timer.update(dt)
end
function Interpolator(length, func)^ top

Create a wrapper for an interpolating function, i.e. a function that acts depending on how much time has passed.

The wrapper will have the prototype:

function wrapper(dt, ...)
dt is the time that has passed since the last call and ... are arguments passed to the interpolating function. It will return whatever the interpolating functions returns if the interpolation is not yet finished or nil if the interpolation is done.

The prototype of the interpolating function is:

function inter(fraction, ...)
where fraction is a number between 0 and 1 and ... are additional arguments supplied to the wrapper.

Parameters:
number length
Interpolation length in seconds.
function func
Interpolating function.
Returns:
function
The wrapper function.
Example:
fader = Timer.Interpolator(5, function(frac, r,g,b)
    love.graphics.setBackgroundColor(frac*r,frac*g,frac*b)
end)

function love.update(dt)
    fader(dt, 255,255,255)
end
function Oscillator(length, func)^ top

Create a wrapper for an oscillating function, which is basically a looping interpolating function.

The function prototypes are the same as with Interpolator():

function wrapper(dt, ...)
function oscillator(fraction, ...)

The wrapper function will return whatever oscillator() returns.

Parameters:
number length
Length of one interpolation period.
function func
Oscillating function.
Returns:
function
The wrapper function.
Example:
mover = Timer.Oscillator(10, function(frac)
   return 400 + 300 * math.sin(2*math.pi*frac)
end)

local xpos = 100
function love.update(dt)
    xpos = mover(dt)
end

function love.draw()
    love.graphics.circle('fill', xpos, 300, 80, 36)
end
hump.vector^ top
vector = require "hump.vector"

A handy 2D vector class defining the most common things you do with vectors.

You can access the individual coordinates by using vec.x and vec.y.

Module overview

new()
Create new vector.
isvector()
Test if value is a vector.
vector:clone()
Copy a vector.
vector:unpack()
Extract coordinates.
vector:permul()
Per element multiplication.
vector:len()
Get length.
vector:len2()
Get squared length.
vector:dist()
Get distance to vector.
vector:normalized()
Get normalized vector
vector:normalize_inplace()
Normalize vector in-place.
vector:rotated()
Get rotated vector.
vector:rotate_inplace()
Rotate vector in-place.
vector:perpendicular()
Get perpendicular vector.
vector:projectOn()
Get projection onto another vector.
vector:cross()
Cross product of two vectors.
Arithmetic and relational operators

Vector arithmetic is implemented by using __add, __mul and other metamethods:

vector + vector = vector
Component wise sum.
vector - vector = vector
Component wise difference.
vector * vector = number
Dot product.
number * vector = vector
Vector scaling.
vector * number = vector
Vector scaling.
vector / number = vector
Vector scaling.

Relational operators are defined, too:

a == b
true, if a.x == b.x and a.y == b.y.
a <= b
true, if a.x <= b.x and a.y <= b.y.
a < b
Lexical sort: true, if a.x < b.x or a.x == b.x and a.y < b.y.
Example:
acceleration = vector(0,-9)
player.velocity = player.velocity + acceleration * dt
player.position = player.position + player.velocity * dt
function new(x,y)^ top

Create new vector

Parameters:
numbers x, y
Coordinates.
Returns:
vector
The vector.
Example:
a = vector.new(10,10)

As a shortcut, you can call the module like a function, i.e.:

vector = require 'hump.vector'
a = vector(10,10)
function isvector(v)^ top

Test whether a variable is a vector.

Parameters:
mixed v
The variable to test.
Returns:
boolean
true if v is a vector, false otherwise.
Example:
if not vector.isvector(v) then
    v = vector(v,0)
end
function vector:clone()^ top

Copy a vector. Simply assigning a vector a vector to a variable will create a reference, so when you modify the vector referenced by the new variable, will also change the old one:

a = vector(1,1) -- create vector
b = a           -- b references a
c = a:clone()   -- c is a copy of a
b.x = 0         -- changes a,b and c
print(a,b,c)    -- prints '(1,0), (1,0), (1,1)'
Parameters:
None
Returns:
vector
The copied vector.
Example:
copy = original:clone()
function vector:unpack()^ top

Extract coordinates.

Parameters:
None
Returns:
numbers
The coordinates.
Example:
x,y = pos:unpack()
love.graphics.draw(self.image, self.pos:unpack())
function vector:permul(other)^ top

Multiplies vectors coordinate wise, i.e. result = vector(a.x * b.x, a.y * b.y).

This does not change either argument vectors, but creates a new one.

Parameters:
vector other
The other vector.
Returns:
vector
New vector as defined above.
Example:
scaled = original:permul(vector(1,1.5))
function vector:len()^ top

Get length of a vector, i.e. math.sqrt(vec.x * vec.x + vec.y * vec.y).

Parameters:
None
Returns:
number
length of the vector.
Example:
distance = (a - b):len()
function vector:len2()^ top

Get squared length of a vector, i.e. vec.x * vec.x + vec.y * vec.y.

Parameters:
None
Returns:
number
The squared length.
Example:
-- get closest vertex to a given vector
closest, dsq = vertices[1], (pos - vertices[1]):len2()
for i = 2,#vertices do
    local temp = (pos - vertices[i]):len2()
    if temp < dsq then
        closest, dsq = vertices[i], temp
    end
end
function vector:dist(other)^ top

Get distance of two vectors. The same as (a - b):len().

Parameters:
vector other
Other vector to measure the distance.
Returns:
number
The distance of both vectors.
Example:
-- get closest vertex to a given vector
-- slightly slower than the example using len2()
closest, dist = vertices[1], pos:dist(vertices[1])
for i = 2,#vertices do
    local temp = pos:dist(vertices[i])
    if temp < dist then
        closest, dist = vertices[i], temp
    end
end
function vector:normalized()^ top

Get normalized vector, i.e. a vector with the same direction as the input vector, but length 1.

This does not change the input vector, but creates a new vector.

Parameters:
None
Returns:
vector
Vector with same direction as the input vector, but length 1.
Example:
normal = edge:normalized()
function vector:normalize_inplace()^ top

Normalize a vector, i.e. make the vector unit length.

This modifies the vector. If in doubt, use vector:normalized().

Parameters:
None
Returns:
vector
The normalized vector.
Example:
normal = (b - a):perpendicular():normalize_inplace()
function vector:rotated(phi)^ top

Get a rotated vector.

This does not change the input vector, but creates a new vector.

Parameters:
number phi
Rotation angle in radians.
Returns:
vector
The rotated vector.
Example:
-- approximate a circle
circle = {}
for i = 1,30 do
    local phi = 2 * math.pi * i / 30
    circle[#circle+1] = vector(0,1):rotated(phi)
end
Sketch:

sketch of rotated vectors

function vector:rotate_inplace(phi)^ top

Rotate a vector.

This modifies the vector. If in doubt, use vector:rotate().

Parameters:
number phi
Rotation angle in radians.
Returns:
vector
The rotated vector.
Example:
-- ongoing rotation
spawner.direction:rotate_inplace(dt)
function vector:perpendicular()^ top

Quick rotation by 90°. Creates a new vector. The same as (but faster):

vec:rotate(math.pi/2)
Parameters:
None
Returns:
vector
A vector perpendicular on the input vector.
Example:
normal = (b - a):perpendicular():normalize_inplace()
Sketch:

sketch of perpendicular vectors

function vector:projectOn(v)^ top

Project vector onto another vector.

Parameters:
vector v
The vector to project on.
Returns:
vector
The projected vector.
Example:
velocity_component = velocity:projectOn(axis)
Sketch:

sketch of vector projection

function vector:cross(other)^ top

Get cross product of both vectors.

For the math geeks:

The cross product not be defined for 2D vectors. To nonetheless get a result, treat the vectors as being 3D vectors (x,y,0). The cross product of both vectors has just a z-component, and this is what this function returns. It's also the determinant of both vectors: d = det(a,b).

Parameters:
vector other
Vector to compute the cross product with.
Returns:
number
The cross product of both vectors.
Example:
parallelogram_area = a:cross(b)
hump.class^ top
Class = require "hump.class"
A small, handy class implementation with multiple inheritance.

Module overview

new()
Create new class.
class.construct()
Call class constructor.
inherit()
Class inheritance.
function new(constructor)^ top
function new{name = the_name, constructor}
function new{name = the_name, inherits = super, constructor}
function new{name = the_name, inherits = {super1, super2, ...}, constructor}

Define a new class.

The constructor will receive the newly created object as first argument.

If you required the module to a variable, you can use the variable as a shortcut to new().

Parameters:
function constructor
Class constructor.
string the_name
Class name to be returned when calling tostring() on the class.
class super
Super class to inherit from. Can also be an array of classes to inherit from.
Returns:
Class
The class.
Example:
Class = require 'hump.class'

-- define unnamed class
Feline = Class(function(self, size, weight)
    self.size = size
    self.weight = weight
end)

-- define class method
function Feline:stats()
    return string.format("size: %.02f, weight %.02f", self.size, self.weight)
end

-- create two objects
garfield = Feline(.7, 45)
felix = Feline(.8, 12)

print("Garfield: " .. garfield:stats(), "Felix: " .. felix:stats())
Class = require 'hump.class'

-- define named class
Feline = Class{name = "Feline", function(self, size, weight)
    self.size = size
    self.weight = weight
end}

garfield = Feline(.7, 45)
print(Feline, garfield) -- prints 'Feline	<instance of Feline>'
Class = require 'hump.class'
A = Class{name = 'A'}
function A:foo()
    print('foo')
end

B = Class{name = 'B'}
function C:bar()
    print('bar')
end

-- single inheritance
C = Class{name = 'C', inherits = A}
instance = C()
instance:foo() -- prints 'foo'

-- multiple inheritance
D = Class{name = 'D', inherits = {A,B}}
instance = D()
instance:foo() -- prints 'foo'
instance:bar() -- prints 'bar'
function class.construct(object, ...)^ top
function class.Construct(object, ...)

Calls class constructor of a class.

Needed in constructors of child classes to initialize parts of the object that the parent classes define.

Parameters:
Object object
The object. This is usually self.
mixed ...
Arguments to pass to the constructor.
Returns:
Nothing
Example:
Class = require 'hump.class'

Feline = Class{name = "Feline", function(self, size, weight)
    self.size = size
    self.weight = weight
end}

Cat = Class{name = "Cat", function(self, name, size, weight)
    Feline.construct(self, size, weight)
    self.name = name
end}
Cat:inherit(Feline)
function inherit(class, super, ...)^ top
function class:inherit(super, ...)
function class:Inherit(super, ...)

Inherit functions (but not class variables).

If multiple super-classes are defined inherit from all of these. If two super-classes define a method of the same name, inherit it from the one mentioned first.

Parameters:
Class class
Child class.
Classes super, ...
Parent classes to inherit from.
Returns:
Nothing
Example:
Class = require 'hump.class'

Feline = Class{name = "Feline", function(self, size, weight)
    self.size = size
    self.weight = weight
end}

function Feline:stats()
    return string.format("size: %.02f, weight %.02f", self.size, self.weight)
end

function Feline:speak() print("meow") end

Cat = Class{name = "Cat", function(self, name, size, weight)
    Feline.construct(self, size, weight)
    self.name = name
end}
Cat:inherit(Feline)

function Cat:stats()
    return string.format("name: %s, %s", self.name, Feline.stats(self))
end

Tiger = Class{name = "Tiger", function(self, size, weight)
    Feline.construct(self, size, weight)
end}
Tiger:Inherit(Feline)

function Tiger:speak() print("ROAR!") end

felix = Cat("Felix", .8, 12)
hobbes = Tiger(2.2, 68)

print(felix:stats())   -- "name: Felix, size: 0.80, weight 12.00"
print(hobbes:stats())  -- "size: 2.20, weight 68.00"
felix:speak()          -- "meow"
hobbes:speak()         -- "ROAR!"

Caveats

Be careful when using metamethods like __add or __mul: When subclass inherits those methods from a superclass, but does not overwrite them, the result of the operation may be of the type superclass. Consider the following:

Class = require 'hump.class'

A = Class(function(self, x) self.x = x end)
function A:__add(other) return A(self.x + other.x) end
function A:show() print("A:", self.x) end

B = Class(function(self, x, y) A.construct(self, x) self.y = y end)
B:Inherit(A)
function B:show() print("B:", self.x, self.y) end
function B:foo() print("foo") end

one, two = B(1,2), B(3,4)
result = one + two
result:show()   -- prints "A:    4"
result:foo()    -- error: method does not exist
hump.camera^ top
camera = require "hump.camera"

Depends on vector

Camera abstraction for LÖVE. A camera "looks" at a position and can be moved, zoomed and rotated.

A camera defines it's own coordinate system, meaning that an object shown on the screen likely has different coordinates in the game world than it has on the screen.

For example, the mouse position could be at pixel 400,400 on the screen (= camera coordinates), but the camera looks at the point 100,100 and is rotated by 90°. The world coordinates of the mouse cursor are 200,100.

The camera class defines methods to convert between both coordinate systems.

Module overview

new()
Create new camera object.
camera:rotate()
Rotate camera.
camera:translate()
Move camera.
camera:predraw()
Apply camera transformation.
camera:postdraw()
Revert camera transformation.
camera:draw()
Apply camera transformations to a function.
camera:toCameraCoords()
Convert vector to camera coordinates.
camera:toWorldCoords()
Convert vector to world coordinates.
camera:mousepos()
Get mouse position in world coordinates.
function new(pos, zoom, rot)^ top

Create new camera object.

You can access and modify the camera parameters using camera.pos, camera.zoom and camera.rot.

Parameters:
vector pos (screen center)
Position the camera should look at.
number zoom (1)
Camera zoom.
number rot (0)
Camera rotation in radians.
Returns:
camera
Camera object.
Example:
cam = hump.camera.new(vector(400,300), 2)

If you assigned the module to a variable, you can call the module as a shortcut to hump.camera.new():

camera = require 'hump.camera'
vector = require 'hump.vector'

cam = camera(vector(400,300), 2)
function camera:rotate(phi)^ top

Rotate the camera. Same as cam.rot = cam.rot + phi.

Parameters:
number phi
Rotation angle in radians.
Returns:
Nothing
Example:
cam:rotate(dt)
function camera:translate(direction)^ top

Move the camera. Same as cam.pos = cam.pos + direction

Parameters:
vector direction
Direction to move the camera.
Returns:
Nothing
Example:
cam:translate(vector(100,0) * dt)
function camera:predraw()^ top

Apply camera transformations, i.e. move, scale and rotate everything so that you see what you would see when looking through the camera.

Everything until the next camera:postdraw() will be transformed.

Parameters:
None
Returns:
Nothing
Example:
function love.draw()
    cam:predraw()
    draw_world()
    cam:postdraw()
    draw_hud()
end
function camera:postdraw()^ top

Revert camera transformations done by camera:predraw().

Parameters:
None
Returns:
Nothing
Example:
function love.draw()
    cam:predraw()
    draw_world()
    cam:postdraw()
    draw_hud()
end
function camera:draw(func)^ top

Wrap a function between predraw() and postdraw():

cam:predraw()
func()
cam:postdraw()
Parameters:
function func
Drawing function to be wrapped.
Returns:
Nothing
Example:
function love.draw()
    cam:draw( draw_world )
    draw_hud()
end
function camera:toCameraCoords(pos)^ top

Convert world coordinates to camera coordinates.

Parameters:
vector pos
Position in world coordinates.
Returns:
vector
Position in camera coordinates.
Example:
screen_pos = cam:toCameraCoords( player.pos )
love.graphics.line(love.mouse.getX(), love.mouse.getY(), screen_pos:unpack()
function camera:toWorldCoords(pos)^ top

Convert camera coordinates to world coordinates.

Parameters:
vector pos
Position in camera coordinates.
Returns:
vector
Position in world coordinates.
Example:
target = cam:toWorldCoords( vector(love.mouse.getPosition()) )
unit:plotPathTo(target)
function camera:mousepos()^ top

Get mouse position in world coordinates.

Parameters:
None
Returns:
vector
Mouse position in world coordinates.
Example:
target = cam:mousepos()
unit:plotPathTo(target)
hump.ringbuffer^ top
ringbuffer = require "hump.ringbuffer"

A ring-buffer is a circular array. That means it does not have a first nor a last, but only a selected/current element.

You can use this to implement Tomb Raider style inventories, looping playlists, recurring dialogs (like a unit's answers when selecting it multiple times in Warcraft) and generally everything that has a circular or looping structure.

Module overview

new()
Create new ring-buffer.
ringbuffer:insert()
Insert element.
ringbuffer:remove()
Remove currently selected item.
ringbuffer:removeAt()
Remove an item.
ringbuffer:next()
Select next item.
ringbuffer:prev()
Select previous item.
ringbuffer:get()
Get currently selected item.
ringbuffer:size()
Get ringbuffer size.
function new(...)^ top

Create new ringbuffer.

Parameters:
mixed ...
Initial elements.
Returns:
Ringbuffer
Ringbuffer object.
Example:
rb = hump.ringbuffer.new(1,2,3)

As with vector, camera and class, you can call the module as shortcut to new():

ringbuffer = require 'hump.ringbuffer'

rb = ringbuffer(1,2,3)
function ringbuffer:insert(item, ...)^ top

Insert items behind current element.

Parameters:
mixed item, ...
Items to insert.
Returns:
Nothing
Example:
rb = ringbuffer(1,5,6) -- content: 1,5,6
rb:insert(2,3,4)       -- content: 1,2,3,4,5,6
function ringbuffer:remove()^ top

Remove currently selected item and select next item.

Parameters:
None
Returns:
mixed
The item removed.
Example:
rb = ringbuffer(1,2,3,4) -- content: 1,2,3,4
rb:next()                -- content: 2,3,4,1
rb:remove()              -- content: 3,4,1
function ringbuffer:removeAt(pos)^ top

Remove item at position relative to current item.

Parameters:
number pos
Position to remove.
Returns:
mixed
The item removed.
Example:
rb = ringbuffer(1,2,3,4,5) -- content: 1,2,3,4,5
rb:removeAt(2)             -- content: 1,2,4,5
rb:removeAt(-1)            -- content: 1,2,4
function ringbuffer:next()^ top

Select and return next item.

Parameters:
None
Returns:
mixed
The next item.
Example:
rb = ringbuffer(1,2,3)
print(rb:next()) -- prints '2'
print(rb:next()) -- prints '3'
print(rb:next()) -- prints '1'
function ringbuffer:prev()^ top

Select and return previous item.

Parameters:
None
Returns:
mixed
The previous item
Example:
rb = ringbuffer(1,2,3)
print(rb:prev()) -- prints '3'
print(rb:prev()) -- prints '2'
print(rb:prev()) -- prints '1'
function ringbuffer:get()^ top

Get currently selected item.

Parameters:
None
Returns:
mixed
Currently selected item.
Example:
rb = ringbuffer(1,2,3)
rb:next()
print(rb:get()) -- prints '2'
			
function ringbuffer:size()^ top

Get number of items in the buffer.

Parameters:
None
Returns:
number
Number of items in the buffer.
Example:
rb = ringbuffer(1,2,3)
print(rb:size()) -- prints '3'
rb:remove()
print(rb:size()) -- prints '2'