diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6024ef3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "doctool"] + path = doctool + url = git@github.com:vrld/doctool.git diff --git a/doc.lua b/doc.lua deleted file mode 100644 index ed37315..0000000 --- a/doc.lua +++ /dev/null @@ -1,1748 +0,0 @@ -Module { name = "hump.gamestate", - title = "Gamestate", - short = "A gamestate system", - long = [===[ - A gamestate encapsulates independent data an behaviour into a single entity. - - A typical game could consist of a {*menu-state}, a {*level-state} and a {*game-over-state}.]===], - - Section { name = "callbacks", - title = "Gamestate Callbacks", - content = [===[ - A gamestate can define (nearly) all callbacks that LÖVE defines. In addition, - there are callbacks for entering and leaving a state.: - - [| - {#init()} :Called once before entering the state. See {#switch()}. - {#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 [^http://love2d.org/wiki/love LÖVE callbacks] do.]===], - example = [===[ -menu = Gamestate.new() -function menu:init() -- run only once - self.background = love.graphics.newImage('bg.jpg') - Buttons.initialize() -end - -function menu:enter(previous) -- run every time the state is entered - Buttons.setActive(Buttons.start) -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 { name = "new", - short = "Create a new gamestate.", - long = "Declare a new gamestate. A gamestate can define several [^#{{MODULE}}-callbacks callbacks].", - params = {}, - returns = { - {"Gamestate", "The new gamestate."} - }, - example = "menu = Gamestate.new()", - }, - - Function { name = "switch", - short = "Switch to gamestate.", - long = [===[ - 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, call the {#init()} function if the state - was not yet inialized and finally call {#enter(old_state, ...)} on the new gamestate.]===], - params = { - {"Gamestate", "to", "Target gamestate."}, - {"mixed", "...", "Additional arguments to pass to to:enter()."} - }, - returns = { - {"mixed", "The results of to:enter()"} - }, - example = "Gamestate.switch(game, level_two)", - }, - - Function { name = { - "update", - "draw", - "focus", - "keypressed", - "keyreleased", - "mousepressed", - "mousereleased", - "joystickpressed", - "joystickreleased", - "quit", - }, - short = { - "Update current gamestate.", - "Draw the current gamestate.", - "Inform current gamestate of a focus event.", - "Inform current gamestate of a keypressed event.", - "Inform current gamestate of a keyreleased event.", - "Inform current gamestate of a mousepressed event.", - "Inform current gamestate of a mousereleased event.", - "Inform current gamestate of a joystickpressed event.", - "Inform current gamestate of a joystickreleased event.", - "Inform current gamestate of a quit event.", - }, - long = [===[ - Calls the corresponding function on the current gamestate (see [^#{{MODULE}}-callbacks callbacks]). - - Only needed when not using {#registerEvents()}.]===], - params = { - {"mixed", "...", "Arguments to pass to the corresponding [^#{{MODULE}}-callbacks callback]."}, - }, - returns = { - {"mixed", "The results 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 { name = "registerEvents", - short = "Automatically do all of the above when needed.", - long = [===[ - Register love callbacks to call {#Gamestate.update()}, {#Gamestate.draw()}, etc. automatically. - - This is by done by overwriting the love callbacks, e.g.: - [%local old_update = love.update -function love.update(dt) - old_update(dt) - Gamestate.current:update(dt) -end] - - {!Note:} Only works when called in {#love.load()} or any other function that is executed -after the whole file is loaded.]===], - params = { - {'table', 'callbacks', 'Names of the callbacks to register. If omitted, register all callbacks.', optional = true}, - }, - returns = {}, - example = { - [===[function love.load() - Gamestate.registerEvents() - Gamestate.switch(menu) -end]===], [===[function love.load() - Gamestate.registerEvents{'draw', 'update', 'quit'} - Gamestate.switch(menu) -end]===] - } - }, -} - -Module { name = "hump.timer", - title = "Timer", - short = "Delayed function calls and helpers for interpolating functions.", - long = [===[ - hump.timer provides a simple interface to use delayed functions, i.e. - functions that will be executed after some amount time has passed. For - example, you can use a timer to set the player invincible for a short - amount of time. - - In addition, the module offers facilities to create functions that - interpolate or oscillate over time. An interpolator could fade the color or - a text message, whereas an oscillator could be used for the movement of - foes in a shmup.]===], - - Function { name = "new", - short = "Create new timer instance.", - long = [===[ - {!If you don't need multiple independent schedulers, you can use the - global/default timer (see examples).} - - Creates a new timer instance that is independent of the global timer: - It will manage it's own list of scheduled functions and does not in any - way affect the the global timer. Likewise, the global timer does not - affect the timer instance. - - {!Note:} Timer instances use the colon-notation (e.g. - {#instance:update(dt)}), while the global timer uses the dot-notation - (e.g. {#Timer.update(dt)}).]===], - params = {}, - returns = { - {"Timer", "A timer instance"} - }, - example = "menuTimer = Timer.new()", - }, - - Function { name = {"add", "instance:add"}, - short = "Schedule a function.", - long = [===[ - Schedule a function. The function will be executed after {#delay} - seconds have elapsed, given that {#update(dt)} is called every frame. - - Note that there is no guarantee that the delay will not be exceeded, it - is only guaranteed that the function will not be executed {*before} the - delay has passed. - - It is an error to schedule a function again if it is not yet finished - or canceled. - - {#func} will receive itself as only parameter. This is useful to - implement periodic behavior (see the example).]===], - params = { - {"number", "delay", "Number of seconds the function will be delayed."}, - {"function", "func", "The function to be delayed."}, - }, - returns = { - {"table", "The timer handle."} - }, - example = { - [===[ --- grant the player 5 seconds of immortality -player.isInvincible = true -Timer.add(5, function() player.isInvincible = false end)]===], - [===[ --- print "foo" every second. See addPeriodic. -Timer.add(1, function(func) print("foo") Timer.add(1, func) end)]===], - [===[menuTimer:add(1, finishAnimation)]===] - }, - }, - - Function { name = {"addPeriodic", "instance:addPeriodic"}, - short = "Add a periodic function.", - long = [===[ - Add a function that will be called {#count} times every {#delay} - seconds. - - If {#count} is omitted, the function will be called until it returns - {#false} or {#clear()} is called.]===], - params = { - {"number", "delay", "Number of seconds between two consecutive function calls."}, - {"function", "func", "The function to be called periodically."}, - {"number", "count", "Number of times the function is to be called.", optional = true}, - }, - returns = { - {"table", "The timer handle."} - }, - example = { - "Timer.addPeriodic(1, function() lamp:toggleLight() end)", - "mothership_timer:addPeriodic(0.3, function() self:spawnFighter() end, 5)", - [===[-- flicker player's image as long as he is invincible -Timer.addPeriodic(0.1, function() - player:flipImage() - return player.isInvincible -end)]===], - }, - }, - - Function { name = {"do_for", "instance:do_for"}, - short = "Run a function for the next few seconds.", - long = [===[ - Run a {#func(dt)} for the next {#delta} seconds. The function is called - every time {#update(dt)} is called. Optionally run {#after()} once - {#delta} seconds have passed. - - {#after} will receive itself as only parameter. - - The same constraints as with {#add()} apply.]===], - params = { - {"number", "delta", "Number of seconds the {#func} will be called."}, - {"function", "func", "The function to be called upon {#update(dt)}."}, - {"function", "after", "A function to be called after {#delta} seconds.", optional=true}, - }, - returns = { - {"table", "The timer handle."} - }, - example = { - [===[-- play an animation for 5 seconds -Timer.do_for(5, function(dt) animation:update(dt) end)]===], - [===[-- shake the camera for one second -local orig_x, orig_y = camera:pos() -Timer.do_for(1, function() - camera:lookAt(orig_x + math.random(-2,2), orig_y + math.random(-2,2)) -end, function() - -- reset camera position - camera:lookAt(orig_x, orig_y) -end)]===], - [===[player.isInvincible = true --- flash player for 3 seconds -local t = 0 -player.timer:do_for(3, function(dt) - t = t + dt - player.visible = (t % .2) < .1 -end, function() - -- make sure the player is visible after three seconds - player.visible = true - player.isInvincible = false -end)]===] - }, - }, - - Function { name = {"cancel", "instance:cancel"}, - short = "Cancel a scheduled function.", - long = [===[ - Prevent a timer from being executed in the future. - - {*Always} use the function handle returned by {#add()}/{#addPeriodic()} - to cancel a timer. - - {*Never} use this inside a scheduled function.]===], - params = { - {"table", "handle", "The function to be canceled."}, - }, - returns = {}, - example = { - [===[function tick() - print('tick... tock...') -end -handle = Timer.addPeriodic(1, tick) --- later -Timer.cancel(handle) -- NOT: Timer.cancel(tick)]===] - }, - }, - - Function { name = {"clear", "instance:clear"}, - short = "Remove all timed and periodic functions.", - long = [===[ - Remove all timed and periodic functions. Functions that have not yet - been executed will discarded. - - {*Never} use this inside a scheduled function.]===], - params = {}, - returns = {}, - example = "Timer.clear()", - }, - - Function { name = {"update", "instance:update"}, - short = "Update scheduled functions.", - long = "Update timers and execute functions if the deadline is reached. Use this in {#love.update(dt)}.", - params = { - {"number", "dt", "Time that has passed since the last update()."}, - }, - returns = {}, - example = [===[ -function love.update(dt) - do_stuff() - Timer.update(dt) -end]===], - }, -} - -Module { name = "hump.vector", - title = "vector", - short = "2D vector math.", - long = [===[ - A handy 2D vector class providing most of the things you do with vectors. - - You can access the individual coordinates by using {#vec.x} and {#vec.y}.]===], - - Section { name = "operators", - title = "Arithmetics and relations", - content = [===[ - 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} :Scalar multiplication (scaling). - {#vector * number = vector} :Scalar multiplication. - {#vector / number = vector} :Scalar multiplication. - ] - - 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, player.velocity and player.position are vectors -acceleration = vector(0,-9) -player.velocity = player.velocity + acceleration * dt -player.position = player.position + player.velocity * dt]===], - }, - - Function { name = "new", - short = "Create a new vector.", - long = "Create a new vector.", - params = { - {"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: -vector = require "hump.vector" -a = vector(10,10)]===], - }, - }, - - Function { name = "isvector", - short = "Test if value is a vector.", - long = "Test whether a variable is a vector.", - params = { - {"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 { name = "vector:clone", - short = "Copy a vector.", - long = [===[ - Copy a vector. Simply assigning a vector a vector to a variable will create - a reference, so when modifying the vector referenced by the new variable - would 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)']]===], - params = {}, - returns = { - {"vector", "Copy of the vector"} - }, - example = "copy = original:clone", - }, - - Function { name = "vector:unpack", - short = "Extract coordinates.", - long = "Extract coordinates.", - params = {}, - returns = { - {"numbers", "The coordinates"} - }, - example = { - "x,y = pos:unpack()", - "love.graphics.draw(self.image, self.pos:unpack())" - }, - }, - - Function { name = "vector:permul", - short = "Per element multiplication.", - long = [===[ - 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.]===], - params = { - {"vector", "other", "The other vector"} - }, - returns = { - {"vector", "The new vector as described above"} - }, - example = "scaled = original:permul(vector(1,1.5))", - }, - - Function { name = "vector:len", - short = "Get length.", - long = "Get length of a vector, i.e. {#math.sqrt(vec.x * vec.x + vec.y * vec.y)}.", - params = {}, - returns = { - {"number", "Length of the vector."} - }, - example = "distance = (a - b):len()", - }, - - Function { name = "vector:len2", - short = "Get squared length.", - long = "Get squared length of a vector, i.e. {#vec.x * vec.x + vec.y * vec.y}.", - params = {}, - returns = { - {"number", "Squared length of the vector."} - }, - 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 { name = "vector:dist", - short = "Distance to other vector.", - long = "Get distance of two vectors. The same as {#(a - b):len()}.", - params = { - {"vector", "other", "Other vector to measure the distance to."}, - }, - returns = { - {"number", "The distance of the 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 { name = "vector:normalized", - short = "Get normalized vector.", - long = [===[ - Get normalized vector, i.e. a vector with the same direction as the input - vector, but with length 1. - - This does not change the input vector, but creates a new vector.]===], - params = {}, - returns = { - {"vector", "Vector with same direction as the input vector, but length 1."} - }, - example = "direction = velocity:normalized()" - }, - - Function { name = "vector:normalize_inplace", - short = "Normalize vector in-place.", - long = [===[ - Normalize a vector, i.e. make the vector unit length. Great to use on - intermediate results. - - {!This modifies the vector. If in doubt, use {#vector:normalized()}.}]===], - params = {}, - returns = { - {"vector", "Itself - the normalized vector"} - }, - example = "normal = (b - a):perpendicular():normalize_inplace()" - }, - - Function { name = "vector:rotated", - short = "Get rotated vector.", - long = [===[ - Get a rotated vector. - - This does not change the input vector, but creates a new vector.]===], - params = { - {"number", "phi", "Rotation angle in [^http://en.wikipedia.org/wiki/Radians 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 = { - "vector-rotated.png", "sketch of rotated vectors", width = 260, height = 171 - }, - }, - - Function { name = "vector:rotate_inplace", - short = "Rotate vector in-place.", - long = [===[ - Rotate a vector in-place. Great to use on intermediate results. - - {!This modifies the vector. If in doubt, use {#vector:rotate()}}]===], - params = { - {"number", "phi", "Rotation angle in [^http://en.wikipedia.org/wiki/Radians radians]."} - }, - returns = { - {"vector", "Itself - the rotated vector"} - }, - example = [===[ --- ongoing rotation -spawner.direction:rotate_inplace(dt)]===], - }, - - Function { name = "vector:perpendicular", - short = "Get perpendicular vector.", - long = [===[ - Quick rotation by 90°. Creates a new vector. The same (but faster) as - {#vec:rotate(math.pi/2)}]===], - params = {}, - returns = { - {"vector", "A vector perpendicular to the input vector"} - }, - example = "normal = (b - a):perpendicular():normalize_inplace()", - sketch = { - "vector-perpendicular.png", "sketch of perpendicular vectors", width = 267, height = 202 - }, - }, - - Function { name = "vector:projectOn", - short = "Get projection onto another vector.", - long = "Project vector onto another vector (see sketch).", - params = { - {"vector", "v", "The vector to project on."} - }, - returns = { - {"vector", "The projected vector."} - }, - example = "velocity_component = velocity:projectOn(axis)", - sketch = { - "vector-projectOn.png", "sketch of vector projection", width = 605, height = 178 - }, - }, - - Function { name = "vector:mirrorOn", - short = "Mirrors vector on other vector", - long = "Mirrors vector on the axis defined by the other vector.", - params = { - {"vector", "v", "The vector to mirror on."} - }, - returns = { - {"vector", "The mirrored vector."} - }, - example = "deflected_velocity = ball.velocity:mirrorOn(surface_normal)", - sketch = { - "vector-mirrorOn.png", "sketch of vector mirroring on axis", width = 334, height = 201 - }, - }, - - Function { name = "vector:cross", - short = "Cross product of two vectors.", - long = [===[ - Get cross product of both vectors. Equals the area of the parallelogram - spanned by both vectors.]===], - params = { - {"vector", "other", "Vector to compute the cross product with."} - }, - returns = { - {"number", "Cross product of both vectors."} - }, - example = "parallelogram_area = a:cross(b)", - sketch = { - "vector-cross.png", "sketch of vector cross product", width = 271, height = 137 - }, - }, -} - - -Module { name = "hump.vector-light", - title = "vector-light", - short = "Lightweight 2D vector math.", - long = [===[ - An table-free version of {#hump.vector}. Instead of a vector class, {#hump.vector-light} provides functions that operate on numbers. - - Using this module instead of {#vector} might result in faster code, but does so at the expense of readability. Unless you are sure that it causes a significant performance penalty, I recommend to use {#hump.vector}.]===], - - - Function { name = "str", - short = "String representation.", - long = "Transforms a vector to a string of the form {#(x,y)}.", - params = { - {"numbers", "x,y", "The vector"} - }, - returns = { - {"string", "The string representation"} - }, - example = { - "print(vector.str(love.mouse.getPosition()))", - } - }, - - Function { name = { "mul", "div" }, - short = { - "Product of a vector and a scalar.", - "Product of a vector and the inverse of a scalar.", - }, - long = "Computes {#x*s,y*s} and {#x/s,y/s} respectively. The order of arguments is chosen so that it's possible to chain multiple operations (see example).", - params = { - {"number", "s", "The scalar."}, - {"numbers", "x,y", "The vector."}, - }, - returns = { - {"numbers", "The result of the operation."} - }, - example = { - "velx,vely = vec.mul(dt, vec.add(velx,vely, accx,accy))", - "x,y = vec.div(self.zoom, x-w/2, y-h/2)", - }, - }, - - Function { name = { "add", "sub" }, - short = { - "Sum of two vectors.", - "Difference of two vectors.", - }, - long = "Computes the sum/difference of vectors. Same as {#x1+x2,y1+y2} and {#x1-x2,y1-y2} respectively. Meant to be used in conjunction with other functions.", - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"numbers", "The result of the operation."} - }, - example = { - "player.x,player.y = vector.add(player.x,player.y, vector.mul(dt, dx,dy))", - "dx,dy = vector.sub(400,300, love.mouse.getPosition())", - }, - }, - - Function { name = "permul", - short = "Per element multiplication.", - long = [===[ - Multiplies vectors coordinate wise, i.e. {#x1*x2,y1*y2}.]===], - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"numbers", "The result of the operation."} - }, - example = "x,y = vector.permul(x,y, 1,1.5)", - }, - - Function { name = "dot", - short = "[^http://en.wikipedia.org/wiki/Dot_product Dot product]", - long = "Computes the [^http://en.wikipedia.org/wiki/Dot_product dot product] of two vectors, {#x1*x2+y1*y2}.", - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"number", "The dot product."} - }, - example = "cosphi = vector.dot(rx,ry, vx,vy)" - }, - - Function { name = {"det", "cross"}, - short = { "Cross product", "Cross product", }, - long = "Computes the cross product/determinant of two vectors, {#x1*y2-y1*x2}.", - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"number", "The cross product."} - }, - example = "parallelogram_area = vector.det(ax,ay, bx,by)" - }, - - Function { name = {"eq", "le", "lt"}, - short = { "Equality.", "Partial lexical order.", "Strict lexical order." }, - long = [===[Compares two vectors according to [| - {#vector.eq(x1,y1, x2,y2)} :{#x1 == x2 and y1 == y2} - {#vector.le(x1,y1, x2,y2)} :{#x1 <= x2 and y1 <= y2} - {#vector.lt(x1,y1, x2,y2)} :{#x1 < x2 or (x1 == x2) and y1 <= y2} - ] - ]===], - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"boolean", "The result of the operation."} - }, - example = "..." - }, - - Function { name = "len", - short = "Get length.", - long = "Get length of a vector, i.e. {#math.sqrt(x*x + y*y)}.", - params = { - {"numbers", "x,y", "The vector."} - }, - returns = { - {"number", "Length of the vector."} - }, - example = "distance = vector.len(love.mouse.getPosition())", - }, - - Function { name = "len2", - short = "Get squared length.", - long = "Get squared length of a vector, i.e. {#x*x + y*y}.", - params = { - {"numbers", "x,y", "The vector."} - }, - returns = { - {"number", "Squared length of the vector."} - }, - example = [===[ --- get closest vertex to a given vector -closest, dsq = vertices[1], vector.len2(px-vertices[1].x, py-vertices[1].y) -for i = 2,#vertices do - local temp = vector.len2(px-vertices[i].x, py-vertices[i].y) - if temp < dsq then - closest, dsq = vertices[i], temp - end -end]===], - }, - - Function { name = "dist", - short = "Distance of two points.", - long = "Get distance of two points. The same as {#vector.len(x1-x2, y1-y2)}.", - params = { - {"numbers", "x1,y1", "First vector."}, - {"numbers", "x2,y2", "Second vector."}, - }, - returns = { - {"number", "The distance of the points."} - }, - example = [===[ --- get closest vertex to a given vector --- slightly slower than the example using len2() -closest, dist = vertices[1], vector.dist(px,py, vertices[1].x,vertices[1].y) -for i = 2,#vertices do - local temp = vector.dist(px,py, vertices[i].x,vertices[i].y) - if temp < dist then - closest, dist = vertices[i], temp - end -end]===], - }, - - Function { name = "normalize", - short = "Normalize vector.", - long = [===[ - Get normalized vector, i.e. a vector with the same direction as the input - vector, but with length 1.]===], - params = { - {"numbers", "x,y", "The vector."}, - }, - returns = { - {"numbers", "Vector with same direction as the input vector, but length 1."} - }, - example = "dx,dy = vector.normalize(vx,vy)" - }, - - Function { name = "rotate", - short = "Rotate vector.", - long = "Get a rotated vector.", - params = { - {"number", "phi", "Rotation angle in [^http://en.wikipedia.org/wiki/Radians radians]."}, - {"numbers", "x,y", "The vector."}, - }, - returns = { - {"numbers", "The rotated vector"} - }, - example = [===[ --- approximate a circle -circle = {} -for i = 1,30 do - local phi = 2 * math.pi * i / 30 - circle[i*2-1], circle[i*2] = vector.rotate(phi, 0,1) -end]===], - }, - - Function { name = "perpendicular", - short = "Get perpendicular vector.", - long = "Quick rotation by 90°. The same (but faster) as {#vector.rotate(math.pi/2, x,y)}", - params = { - {"numbers", "x,y", "The vector."}, - }, - returns = { - {"numbers", "A vector perpendicular to the input vector"} - }, - example = "nx,ny = vector.normalize(vector.perpendicular(bx-ax, by-ay))", - }, - - Function { name = "project", - short = "Project projection onto another vector.", - long = "Project vector onto another vector.", - params = { - {"numbers", "x,y", "The vector to project."}, - {"numbers", "u,v", "The vector to project onto."}, - }, - returns = { - {"numbers", "The projected vector."} - }, - example = "vx_p,vy_p = vector.project(vx,vy, ax,ay)", - }, - - Function { name = "mirror", - short = "Mirrors vector on other vector.", - long = "Mirrors vector on the axis defined by the other vector.", - params = { - {"numbers", "x,y", "The vector to mirror."}, - {"numbers", "u,v", "The vector defining the axis."}, - }, - returns = { - {"numbers", "The mirrored vector."} - }, - example = "vx,vy = vector.mirror(vx,vy, surface.x,surface.y)", - }, -} - -Module { name = "hump.class", - title = "Class", - short = "Class-based object orientated programming for Lua", - long = "A small, fast class implementation with multiple inheritance support", - - Function { name = "new", - short = "Declare a new class.", - long = [===[ - Declare a new class. - - The constructor will receive the newly create object as first argument. - - You can check if an object is an instance of a class using {#object:is_a()}. - - The name of the variable that holds the module can be used as a shortcut to - {#new()} (see example).]===], - params = { table_argument = true, - {"function", "constructor", "Class constructor. Can be accessed with {#theclass.construct(object, ...)}", optional = true}, - {"string", "the_name", "Class name (used only to make the class compliant to {#tostring()}.", name = "name", optional = true}, - {"class or table of classes", "super", "Classes to inherit from. Can either be a single class or a table of classes", name = "inherits", optional = true}, - }, - returns = { - {"class", "The class"} - }, - example = { -[===[ -Class = require 'hump.class' -- `Class' is now a shortcut to new() - --- define unnamed class -Feline = Class{function(self, size, weight) - self.size = size - self.weight = weight -end} -print(Feline) -- prints ' - --- 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 class with explicit name 'Feline' -Feline = Class{name = "Feline", function(self, size, weight) - self.size = size - self.weight = weight -end} - -garfield = Feline(.7, 45) -print(Feline, garfield) -- prints ' >' -]===], -[===[ -Class = require 'hump.class' -A = Class{} -function A:foo() - print('foo') -end - -B = Class{} -function B:bar() - print('bar') -end - --- single inheritance -C = Class{inherits = A} -instance = C() -instance:foo() -- prints 'foo' - --- multiple inheritance -D = Class{inherits = {A,B}} -instance = D() -instance:foo() -- prints 'foo' -instance:bar() -- prints 'bar' -]===], - }, - }, - - Function { name = "class.construct", - short = "Call class constructor.", - long = [===[ - Calls class constructor of a class on an object - - Derived classes use this function their constructors to initialize the - parent class(es) portions of the object.]===], - params = { - {"Object", "object", "The object. Usually {#self}."}, - {"mixed", "...", "Arguments to pass to the constructor"}, - }, - returns = { - {"mixed", "Whatever the parent class constructor returns"}, - }, - example = { -[===[ -Class = require 'hump.class' - -Shape = Class{function(self, area) - self.area = area -end} -function Shape:__tostring() - return "area = " .. self.area -end - -Rectangle = Class{inherits = Shape, function(self, width, height) - Shape.construct(self, width * height) - self.width = width - self.height = height -end} -function Rectangle:__tostring() - local strs = { - "width = " .. self.width, - "height = " .. self.height, - Shape.__tostring(self) - }, - return table.concat(strs, ", ") -end - -print( Rectangle(2,4) ) -- prints 'width = 2, height = 4, area = 8' -]===], -[===[ -Menu = Class{function(self) - self.entries = {} -end} -function Menu:add(title, entry) - self.entries[#self.entries + 1] = entry -end -function Menu:display() - -- ... -end - -Entry = Class{function(self, title, command) - self.title = title - self.command = command -end} -function Entry:execute() - return self.command() -end - -Submenu = Class{inherits = {Menu, Entry}, function(self, title) - Menu.construct(self) - -- redirect self:execute() to self:display() - Entry.construct(self, title, Menu.display) -end} -]===] - }, - - }, - - Function { name = "class:inherit", - short = "Explicit class inheritance/mixin support.", - long = [===[ - Inherit functions and variables of another class, if they are not already - defined for the class. This is done by simply copying the functions and - variables over to the subclass. The Lua rules for copying apply - (i.e. tables are referenced, functions and primitive types are copied by value). - - {!Be careful with changing table values in a subclass: This will change the - value in the parent class too.} - - If more than one parent class is specified, inherit from all of these, in - order of occurrence. That means that when two parent classes define the same - method, the one from the first class will be inherited. - - Note: {#class:inherit()} doesn't actually care if the arguments supplied are - hump classes. Just any table will work.]===], - params = { - {"tables", "...", "Parent classes to inherit from"} - }, - returns = {}, - example = [===[ -Class = require 'hump.class' - -Entity = Class{function(self) - GameObjects.register(self) -end} - -Collidable = { - dispatch_collision = function(self, other, dx, dy) - if self.collision_handler[other.type]) - return collision_handler[other.type](self, other, dx, dy) - end - return collision_handler["*"](self, other, dx, dy) - end, - - collision_handler = {["*"] = function() end}, -} - -Spaceship = Class{function(self) - self.type = "Spaceship" - -- ... -end} - --- make Spaceship collidable -Spaceship:inherit(Collidable) - -function Spaceship:collision_handler["Spaceship"](other, dx, dy) - -- ... -end -]===] - }, - - Function { name = "object:is_a", - short = "Test object's type.", - long = "Tests whether an object is an instance of a class.", - params = { - {"class", "cls", "Class to test. Note: this is the class itself, {*not} the name of the class."} - }, - returns = { - {"Boolean", "{#true} if the object is an instance of the class, {#false} otherwise"} - }, - example = [===[ -Class = require 'hump.class' - -A = Class{} -B = Class{inherits=A} -C = Class{inherits=B} -a, b, c = A(), B(), C() -print(a:is_a(A), a:is_a(B), a:is_a(C)) --> true false false -print(b:is_a(A), b:is_a(B), b:is_a(C)) --> true true false -print(c:is_a(A), c:is_a(B), c:is_a(C)) --> true true true - -D = Class{} -E = Class{inherits={B,D}} -d, e = D(), E() -print(d:is_a(A), d:is_a(B), d:is_a(D)) --> false false true -print(e:is_a(A), e:is_a(B), e:is_a(D)) --> true true true -]===] - }, - - Section { name = "caveats", - title = "Caveats", - content = [===[ - Be careful when using metamethods like {#__add} or {#__mul}: If 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{inherits = A, function(self, x, y) A.construct(self, x) self.y = y end} -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] - - Note that while you can define the {#__index} metamethod of the class, this - is not a good idea: It will break the class. To add a custom {#__index} - metamethod without breaking the class system, you have to use {#rawget()}. - But beware that this won't affect subclasses: - [%Class = require 'hump.class' - -A = Class{} -function A:foo() print('bar') end - -function A:__index(key) - print(key) - return rawget(A, key) -end - -instance = A() -instance:foo() -- prints foo bar - -B = Class{inherits = A} -instance = B() -instance:foo() -- prints only foo]]===], - }, -} - -Module { name = "hump.signal", - title = "Signal", - short = "Simple Signal/Slot (aka. Observer) implementation.", - long = [===[ - A simple yet effective implementation of - [^http://en.wikipedia.org/wiki/Signals_and_slots Signals and Slots], also - known as [^http://en.wikipedia.org/wiki/Observer_pattern Observer pattern]: - Functions can be dynamically bound to {*signals}. When a signal is - {*emitted}, all registered functions will be invoked. Simple as that. - - {#hump.signal} makes things more interesing by allowing to emit all signals - that match a [^http://www.lua.org/manual/5.1/manual.html#5.4.1 Lua string - pattern].]===], - - Function { name = "new", - short = "Create new signal registry.", - long = [===[ - {!If you don't need multiple independent registries, you can use the - global/default registry (see examples).} - - Creates a new signal registry that is independent of the default - registry: It will manage it's own list of signals and does not in any - way affect the the global registry. Likewise, the global registry does - not affect the instance. - - {!Note:} Independent registries use the colon-notation (e.g. - {#instance:emit("foo")}), while the global registry uses the - dot-notation (e.g. {#Signal.emit("foo")}).]===], - params = {}, - returns = { - {"Registry", "A new signal registry."}, - }, - example = "player.signals = Signals.new()" - }, - - Function { name = {"register", "instance:register"}, - short = "Register function with a signal.", - long = [===[ - Registers a function {#f} to be called when signal {#s} is emitted. - ]===], - params = { - {"string", "s", "The signal identifier."}, - {"function", "f", "The function to register."} - }, - returns = { - {"function", "A function handle to use in {#remove}."} - }, - example = { - "Signal.register('level-complete', function() self.fanfare:play() end)", - "handle = Signal.register('level-load', function(level) level.show_help() end)", - "menu:register('key-left', select_previous_item)" - } - }, - - Function { name = {"emit", "instance:emit"}, - short = "Call all functions bound to a signal.", - long = [===[ - Calls all functions bound to signal {#s} with the supplied arguments. - ]===], - params = { - {"string", "s", "The signal identifier."}, - {"mixed", "...", "Arguments to pass to the bound functions.", optional = true}, - }, - returns = {}, - example = { - [===[function love.keypressed(key) - if key == 'left' then menu:emit('key-left') end -end]===], - [===[if level.is_finished() then - Signal.emit('level-load', level.next_level) -end]===], - [===[function on_collide(dt, a,b, dx,dy) - a.signals:emit('collide', b, dx, dy) - b.signals:emit('collide', a, -dx,-dy) -end]===] - } - }, - - Function { name = {"remove", "instance:remove"}, - short = "Remove functions from registry.", - long = [===[ - Unbinds (removes) functions from signal {#s}. - ]===], - params = { - {"string", "s", "The signal identifier."}, - {"functions", "...", "Functions to unbind from the signal."} - }, - returns = {}, - example = { - "Signal.remove('level-load', handle)", - } - }, - - Function { name = {"clear", "instance:clear"}, - short = "Clears a signal registry.", - long = [===[ - Removes all functions from signal {#s}. - ]===], - params = { - {"string", "s", "The signal identifier."}, - }, - returns = {}, - example = "Signal.clear('key-left')", - }, - - Function { name = {"emit_pattern", "instance:emit_pattern"}, - short = "Emits signals matching a pattern.", - long = [===[ - Emits all signals matching a - [^http://www.lua.org/manual/5.1/manual.html#5.4.1 string pattern]. - ]===], - params = { - {"string", "p", "The signal identifier pattern."}, - {"mixed", "...", "Arguments to pass to the bound functions.", optional = true}, - }, - returns = {}, - example = "Signal.emit_pattern('^update%-.*', dt)", - }, - - Function { name = {"remove_pattern", "instance:remove_pattern"}, - short = "Remove functions from signals matching a pattern.", - long = [===[ - Removes functions from all signals matching a - [^http://www.lua.org/manual/5.1/manual.html#5.4.1 string pattern]. - ]===], - params = { - {"string", "p", "The signal identifier pattern."}, - {"functions", "...", "Functions to unbind from the signals."} - }, - returns = {}, - example = "Signal.remove_pattern('key%-.*', play_click_sound)", - }, - - Function { name = {"clear_pattern", "instance:clear_pattern"}, - short = "Clears signal registry matching a pattern.", - long = [===[ - Removes all functions from all signals matching a - [^http://www.lua.org/manual/5.1/manual.html#5.4.1 string pattern]. - ]===], - params = { - {"string", "p", "The signal identifier pattern."}, - }, - returns = {}, - example = { - "Signal.clear_pattern('sound%-.*')", - "Signal.clear_pattern('.*') -- clear all signals", - } - } -} - -Module { name = "hump.camera", - title = "Camera", - short = "A camera for LÖVE", - long = [===[ - A camera utility for LÖVE. A camera can "look" at a position. It can zoom in and - out and it can rotate it's view. In the background, this is done by actually - moving, scaling and rotating everything in the game world. But don't worry about - that.]===], - - Function { name = "new", - short = "Create a new camera.", - long = [===[ - Creates a new camera. You can access the camera position using - {#camera.x, camera.y}, the zoom using {#camera.zoom} and the rotation using - {#camera.rot}. - - The module variable name can be used at a shortcut to {#new()}.]===], - - params = { - {"numbers", "x,y", "Point for the camera to look at.", default = "screen center"}, - {"number", "zoom", "Camera zoom.", default = "1"}, - {"number", "rot", "Camera rotation in radians.", default = "0"}, - }, - - returns = { - {"camera", "A new camera."} - }, - - example = [===[ -camera = require 'hump.camera' - --- camera looking at (100,100) with zoom 2 and rotated by 45 degrees -cam = camera(100,100, 2, math.pi/2) -]===] - }, - - Function { name = "camera:rotate", - short = "Rotate camera.", - long = [===[ - Rotate the camera {*by} some angle. To {*set} the angle use - {#camera.rot = new_angle}. - - This function is shortcut to {#camera.rot = camera.rot + angle}.]===], - - params = { - {"number", "angle", "Rotation angle in radians"} - }, - - returns = { - {"camera", "The camera."} - }, - - example = { - "function love.update(dt)\n camera:rotate(dt)\nend", - "function love.update(dt)\n camera:rotate(dt):move(dt,dt)\nend" - }, - }, - - Function { name = "camera:rotation", - short = "Get or set camera rotation.", - long = [===[Returns {#camera.rot}. - - If given an angle, set rotation: {#camera.rot = angle}.]===], - - params = { - {"number", "angle", "Rotation angle in radians", optional = true} - }, - - returns = { - {"number", "Rotation angle in radians."} - }, - - example = { - [===[love.graphics.print(camera:rotation(), 10, 10)]===], - [===[camera:rotation(math.pi/2)]===], - } - }, - - Function { name = "camera:move", - short = "Move camera.", - long = [===[ - {*Move} the camera {*by} some vector. To {*set} the position, use {#camera:lookAt(x,y)}. - - This function is shortcut to {#camera.x,camera.y = camera.x+dx, camera.y+dy}.]===], - - params = { - {"numbers", "dx,dy", "Direction to move the camera."}, - }, - - returns = { - {"camera", "The camera."}, - }, - - example = { - "function love.update(dt)\n camera:move(dt * 5, dt * 6)\nend", - "function love.update(dt)\n camera:move(dt * 5, dt * 6):rotate(dt)\nend" - }, - }, - - Function { name = "camera:lookAt", - short = "Move camera to a position.", - long = [===[ - Let the camera look at a point. In other words, it {*sets} the camera position. - To {*move} the camera {*by} some amount, use {#camera:move(x,y)}. - - This function is shortcut to {#camera.x,camera.y = x, y}.]===], - - params = { - {"numbers", "x,y", "Position to look at."}, - }, - - returns = { - {"camera", "The camera."}, - }, - - example = { - "function love.update(dt)\n camera:lookAt(player.pos:unpack())\nend", - "function love.update(dt)\n camera:lookAt(player.pos:unpack()):rotation(player.rot)\nend", - }, - }, - - Function { name = "camera:pos", - short = "Get camera position..", - long = [===[Returns {#camera.x, camera.y}.]===], - - params = {}, - - returns = { - {"numbers", "Camera position."}, - }, - - example = [===[-- let the camera fly! -local cam_dx, cam_dy = 0, 0 -function love.mousereleased(x,y) - local cx,cy = camera:position() - dx, dy = x-cx, y-cy -end - -function love.update(dt) - camera:move(dx * dt, dy * dt) -end]===], - }, - - Function { name = "camera:attach", - short = "Attach camera.", - long = [===[ - Start looking through the camera. - - Apply camera transformations, i.e. move, scale and rotate everything until - {#camera:detach()} as if looking through the camera.]===], - - params = {}, - returns = {}, - - example = [===[ -function love.draw() - camera:attach() - draw_world() - cam:detach() - - draw_hud() -end]===] - }, - - Function { name = "camera:detach", - short = "Detach camera.", - long = "Stop looking through the camera.", - - params = {}, - returns = {}, - - example = [===[ -function love.draw() - camera:attach() - draw_world() - cam:detach() - - draw_hud() -end]===] - }, - - Function { name = "camera:draw", - short = "Attach, draw and detach.", - long = [===[ - Wrap a function between a {#camera:attach()}/{#camera:detach()} pair: - [%cam:attach() -func() -cam:detach()]]===], - - params = { - {"function", "func", "Drawing function to be wrapped."}, - }, - - returns = {}, - - example = [===[ -function love.draw() - camera:draw(draw_world) - draw_hud() -end]===] - }, - - Function { name = { - "camera:worldCoords", - "camera:cameraCoords", - }, - short = { - "Convert point to world coordinates.", - "Convert point to camera coordinates.", - }, - long = [===[ - Because a camera has a point it looks at, a rotation and a zoom factor, it - defines a coordinate system. A point now has two sets of coordinates: One - defines where the point is to be found in the game world, and the other - describes the position on the computer screen. The first set of coordinates - is called {*world coordinates}, the second one {*camera coordinates}. - - Sometimes it is needed to convert between the two coordinate systems, for - example to get the position of a mouse click in the game world in a strategy - game, or to see if an object is visible on the screen. - - These two functions convert a point between these two coordinate systems.]===], - - params = { - {"numbers", "x, y", "Point to transform."}, - }, - - returns = { - {"numbers", "Transformed point."}, - }, - - example = { - [===[ -x,y = camera:worldCoords(love.mouse.getPosition()) -selectedUnit:plotPath(x,y) -]===], [===[ -x,y = cam:cameraCoords(player.pos) -love.graphics.line(x, y, love.mouse.getPosition()) -]===] - }, - }, - - Function { name = "camera:mousepos", - short = "Get mouse position in world coordinates.", - long = "Shortcut to {#camera:worldCoords(love.mouse.getPosition())}.", - params = {}, - returns = { - {"numbers", "Mouse position in world coordinates."}, - }, - example = [===[ -x,y = camera:mousepos() -selectedUnit:plotPath(x,y) -]===], - }, -} - -Module { name = "hump.ringbuffer", - title = "Ringbuffer", - short = "A data structure that wraps around itself.", - long = [===[ - A ring-buffer is a circular array: It does not have a first nor a last item, - but it has a {*selected} or {*current} element. - - A ring-buffer can be used to implement {*Tomb Raider} style inventories, looping - play-lists, recurring dialogs (like a unit's answers when selecting it multiple - times in {*Warcraft}) and generally everything that has a circular or looping - structure.]===], - - Function { name = "new", - short = "Create new ring-buffer.", - long = "Create new ring-buffer.\n\nThe module name is a shortcut to this function.", - params = { - {"mixed", "...", "Initial elements."} - }, - returns = { - {"Ringbuffer", "The ring-buffer object."}, - }, - example = [===[ -Ringbuffer = require 'hump.ringbuffer' - -rb = ringbuffer(1,2,3) -]===] - }, - - Function { name = "ringbuffer:insert", - short = "Insert element.", - long = "Insert items behind current element.", - - params = { - {"mixed", "...", "Items to insert."}, - }, - - returns = {}, - - example = [===[ -rb = RingbuffeR(1,5,6) -- content: 1,5,6 -rb:insert(2,3,4) -- content: 1,2,3,4,5,6 -]===] - }, - - Function { name = "ringbuffer:remove", - short = "Remove currently selected item.", - long = "Remove current item, return it and select next element.", - - params = {}, - - returns = { - {"mixed", "The removed item."} - }, - - example = [===[ -rb = Ringbuffer(1,2,3,4) -- content: 1,2,3,4 -val = rb:remove() -- content: 2,3,4 -print(val) -- prints `1' -]===] - }, - - Function { name = "ringbuffer:removeAt", - short = "Remove an item.", - long = "Remove the item at a position relative to the current element.", - - params = { - {"number", "pos", "Position of the item to remove."} - }, - - returns = { - {"mixed", "The removed item."} - }, - - 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 { name = "ringbuffer:next", - short = "Select next item.", - long = "Select and return the next element.", - - params = {}, - - returns = { - {"mixed", "The next item."} - }, - - example = [===[ -rb = Ringbuffer(1,2,3) -rb:next() -- content: 2,3,1 -rb:next() -- content: 3,1,2 -x = rb:next() -- content: 1,2,3 -print(x) -- prints `1' -]===] - }, - - Function { name = "ringbuffer:prev", - short = "Select previous item.", - long = "Select and return the previous item.", - - params = {}, - - returns = { - {"mixed", "The previous item."} - }, - - example = [===[ -rb = Ringbuffer(1,2,3) -rb:prev()) -- content: 3,1,2 -rb:prev()) -- content: 2,3,1 -x = rb:prev() -- content: 1,2,3 -print(x) -- prints `1' -]===] - }, - - Function { name = "ringbuffer:get", - short = "Get currently selected item.", - long = "Return the current element.", - - params = {}, - - returns = { - {"mixed", "The currently selected element."} - }, - - example = [===[ -rb = Ringbuffer(1,2,3) -rb:next() -- content: 2,3,1 -print(rb:get()) -- prints '2' -]===] - }, - - Function { name = "ringbuffer:size", - short = "Get ringbuffer size.", - long = "Get number of items in the buffer", - - params = {}, - - 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' -]===] - }, -} diff --git a/doctool b/doctool new file mode 160000 index 0000000..72f4c13 --- /dev/null +++ b/doctool @@ -0,0 +1 @@ +Subproject commit 72f4c13759edf79a6780096a3278bfedbb4ed3e7 diff --git a/doctool-theme.lua b/doctool-theme.lua new file mode 100644 index 0000000..3a85ab0 --- /dev/null +++ b/doctool-theme.lua @@ -0,0 +1,241 @@ +local discount = function(s) return (require 'discount')(s, "nopants") end +local actions = {} + +local function filter(t, p) + local r = {} + for _,v in ipairs(t) do + if p(v) then r[#r+1] = v end + end + return r +end + +-- generic +function actions.textblock(info) + return discount(info[1]) +end + +function actions.section(info) + local htype = 'h'..(info[3]+1) + if info[3] >= 3 then + return table.concat{ + '
', + '<',htype,'>', info[1], '^top', + discount(info[4]), + '
' + } + end + return table.concat{ + '
', + '<',htype,'>', info[1], '^top', + '
', discount(info[4]), '
', + '
' + } +end + +-- function +function actions.parameters(info) + return discount(info[1]):gsub('
([^<]+)
', function(m) + local type, what, optional = m:match("(%S+) ([^%(]+)( %b())") + if not type then + optional, type, what = '', m:match("(%S+) ([^%(]+)%s*") + end + assert(type and what and optional, "Invalid parameter description: " .. m) + return table.concat{'
', type, ' ', what, '', optional, '
'} + end) +end + +function actions.returns(info) + return discount(info[1]) +end + +function actions.example(info) + return discount(info[1]) +end + +function actions.sketch(info) + return discount(info[1]) +end + +actions['function'] = function(info) + local arg_delim = info.has_table_args and {'{','}'} or {'(',')'} + local out = { + '
', + '

', + 'function ', info[1], '', + '', arg_delim[1], info[2], arg_delim[2], '', + '^top

', + discount(info[4]) + } + + -- parameter list + local parameters = filter(info[5], function(v) return v.type == 'parameters' end) + out[#out+1] = '
' + out[#out+1] = 'Parameters:' + if #parameters == 0 then + out[#out+1] = '
None
' + else + for _, r in ipairs(parameters) do + out[#out+1] = actions.parameters(r) + end + end + out[#out+1] = '
' + + -- returns list + local returns = filter(info[5], function(v) return v.type == 'returns' end) + out[#out+1] = '
' + out[#out+1] = 'Returns:' + if #returns == 0 then + out[#out+1] = '
Nothing
' + else + for _, r in ipairs(returns) do + out[#out+1] = actions.returns(r) + end + end + out[#out+1] = '
' + + -- examples + local examples = filter(info[5], function(v) return v.type == 'example' end) + assert(#examples > 0, "No examples given for function " .. info[1] .. "()") + out[#out+1] = '
' + out[#out+1] = #examples > 1 and 'Examples:' or 'Example:' + for _,s in ipairs(examples) do + out[#out+1] = actions.example(s) + end + out[#out+1] = '
' + + -- sketch + local sketch = filter(info[5], function(v) return v.type == 'sketch' end) + if #sketch > 0 then + out[#out+1] = '
' + out[#out+1] = #sketch > 1 and 'Sketches:' or 'Sketch:' + for _,s in ipairs(sketch) do + out[#out+1] = actions.sketch(s) + end + out[#out+1] = '
' + end + + out[#out+1] = '
' + return table.concat(out) +end + +-- module +function actions.module(info) + local modname = info[1] + local out = { + '
', + '

', modname, '^top

', + '
', discount(info[3]), '
' + } + + -- create module overview + out[#out+1] = '
' + out[#out+1] = '

Module overview

' + out[#out+1] = '
' + for _,info in ipairs(info[4]) do + if info.type == 'function' then + out[#out+1] = table.concat{ + '
', + '', + info[1], '()', + '', + '
', + info[3], + '
', + } + elseif info.type == 'section' then + out[#out+1] = table.concat{ + '
', + '', + info[1], + '', + '
', + info[2], + '
', + } + else + error("Unhandled module subtype: " .. info.type) + end + end + out[#out+1] = '
' + out[#out+1] = '
' + + -- create detailed reference + for _,info in ipairs(info[4]) do + local s = actions[info.type](info) + out[#out+1] = s:gsub('{{MODULE}}', modname) + end + + out[#out+1] = '
' + return table.concat(out) +end + + +-- title +function actions.title(info) + --return table.concat{'

', info[1], '

'} + return "" +end + +-- build module overview +function actions.preprocess(doctree) + local out = {} + out[#out+1] = '
' + for _, info in ipairs(filter(doctree, function(v) return v.type == 'module' end)) do + out[#out+1] = table.concat{ + '
', info[1], '
', + '
', info[2], '
', + } + end + out[#out+1] = '
' + + local mod_overview = {type = 'section', 'Modules', '', 2, table.concat(out)} + for i = 1,#doctree do + if doctree[i][1] == 'Introduction' then + table.insert(doctree, i+1, mod_overview) + break + end + end + + return doctree +end + +function actions.postprocess(out) + return table.concat{[[ + + + + +hump - LÖVE Helper Utilities for More Productivity + + + + + + + +]], + out:gsub('{{MODULE}}', ''):gsub('', ''), + "" + } +end + +return actions diff --git a/documentation.md b/documentation.md new file mode 100644 index 0000000..52d625a --- /dev/null +++ b/documentation.md @@ -0,0 +1,2241 @@ +# HUMP + +## Introduction + +Helper Utilities for a Multitude of Problems is a set of lightweight helpers for the awesome LÖVE Engine. + +hump differs from other libraries in that every component is independent of the remaining ones. hump's footprint is very small and thus should fit nicely into your projects. + + +## Module hump.gamestate [A gamestate system.] + + Gamestate = require "hump.gamestate" + +A gamestate encapsulates independent data an behaviour into a single entity. + +A typical game could consist of a menu-state, a level-state and a game-over-state. + + +### Callbacks [Gamestate Callbacks.] + +A gamestate can define all callbacks that LÖVE defines. In addition, there are +callbacks for initalizing, entering and leaving a state: + +=`init()`= + Called once before entering the state. See [`switch()`](#hump.gamestateswitch). +=`enter(previous, ...)`= + Called when entering the state. See [`switch()`](#hump.gamestateswitch). +=`leave()`= + Called when leaving a state. See [`switch()`](#hump.gamestateswitch). +=`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()`](#hump.gamestateregisterEvents), all these +callbacks will be called by the corresponding LÖVE callbacks and receive +receive the same arguments (e.g. `state:update(dt)` will be called by +`love.update(dt)`). + +#### Example: + + menu = Gamestate.new() + function menu:init() -- run only once + self.background = love.graphics.newImage('bg.jpg') + Buttons.initialize() + end + + function menu:enter(previous) -- run every time the state is entered + Buttons.setActive(Buttons.start) + 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() [Create a new gamestate.] + +Declare a new gamestate. A gamestate can define several callbacks. + +#### Returns: + +=Gamestate= + The new gamestate. + +#### Example: + + menu = Gamestate.new() + + +### function switch(to, ...) [Switch to gamestate.] + +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`, call the `init()` function +if the state was not yet inialized and finally call `enter(old_state, ...)` on +the new gamestate. + + +#### Parameters: + +=Gamestate to= + Target gamestate. +=mixed ...= + Additional arguments to pass to `to:enter(current, ...)`. + + +#### Returns: + +=mixed= + The results of `to:enter(current, ...)` + +#### Example: + + Gamestate.switch(game, level_two) + + +### function <callback>(...) [Call function on active gamestate.] + +Calls a function on the current gamestate. Can be any function, but is intended to +be one of the [callbacks](#hump.gamestateCallbacks). Mostly useful when not using +[`registerEvents()`](#hump.gamestateregisterEvents). + +#### Parameters: + +=mixed ...= + Arguments to pass to the corresponding function. + +#### Returns: + +=mixed= + The result of the callback function. + +#### Example: + + function love.draw() + Gamestate.draw() -- is `draw' + end + + function love.update(dt) + Gamestate.update(dt) -- pass dt to currentState:update(dt) + end + + function love.keypressed(key, code) + Gamestate.keypressed(key, code) -- pass multiple arguments + end + + +### function registerEvents(callbacks) [Automatically do all of the above when needed.] + +Overwrite love callbacks to call `Gamestate.update()`, `Gamestate.draw()`, etc. +automatically. love callbacks (e.g. `love.update()`) are still invoked. + +This is by done by overwriting the love callbacks, e.g.: + + local old_update = love.update + function love.update(dt) + old_update(dt) + return Gamestate.current:update(dt) + end + +**Note:** Only works when called in love.load() or any other function that is +executed *after* the whole file is loaded. + +#### Parameters: + +=table callbacks (optional)= + Names of the callbacks to register. If omitted, register all love callbacks. + +#### Example: + + function love.load() + Gamestate.registerEvents() + Gamestate.switch(menu) + end + + -- love callback will still be invoked + function love.update(dt) + Timer.update(dt) + -- no need for Gamestate.update(dt) + end + +#### Example: + + function love.load() + -- only register draw, update and quit + Gamestate.registerEvents{'draw', 'update', 'quit'} + Gamestate.switch(menu) + end + + + +## Module hump.timer [Delayed and time-limited function calls.] + + Timer = require "hump.timer" + +hump.timer offers a simple interface to schedule the execution of functions. It +is possible to run functions *after* and *for* some amount of time. For +example, a timer could be set to move critters every 5 seconds or to make the +player invincible for a short amount of time. + + +### function new() [Create new timer instance.] + +**If you don't need multiple independent schedulers, you can use the +global/default timer (see examples).** + +Creates a new timer instance that is independent of the global timer: It will +manage it's own list of scheduled functions and does not in any way affect the +the global timer. Likewise, the global timer does not affect timer instances. + +**Note:** Timer instances use the colon-notation (e.g. `instance:update(dt)`), +while the global timer uses the dot-notation (e.g. `Timer.update(dt)`). + +#### Returns: + +=Timer= + A timer instance. + +#### Example: + + menuTimer = Timer.new() + + +### function add(delay, func) [Schedule a function.] + +Schedule a function. The function will be executed after `delay` seconds have +elapsed, given that `update(dt)` is called every frame. + +**Note:** There is no guarantee that the delay will not be exceeded, it is only +guaranteed that the function will *not* be executed *before* the delay has +passed. + +`func` will receive itself as only parameter. This is useful to implement +periodic behavior (see the example). + +#### Parameters: + +=number delay= + Number of seconds the function will be delayed. +=function func= + The function to be delayed. + +#### Returns: + +=table= + The timer handle. + +#### Example: + + -- grant the player 5 seconds of immortality + player.isInvincible = true + Timer.add(5, function() player.isInvincible = false end) + +#### Example: + + -- print "foo" every second. See also addPeriodic() + Timer.add(1, function(func) print("foo") Timer.add(1, func) end) + +#### Example: + + --Using a timer instance: + menuTimer:add(1, finishAnimation) + + +### function addPeriodic(delay, func) [Add a periodic function.] + +Add a function that will be called `count` times every `delay` seconds. + +If `count` is omitted, the function will be called until it returns `false` or +[`cancel(handle)`](#hump.timercancel) or [`clear()`](#hump.timerclear) is +called. + +#### Parameters: + +=number delay= + Number of seconds between two consecutive function calls. +=function func= + The function to be called periodically. +=number count (optional)= + Number of times the function is to be called. + +#### Returns: + +=table= + The timer handle. See also [`cancel()`](#hump.timercancel). + +#### Example: + + -- toggle light on and off every second + Timer.addPeriodic(1, function() lamp:toggleLight() end) + +#### Example: + + -- launch 5 fighters in quick succession (using a timer instance) + mothership_timer:addPeriodic(0.3, function() self:launchFighter() end, 5) + +#### Example: + + -- flicker player's image as long as he is invincible + Timer.addPeriodic(0.1, function() + player:flipImage() + return player.isInvincible + end) + + +### function do_for(delay, func, after) [Run a function for the next few seconds.] + +Run `func(dt)` for the next `delta` seconds. The function is called every time +`update(dt)` is called. Optionally run `after()` once `delta` seconds have +passed. + +`after()` will receive itself as only parameter. + +**Note:** You should not add new timers in `func(dt)`, as this can lead to random +crashes. + +#### Parameters: + +=number delta= + Number of seconds the func will be called. +=function func= + The function to be called on `update(dt)`. +=function after (optional)= + A function to be called after delta seconds. + +#### Returns: + +=table= + The timer handle. + +#### Example: + + -- play an animation for 5 seconds + Timer.do_for(5, function(dt) animation:update(dt) end) + +#### Example: + + -- shake the camera for one second + local orig_x, orig_y = camera:pos() + Timer.do_for(1, function() + camera:lookAt(orig_x + math.random(-2,2), orig_y + math.random(-2,2)) + end, function() + -- reset camera position + camera:lookAt(orig_x, orig_y) + end) + +#### Example: + + player.isInvincible = true + -- flash player for 3 seconds + local t = 0 + player.timer:do_for(3, function(dt) + t = t + dt + player.visible = (t % .2) < .1 + end, function() + -- make sure the player is visible after three seconds + player.visible = true + player.isInvincible = false + end) + + +### function cancel(handle) [Cancel a scheduled function.] + +Prevent a timer from being executed in the future. + +#### Parameters: + +=table handle= + The function to be canceled. + +#### Example: + + function tick() + print('tick... tock...') + end + handle = Timer.addPeriodic(1, tick) + -- later + Timer.cancel(handle) -- NOT: Timer.cancel(tick) + + +### function clear() [Remove all timed and periodic functions.] + +Remove all timed and periodic functions. Functions that have not yet been +executed will discarded. + +#### Example: + + Timer.clear() + +#### Example: + + menu_timer:clear() + + +### function update(dt) [Update scheduled functions.] + +Update timers and execute functions if the deadline is reached. Use this in +`love.update(dt)`. + +#### Parameters: + +=number dt= + Time that has passed since the last `update()`. + +#### Example: + + function love.update(dt) + do_stuff() + Timer.update(dt) + end + +#### Example: + + -- using hump.gamestate and a timer instance + function menuState:update(dt) + self.timer:update(dt) + end + + + +## Module hump.vector [2D vector math.] + + vector = require "hump.vector" + +A handy 2D vector class providing most of the things you do with vectors. + +You can access the individual coordinates by using vec.x and vec.y. + +### Operators [Arithmetics and relations.] + +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`= + Scalar multiplication (scaling). +=`vector * number = vector`= + Scalar multiplication. +=`vector / number = vector`= + Scalar multiplication. + +Relational operators are defined, too: + +=`a == b`= + Same as `a.x == b.x and a.y == b.y`. +=`a <= b`= + Same as `a.x <= b.x and a.y <= b.y`. +=`a < b`= + Lexical sort: `a.x < b.x or (a.x == b.x and a.y < b.y)`. + +#### Example: + + -- acceleration, player.velocity and player.position are vectors + acceleration = vector(0,-9) + player.velocity = player.velocity + acceleration * dt + player.position = player.position + player.velocity * dt + + +### function new(x,y) [Create a new vector.] + +Create a new vector. + +#### Parameters: + +=numbers x,y= + Coordinates. + +#### Returns: + +=vector= + The vector. + +#### Example: + + a = vector.new(10,10) + +#### Example: + + -- as a shortcut, you can call the module like a function: + vector = require "hump.vector" + a = vector(10,10) + + +### function isvector(v) [Test if value is a vector.] + +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() [Copy a vector.] + +Copy a vector. Simply assigning a vector a vector to a variable will create a +*reference*, so when modifying the vector referenced by the new variable would +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)' + +#### Returns: + +=vector= + Copy of the vector + +#### Example: + + copy = original:clone() + + +### function vector:unpack() [Extract coordinates.] + +Extract coordinates. + +#### Returns: + +=numbers= + The coordinates + +#### Example: + + x,y = pos:unpack() + +#### Example: + + love.graphics.draw(self.image, self.pos:unpack()) + + +### function vector:permul(other) [Per element multiplication.] + +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= + The new vector as described above + +#### Example: + + scaled = original:permul(vector(1,1.5)) + + +### function vector:len() [Get length.] + +Get length of a vector, i.e. `math.sqrt(vec.x * vec.x + vec.y * vec.y)`. + +#### Returns: + +=number= + Length of the vector. + +#### Example: + + distance = (a - b):len() + + +### function vector:len2() [Get squared length.] + +Get squared length of a vector, i.e. `vec.x * vec.x + vec.y * vec.y`. + +#### Returns: + +=number= + Squared length of the vector. + +#### 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) [Distance to other vector.] + +Get distance of two vectors. The same as `(a - b):len()`. + +#### Parameters: + +=vector other= + Other vector to measure the distance to. + +#### Returns: + +=number= + The distance of the 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() [Get normalized vector.] + +Get normalized vector, i.e. a vector with the same direction as the input +vector, but with length 1. + +This does not change the input vector, but creates a new vector. + +#### Returns: + +=vector= + Vector with same direction as the input vector, but length 1. + +#### Example: + + direction = velocity:normalized() + + +### function vector:normalize_inplace() [Normalize vector in-place.] + +Normalize a vector, i.e. make the vector unit length. Great to use on +intermediate results. + +**This modifies the vector. If in doubt, use +[`vector:normalized()`](#hump.vectornormalized).** + +#### Returns: + +=vector= + Itself - the normalized vector + +#### Example: + + normal = (b - a):perpendicular():normalize_inplace() + + +### function vector:rotated(angle) [Get rotated vector.] + +Get a rotated vector. + +This does not change the input vector, but creates a new vector. + +#### Parameters: + +=number angle= + 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: + +![Rotated vector sketch](vector-rotated.png) + + +### function vector:rotate_inplace(angle) [Rotate vector in-place.] + +Rotate a vector in-place. Great to use on intermediate results. + +**This modifies the vector. If in doubt, use +[`vector:rotate()`](#hump.vectorrotate).** + +#### Parameters: + +=number angle= + Rotation angle in radians. + +#### Returns: + +=vector= + Itself - the rotated vector + +#### Example: + + -- ongoing rotation + spawner.direction:rotate_inplace(dt) + + +### function vector:perpendicular() [Get perpendicular vector.] + +Quick rotation by 90°. Creates a new vector. The same (but faster) as +`vec:rotate(math.pi/2)`. + +#### Returns: + +=vector= + A vector perpendicular to the input vector + +#### Example: + + normal = (b - a):perpendicular():normalize_inplace() + +#### Sketch: + +![Perpendiculat vector sketch](vector-perpendicular.png) + + +### function vector:projectOn(v) [Get projection onto another vector.] + +Project vector onto another vector (see sketch). + +#### Parameters: + +=vector v= + The vector to project on. + +#### Returns: + +=vector= + The projected vector. + +#### Example: + + velocity_component = velocity:projectOn(axis) + +#### Sketch: + +![Projected vector sketch](vector-projectOn.png) + + +### function vector:mirrorOn(v) [Mirrors vector on other vector] + +Mirrors vector on the axis defined by the other vector. + +#### Parameters: + +=vector v= + The vector to mirror on. + +#### Returns: + +=vector= + The mirrored vector. + +#### Example: + + deflected_velocity = ball.velocity:mirrorOn(surface_normal) + +#### Sketch: + +![Mirrored vector sketch](vector-mirrorOn.png) + + +### function vector:cross(other) [Cross product of two vectors.] + +Get cross product of both vectors. Equals the area of the parallelogram spanned +by both vectors. + +#### Parameters: + +=vector other= + Vector to compute the cross product with. + +#### Returns: + +=number= + Cross product of both vectors. + +#### Example: + + parallelogram_area = a:cross(b) + + + +## Module hump.vector-light [Lightweight 2D vector math.] + + vector = require "hump.vector-light" + +An table-free version of [`hump.vector`](#hump.vector). Instead of a vector +type, `hump.vector-light` provides functions that operate on numbers. + +**Note:** Using this module instead of [`hump.vector`](#hump.vector) might +result in faster code, but does so at the expense of readability. Unless you +are sure that it causes a significant performance penalty, I recommend using +[`hump.vector`](#hump.vector). + +### function str(x,y) [String representation.] + +Transforms a vector to a string of the form `(x,y)`. + +#### Parameters: + +=numbers x,y= + The vector + +#### Returns: +=string= + The string representation + +#### Example: + + print(vector.str(love.mouse.getPosition())) + +### function mul(s, x,y) [Product of a vector and a scalar.] + +Computes `x*s,y*s`. The order of arguments is chosen so that it's possible to +chain multiple operations (see example). + +#### Parameters: + +=number s= + The scalar. += numbers x,y= + The vector. + +#### Returns: + +=numbers= + `x*s, y*s` + +#### Example: + + velx,vely = vec.mul(dt, vec.add(velx,vely, accx,accy)) + + +### function mul(s, x,y) [Product of a vector and the inverse of a scalar.] + +Computes `x/s,y/s`. The order of arguments is chosen so that it's possible to +chain multiple operations. + +#### Parameters: + +=number s= + The scalar. += numbers x,y= + The vector. + +#### Returns: + +=numbers= + `x/s, y/s` + +#### Example: + + x,y = vec.div(self.zoom, x-w/2, y-h/2) + + +### function add(x1,y1, x2,y2) [Sum of two vectors.] + +Computes the sum (`x1+x2,y1+y2`) of two vectors. Meant to be used in +conjunction with other functions. + +#### Parameters: + +=numbers x1,y1= + First vector. += numbers x2,y2= + Second vector. + +#### Returns: + +=numbers= + `x1+x2, x1+x2` + +#### Example: + + player.x,player.y = vector.add(player.x,player.y, vector.mul(dt, dx,dy)) + +### function sub(x1,y1, x2,y2) [Difference of two vectors.] + +Computes the difference (`x1-x2,y1-y2`) of two vectors. Meant to be used in +conjunction with other functions. + +#### Parameters: + +=numbers x1,y1= + First vector. += numbers x2,y2= + Second vector. + +#### Returns: + +=numbers= + `x1-x2, x1-x2` + +#### Example: + + dx,dy = vector.sub(400,300, love.mouse.getPosition()) + + +### function permul(x1,y1, x2,y2) [Per element multiplication.] + +Multiplies vectors coordinates, i.e.: `x1*x2, y1*y2`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=numbers= + `x1*x2, y1*y2` + +#### Example: + + x,y = vector.permul(x,y, 1,1.5) + +### function dot(x1,y1, x2,y2) [Dot product.] + +Computes the [dot product](http://en.wikipedia.org/wiki/Dot_product ) of two +vectors: `x1*x2 + y1*y2`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=number= + `x1*x2 + y1*y2` + +#### Example: + + cosphi = vector.dot(rx,ry, vx,vy) + +### function cross(x1,y1, x2,y2) [Cross product.] + +Computes the [cross product](http://en.wikipedia.org/wiki/Cross_product) of two +vectors, `x1*y2 - y1*x2`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=number= + `x1*y2 - y1*x2` + +#### Example: + + parallelogram_area = vector.cross(ax,ay, bx,by) + + +Alias to [`vector.cross(x1,y1, x2,y2)`]. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=number= + `x1*y2 - y1*x2` + +#### Example: + + parallelogram_area = vector.det(ax,ay, bx,by) + + +### function eq(x1,y1, x2,y2) [Equality.] + +Test for equality. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=boolean= + `x1 == x2 and y1 == y2` + +#### Example: + + if vector.eq(x1,y1, x2,y2) then be.happy() end + + +### function le(x1,y1, x2,y2) [Partial lexical order.] + +Test for partial lexical order, `<=`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=boolean= + `x1 <= x2 and y1 <= y2` + +#### Example: + + if vector.le(x1,y1, x2,y2) then be.happy() end + + +### function lt(x1,y1, x2,y2) [Strict lexical order.] + +Test for strict lexical order, `<`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=boolean= + `x1 < x2 or (x1 == x2) and y1 <= y2` + +#### Example: + + if vector.lt(x1,y1, x2,y2) then be.happy() end + +### function len(x,y) [Get length.] + +Get length of a vector, i.e. `math.sqrt(x*x + y*y)`. + +#### Parameters: + +=numbers x,y= + The vector. + +#### Returns: + +=number= + Length of the vector. + +#### Example: + + distance = vector.len(love.mouse.getPosition()) + + +### function len2(x,y) [Get squared length.] + +Get squared length of a vector, i.e. `x*x + y*y`. + +#### Parameters: + +=numbers x,y= + The vector. + +#### Returns: + +=number= + Squared length of the vector. + +#### Example: + + -- get closest vertex to a given vector + closest, dsq = vertices[1], vector.len2(px-vertices[1].x, py-vertices[1].y) + for i = 2,#vertices do + local temp = vector.len2(px-vertices[i].x, py-vertices[i].y) + if temp < dsq then + closest, dsq = vertices[i], temp + end + end + + +### function dist(x1,y1, x2,y2) [Distance of two points.] + +Get distance of two points. The same as `vector.len(x1-x2, y1-y2)`. + +#### Parameters: + +=numbers x1,y1= + First vector. +=numbers x2,y2= + Second vector. + +#### Returns: + +=number= + The distance of the points. + +#### Example: + + -- get closest vertex to a given vector + -- slightly slower than the example using len2() + closest, dist = vertices[1], vector.dist(px,py, vertices[1].x,vertices[1].y) + for i = 2,#vertices do + local temp = vector.dist(px,py, vertices[i].x,vertices[i].y) + if temp < dist then + closest, dist = vertices[i], temp + end + end + + +### function normalize(x,y) [Normalize vector.] + + Get normalized vector, i.e. a vector with the same direction as the input + vector, but with length 1. + +#### Parameters: + +=numbers x,y= + The vector. + +#### Returns: + +=numbers= + Vector with same direction as the input vector, but length 1. + +#### Example: + + dx,dy = vector.normalize(vx,vy) + + +### function rotate(phi, x,y) [Rotate vector.] + +Get a rotated vector. + +#### Parameters: + +=number phi= + Rotation angle in radians. +=numbers x,y= + The vector. + +#### Returns: + +=numbers= + The rotated vector + +#### Example: + + -- approximate a circle + circle = {} + for i = 1,30 do + local phi = 2 * math.pi * i / 30 + circle[i*2-1], circle[i*2] = vector.rotate(phi, 0,1) + end + + +### function perpendicular(x,y) [Get perpendicular vector.] + +Quick rotation by 90°. The same (but faster) as `vector.rotate(math.pi/2, x,y)`. + +#### Parameters: + +=numbers x,y= + The vector. + +#### Returns: + +=numbers= + A vector perpendicular to the input vector + +#### Example: + + nx,ny = vector.normalize(vector.perpendicular(bx-ax, by-ay)) + + +### function project(x,y, u,v) [Project vector onto another vector.] + +Project vector onto another vector. + +#### Parameters: + +=numbers x,y= + The vector to project. +=numbers u,v= + The vector to project onto. + +#### Returns: + +=numbers= + The projected vector. + +#### Example: + + vx_p,vy_p = vector.project(vx,vy, ax,ay) + + +### function mirror(x,y, u,v) [Mirror vector on other vector.] + +Mirrors vector on the axis defined by the other vector. + +#### Parameters: + +=numbers x,y= + The vector to mirror. +=numbers u,v= + The vector defining the axis. + +#### Returns: + +=numbers= + The mirrored vector. + +#### Example: + + vx,vy = vector.mirror(vx,vy, surface.x,surface.y) + + +## Module hump.class [Class-based object orientated programming for Lua.] + + Class = require "hump.class" + +A small, fast class implementation with multiple inheritance support. + +Implements [class commons](https://github.com/bartbes/Class-Commons). + + +### function new{constructor, name = the_name, inherits = super} [Declare a new class.] + +Declare a new class. + +The constructor will receive the newly create object as first argument. + +You can check if an object is an instance of a class using +[`object:is_a()`](#hump.classis_a). + +The name of the variable that holds the module can be used as a shortcut to +`new()` (see example). + +#### Parameters: + +=function constructor (optional)= + Class constructor. Can be accessed with theclass.construct(object, ...) +=string the_name (optional)= + Class name (used only to make the class compliant to tostring(). +=class or table of classes super (optional)= + Classes to inherit from. Can either be a single class or a table of classes + +#### Returns: + +=class= + The class + +#### Example: + + Class = require 'hump.class' -- `Class' is now a shortcut to new() + + -- define unnamed class + Feline = Class{function(self, size, weight) + self.size = size + self.weight = weight + end} + print(Feline) -- prints ' + + -- 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()) + +#### Example: + + Class = require 'hump.class' + + -- define class with explicit name 'Feline' + Feline = Class{name = "Feline", function(self, size, weight) + self.size = size + self.weight = weight + end} + + garfield = Feline(.7, 45) + print(Feline, garfield) -- prints ' >' + +#### Example: + + Class = require 'hump.class' + A = Class{} + function A:foo() + print('foo') + end + + B = Class{} + function B:bar() + print('bar') + end + + -- single inheritance + C = Class{inherits = A} + instance = C() + instance:foo() -- prints 'foo' + + -- multiple inheritance + D = Class{inherits = {A,B}} + instance = D() + instance:foo() -- prints 'foo' + instance:bar() -- prints 'bar' + + +### function class.construct(object, ...) [Call class constructor.] + +Calls class constructor of a class on an object. + +Derived classes use this function their constructors to initialize the parent +class(es) portions of the object. + +#### Parameters: + +=Object object= + The object. Usually `self`. +=mixed ...= + Arguments to pass to the constructor. + +#### Returns: + +=mixed= + Whatever the parent class constructor returns. + + +#### Example: + + Class = require 'hump.class' + + Shape = Class{function(self, area) + self.area = area + end} + function Shape:__tostring() + return "area = " .. self.area + end + + Rectangle = Class{inherits = Shape, function(self, width, height) + Shape.construct(self, width * height) + self.width = width + self.height = height + end} + function Rectangle:__tostring() + local strs = { + "width = " .. self.width, + "height = " .. self.height, + Shape.__tostring(self) + }, + return table.concat(strs, ", ") + end + + print( Rectangle(2,4) ) -- prints 'width = 2, height = 4, area = 8' + +#### Example: + + Menu = Class{function(self) + self.entries = {} + end} + function Menu:add(title, entry) + self.entries[#self.entries + 1] = entry + end + function Menu:display() + -- ... + end + + Entry = Class{function(self, title, command) + self.title = title + self.command = command + end} + function Entry:execute() + return self.command() + end + + Submenu = Class{inherits = {Menu, Entry}, function(self, title) + Menu.construct(self) + -- redirect self:execute() to self:display() + Entry.construct(self, title, Menu.display) + end} + +### function class:inherit(...) [Explicit class inheritance/mixin support.] + +Inherit functions and variables of another class, if they are not already +defined for the class. This is done by simply copying the functions and +variables over to the subclass. The Lua rules for copying apply (i.e. tables +are referenced, functions and primitive types are copied by value). + +**Be careful with changing table values in a subclass: This will change the +value in the parent class too.** + +If more than one parent class is specified, inherit from all of these, in order +of occurrence. That means that when two parent classes define the same method, +the one from the first class will be inherited. + +**Note:** `class:inherit()` doesn't actually care if the arguments supplied are +hump classes. Just any table will work. + +#### Parameters: + +=tables ...= + Parent classes to inherit from + +#### Example: + + Class = require 'hump.class' + + Entity = Class{function(self) + GameObjects.register(self) + end} + + Collidable = { + dispatch_collision = function(self, other, dx, dy) + if self.collision_handler[other.type]) + return collision_handler[other.type](self, other, dx, dy) + end + return collision_handler["*"](self, other, dx, dy) + end, + + collision_handler = {["*"] = function() end}, + } + + Spaceship = Class{function(self) + self.type = "Spaceship" + -- ... + end} + + -- make Spaceship collidable + Spaceship:inherit(Collidable) + + function Spaceship:collision_handler["Spaceship"](other, dx, dy) + -- ... + end + +### function object:is_a(cls) [Test object's type.] + +Tests whether an object is an instance of a class. + +#### Parameters: + +=class cls= + Class to test. **Note:** this is the class itself, not the name of the class. + +#### Returns: + +=boolean= + `true` if the object is an instance of the class, `false` otherwise + +#### Example: + + Class = require 'hump.class' + + A = Class{} + B = Class{inherits=A} + C = Class{inherits=B} + a, b, c = A(), B(), C() + print(a:is_a(A), a:is_a(B), a:is_a(C)) --> true false false + print(b:is_a(A), b:is_a(B), b:is_a(C)) --> true true false + print(c:is_a(A), c:is_a(B), c:is_a(C)) --> true true true + + D = Class{} + E = Class{inherits={B,D}} + d, e = D(), E() + print(d:is_a(A), d:is_a(B), d:is_a(D)) --> false false true + print(e:is_a(A), e:is_a(B), e:is_a(D)) --> true true true + +### Caveats [Common gotchas.] + +Be careful when using metamethods like `__add` or `__mul`: If 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{inherits = A, function(self, x, y) A.construct(self, x) self.y = y end} + 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 + +Note that while you can define the `__index` metamethod of the class, this is +not a good idea: It will break the class. To add a custom `__index` metamethod +without breaking the class system, you have to use `rawget()`. But beware that +this won't affect subclasses: + + Class = require 'hump.class' + + A = Class{} + function A:foo() print('bar') end + + function A:__index(key) + print(key) + return rawget(A, key) + end + + instance = A() + instance:foo() -- prints foo bar + + B = Class{inherits = A} + instance = B() + instance:foo() -- prints only foo + + +## Module hump.signal [Simple Signal/Slot (aka. Observer) implementation.] + +A simple yet effective implementation of [Signals and +Slots](http://en.wikipedia.org/wiki/Signals_and_slots), also known as [Observer +pattern](http://en.wikipedia.org/wiki/Observer_pattern): Functions can be +dynamically bound to signals. When a *signal* is *emitted*, all registered +functions will be invoked. Simple as that. + +`hump.signal` makes things more interesing by allowing to emit all signals that +match a [Lua string pattern](http://www.lua.org/manual/5.1/manual.html#5.4.1). + +### function new() [Create a new signal registry] + +**If you don't need multiple independent registries, you can use the +global/default registry (see examples).** + +Creates a new signal registry that is independent of the default registry: It +will manage it's own list of signals and does not in any way affect the the +global registry. Likewise, the global registry does not affect the instance. + +**Note:** Independent registries use the colon-notation (e.g. +`instance:emit("foo")`), while the global registry uses the dot-notation (e.g. +`Signal.emit("foo")`). + +#### Returns: + +=Registry= + A new signal registry. + +#### Example: + + player.signals = Signals.new() + + +### function register(s, f) [Register function with signal.] + +Registers a function `f` to be called when signal `s` is emitted. + +#### Parameters: + +=string s= + The signal identifier. +=function f= + The function to register. + +#### Returns: + +=function= + A function handle to use in [`remove()`](#hump.signalremove). + +#### Example: + + Signal.register('level-complete', function() self.fanfare:play() end) + +#### Example: + + handle = Signal.register('level-load', function(level) level.show_help() end) + +#### Example: + + menu:register('key-left', select_previous_item) + + +### function emit(s, ...) [Call all functions bound to a signal.] + +Calls all functions bound to signal `s` with the supplied arguments. + + +#### Parameters: + +=string s= + The signal identifier. +=mixed ... (optional)= + Arguments to pass to the bound functions. + +#### Example: + + function love.keypressed(key) + -- using a signal instance + if key == 'left' then menu:emit('key-left') end + end + +#### Example + + if level.is_finished() then + -- adding arguments + Signal.emit('level-load', level.next_level) + end + + +### function remove(s, ...) [Remove functions from registry. ] + +Unbinds (removes) functions from signal `s`. + +#### Parameters: + +=string s= + The signal identifier. +=functions ...= + Functions to unbind from the signal. + +#### Example: + + Signal.remove('level-load', handle) + + +### function clear(s) [Clears a signal registry.] + +Removes all functions from signal `s`. + +#### Parameters: + +=string s= + The signal identifier. + +#### Example: + + Signal.clear('key-left') + + +### function emit_pattern(p, ...) [Emits signals matching a pattern.] + +Emits all signals matching a [string pattern](http://www.lua.org/manual/5.1/manual.html#5.4.1). + +#### Parameters: + +=string p= + The signal identifier pattern. +=mixed ... (optional)= + Arguments to pass to the bound functions. + +#### Example: + + Signal.emit_pattern('^update%-.*', dt) + + +### function remove_pattern(p, ...) [Remove functions from signals matching a pattern.] + +Removes functions from all signals matching a [string pattern](http://www.lua.org/manual/5.1/manual.html#5.4.1). + +#### Parameters: + +=string p= + The signal identifier pattern. +=functions ...= + Functions to unbind from the signals. + +#### Example: + + Signal.remove_pattern('key%-.*', play_click_sound) + + +### function clear_pattern(p) [Clears signal registry matching a pattern.] + +Removes *all* functions from all signals matching a [string pattern](http://www.lua.org/manual/5.1/manual.html#5.4.1). + +#### Parameters: + +=string p= + The signal identifier pattern. + +#### Example: + + Signal.clear_pattern('sound%-.*') + +#### Example: + + player.signals:clear_pattern('.*') -- clear all signals + + +## Module hump.camera [A camera for LÖVE.] + + Camera = require "hump.camera" + +A camera utility for LÖVE. A camera can "look" at a position. It can zoom in +and out and it can rotate it's view. In the background, this is done by +actually moving, scaling and rotating everything in the game world. But don't +worry about that. + +### function new(x,y, zoom, rot) [Create a new camera.] + +Creates a new camera. You can access the camera position using `camera.x, +camera.y`, the zoom using `camera.zoom` and the rotation using `camera.rot`. + +The module variable name can be used at a shortcut to `new()`. + +#### Parameters: + +=numbers x,y (optional)= + Point for the camera to look at. +=number zoom (optional)= + Camera zoom. +=number rot (optional)= + Camera rotation in radians. + + +#### Returns: + +=camera= + A new camera. + +#### Example: + + camera = require 'hump.camera' + -- camera looking at (100,100) with zoom 2 and rotated by 45 degrees + cam = camera(100,100, 2, math.pi/2) + + +### function camera:rotate(angle) [Rotate camera.] + +Rotate the camera by some angle. To set the angle use `camera.rot = new_angle`. + +This function is shortcut to `camera.rot = camera.rot + angle`. + +#### Parameters: + +=number angle= + Rotation angle in radians + +#### Returns: + +=camera= + The camera. + +#### Example: + + function love.update(dt) + camera:rotate(dt) + end + +#### Example: + + function love.update(dt) + camera:rotate(dt):move(dt,dt) + end + + +### function camera:rotation(angle) [Get or set camera rotation.] + +Returns `camera.rot`. + +If given an angle, set rotation: `camera.rot = angle`. + +#### Parameters: + +=number angle (optional)= + Rotation angle in radians + +#### Returns: + +=number= + Rotation angle in radians. + +#### Example: + + love.graphics.print(camera:rotation(), 10, 10) + camera:rotation(math.pi/2) + + +### function camera:move(dx,dy) [Move camera.] + +Move the camera *by* some vector. To set the position, use +[`camera:lookAt(x,y)`](#hump.cameralookAt). + +This function is shortcut to camera.x,camera.y = camera.x+dx, camera.y+dy. + +#### Parameters: + +=numbers dx,dy= + Direction to move the camera. + +#### Returns: + +=camera= + The camera. + +#### Example: + + function love.update(dt) + camera:move(dt * 5, dt * 6) + end + +#### Example: + + function love.update(dt) + camera:move(dt * 5, dt * 6):rotate(dt) + end + + +### function camera:lookAt(x,y) [Move camera to position.] + +Let the camera look at a point. In other words, it sets the camera position. To +move the camera *by* some amount, use [`camera:move(x,y)`](#hump.cameramove). + +This function is shortcut to `camera.x,camera.y = x, y`. + +#### Parameters: + +=numbers x,y= + Position to look at. + +#### Returns: + +=camera= + The camera. + +#### Example: + + function love.update(dt) + camera:lookAt(player.pos:unpack()) + end + +#### Example: + + function love.update(dt) + camera:lookAt(player.pos:unpack()):rotation(player.rot) + end + +### function camera:pos() [Get camera position.] + +Returns `camera.x, camera.y`. + +#### Returns: + +=numbers= + Camera position. + +#### Example: + + -- let the camera fly! + local cam_dx, cam_dy = 0, 0 + + function love.mousereleased(x,y) + local cx,cy = camera:position() + dx, dy = x-cx, y-cy + end + + function love.update(dt) + camera:move(dx * dt, dy * dt) + end + + +### function camera:attach() [Attach camera.] + +Start looking through the camera. + +Apply camera transformations, i.e. move, scale and rotate everything until +`camera:detach()` as if looking through the camera. + +#### Example: + + function love.draw() + camera:attach() + draw_world() + cam:detach() + + draw_hud() + end + + +### function camera:detach() [Detach camera.] + +Stop looking through the camera. + +#### Example: + + function love.draw() + camera:attach() + draw_world() + cam:detach() + + draw_hud() + end + + +### function camera:draw(func) [Attach, draw, then detach.] + +Wrap a function between a `camera:attach()/camera:detach()` pair: + + cam:attach() + func() + cam:detach() + + +#### Parameters: + +=function func= + Drawing function to be wrapped. + +#### Example: + + function love.draw() + camera:draw(draw_world) + draw_hud() + end + + +### function camera:worldCoords(x, y) [Convert point to world coordinates.] + +Because a camera has a point it looks at, a rotation and a zoom factor, it +defines a coordinate system. A point now has two sets of coordinates: One +defines where the point is to be found in the game world, and the other +describes the position on the computer screen. The first set of coordinates is +called *world coordinates*, the second one *camera coordinates*. Sometimes it +is needed to convert between the two coordinate systems, for example to get the +position of a mouse click in the game world in a strategy game, or to see if an +object is visible on the screen. + +`camera:worldCoords(x,y)` and `camera:cameraCoords(x,y)` transform a point +between these two coordinate systems. + +#### Parameters: + +=numbers x, y= + Point to transform. + +#### Returns: + +=numbers= + Transformed point. + +#### Example: + + x,y = camera:worldCoords(love.mouse.getPosition()) + selectedUnit:plotPath(x,y) + + +### function camera:cameraCoords(x, y) [Convert point to camera coordinates.] + +Because a camera has a point it looks at, a rotation and a zoom factor, it +defines a coordinate system. A point now has two sets of coordinates: One +defines where the point is to be found in the game world, and the other +describes the position on the computer screen. The first set of coordinates is +called *world coordinates*, the second one *camera coordinates*. Sometimes it +is needed to convert between the two coordinate systems, for example to get the +position of a mouse click in the game world in a strategy game, or to see if an +object is visible on the screen. + +`camera:worldCoords(x,y)` and `camera:cameraCoords(x,y)` transform a point +between these two coordinate systems. + +#### Parameters: + +=numbers x, y= + Point to transform. + +#### Returns: + +=numbers= + Transformed point. + +#### Example: + + x,y = cam:cameraCoords(player.pos) + love.graphics.line(x, y, love.mouse.getPosition()) + + +### function camera:mousepos() [Get mouse position in world coordinates.] + +Shortcut to `camera:worldCoords(love.mouse.getPosition())`. + +#### Returns: + +=numbers= + Mouse position in world coordinates. + +#### Example: + + x,y = camera:mousepos() + selectedUnit:plotPath(x,y) + + +## Module hump.ringbuffer [A data structure that wraps around itself.] + + Ringbuffer = require "hump.ringbuffer" + +A ring-buffer is a circular array: It does not have a first nor a last item, +but it has a *selected* or *current* element. + +A ring-buffer can be used to implement [Tomb Raider style +inventories](http://www.youtube.com/watch?v=YTdsKq77_lg), looping play-lists, +recurring dialogs (like a unit's answers when selecting it multiple +times in *Warcraft*) and generally everything that has a circular or looping +structure. + + +### function new(...) [Create a new ringbuffer.] + +Create new ring-buffer. + +The module name is a shortcut to this function. + +#### Parameters: + +=mixed ...= + Initial elements. + +#### Returns: + +=Ringbuffer= + The ring-buffer object. + +#### Example: + + ringbuffer = require 'hump.ringbuffer' + rb = ringbuffer.new(1,2,3) + -- or: + rb = ringbuffer(1,2,3) + +### function ringbuffer:insert(...) [Inser elements.] + +Insert items behind current element. + +#### Parameters: + +=mixed ...= + Items to insert. + +#### 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() [Remove currently selected item.] + +Remove current item, return it and select next element. + +#### Returns: + +=mixed= + The removed item. + +#### Example: + + rb = Ringbuffer(1,2,3,4) -- content: 1,2,3,4 + val = rb:remove() -- content: 2,3,4 + print(val) -- prints `1' + + +### function ringbuffer:removeAt(pos) [Remove an item.] + +Remove the item at a position relative to the current element. + +#### Parameters: + +=number pos= + Position of the item to remove. + + +#### Returns: + +=mixed= + The removed item. + + +#### 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() [Select next item.] + +Select and return the next element. + +#### Returns: + +=mixed= + The next item. + +#### Example: + + rb = Ringbuffer(1,2,3) + rb:next() -- content: 2,3,1 + rb:next() -- content: 3,1,2 + x = rb:next() -- content: 1,2,3 + print(x) -- prints `1' + +### function ringbuffer:prev() [Select previous item.] + +Select and return the previous item. + +#### Returns: + +=mixed= + The previous item. + +#### Example: + + rb = Ringbuffer(1,2,3) + rb:prev()) -- content: 3,1,2 + rb:prev()) -- content: 2,3,1 + x = rb:prev() -- content: 1,2,3 + print(x) -- prints `1' + + +### function ringbuffer:get() [Get currently selected item.] + +Return the current element. + +#### Returns: + +=mixed= + The currently selected element. + + +#### Example: + + rb = Ringbuffer(1,2,3) + rb:next() -- content: 2,3,1 + print(rb:get()) -- prints '2' + + +### function ringbuffer:size() [Get ringbuffer size.] + +Get number of items in the buffer + +#### 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' + + +## License + +Yay, *free software* + +> Copyright (c) 2010-2012 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. + +## Download + +You can view and download the individual modules on github: [vrld/hump]("http://github.com/vrld/hump") +You may also download the whole packed sourcecode either in +[zip](http://github.com/vrld/hump/zipball/master) or +[tar](http://github.com/vrld/hump/tarball/master) formats. + +Using [Git](http://git-scm.com), you can clone the project by running: + + git clone git://github.com/vrld/hump + +Once done, tou can check for updates by running + + git pull diff --git a/index.html b/index.html index bcce829..8fe97cc 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,73 @@ -hump - LÖVE Helper Utilities for More Productivity

Introduction^ top

Helper Utilities for a Multitude of Problems is a set of lightweight helpers for the awesome LÖVE Engine.

hump differs from other libraries in that every component is independent of the remaining ones. hump's footprint is very small and thus should fit nicely into your projects.

Documentation^ top

hump.gamestate
A gamestate system
hump.timer
Delayed function calls and helpers for interpolating functions.
hump.vector
2D vector math.
hump.vector-light
Lightweight 2D vector math.
hump.class
Class-based object orientated programming for Lua
hump.signal
Simple Signal/Slot (aka. Observer) implementation.
hump.camera
A camera for LÖVE
hump.ringbuffer
A data structure that wraps around itself.

hump.gamestate^ top

Gamestate = require "hump.gamestate"

A gamestate encapsulates independent 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

callbacks
Gamestate Callbacks
new()
Create a new gamestate.
switch()
Switch to gamestate.
update()
Update current gamestate.
draw()
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^ top

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

init()
Called once before entering the state. See switch().
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()
+
+
+
+
+
+hump - LÖVE Helper Utilities for More Productivity
+
+
+
+
+
+
+
+

Introduction^top

Helper Utilities for a Multitude of Problems is a set of lightweight helpers for the awesome LÖVE Engine.

+ +

hump differs from other libraries in that every component is independent of the remaining ones. hump's footprint is very small and thus should fit nicely into your projects.

+

Modules^top

hump.gamestate
A gamestate system.
hump.timer
Delayed and time-limited function calls.
hump.vector
2D vector math.
hump.vector-light
Lightweight 2D vector math.
hump.class
Class-based object orientated programming for Lua.
hump.signal
Simple Signal/Slot (aka. Observer) implementation.
hump.camera
A camera for LÖVE.
hump.ringbuffer
A data structure that wraps around itself.
+ +

hump.gamestate^top

Gamestate = require "hump.gamestate"
+
+ +

A gamestate encapsulates independent 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

Callbacks
Gamestate Callbacks.
new()
Create a new gamestate.
switch()
Switch to gamestate.
<callback>()
Call function on active gamestate.
registerEvents()
Automatically do all of the above when needed.

Callbacks ^top

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

+ +
+
init()
+
Called once before entering the state. See switch().
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 be called by the corresponding LÖVE callbacks and receive +receive the same arguments (e.g. state:update(dt) will be called by +love.update(dt)).

+ +

Example:

+ +
menu = Gamestate.new()
 function menu:init() -- run only once
     self.background = love.graphics.newImage('bg.jpg')
     Buttons.initialize()
@@ -35,120 +104,706 @@ function menu:mousereleased(x,y, mouse_btn)
             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, call the init() function if the state was not yet inialized 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 results of to:enter()
Example:
Gamestate.switch(game, level_two)

function update(...)^ top

function draw(...)^ top

function focus(...)^ top

function keypressed(...)^ top

function keyreleased(...)^ top

function mousepressed(...)^ top

function mousereleased(...)^ top

function joystickpressed(...)^ top

function joystickreleased(...)^ top

function quit(...)^ top

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
The results of the callback function.
Example:
function love.update(dt)
-    Gamestate.update(dt)
+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, call the init() function +if the state was not yet inialized and finally call enter(old_state, ...) on +the new gamestate.

+
Parameters:
+
Gamestate to
+
Target gamestate.
mixed ...
+
Additional arguments to pass to to:enter(current, ...).
+
Returns:
+
mixed
+
The results of to:enter(current, ...)
+
Example:
Gamestate.switch(game, level_two)
+
+

function <callback>(...)^top

Calls a function on the current gamestate. Can be any function, but is intended to +be one of the callbacks. Mostly useful when not using +registerEvents().

+
Parameters:
+
mixed ...
+
Arguments to pass to the corresponding function.
+
Returns:
+
mixed
+
The result of the callback function.
+
Example:
function love.draw()
+    Gamestate.draw() -- <callback> is `draw'
 end
 
-function love.draw()
-    local mx,my = love.mouse.getPosition()
-    Gamestate.draw(mx, my)
+function love.update(dt)
+    Gamestate.update(dt) -- pass dt to currentState:update(dt)
 end
 
 function love.keypressed(key, code)
-    Gamestate.keypressed(key, code)
-end

function registerEvents(callbacks)^ top

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

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

local old_update = love.update
+    Gamestate.keypressed(key, code) -- pass multiple arguments
+end
+
+

function registerEvents(callbacks)^top

Overwrite love callbacks to call Gamestate.update(), Gamestate.draw(), etc. +automatically. love callbacks (e.g. love.update()) are still invoked.

+ +

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

+ +
local old_update = love.update
 function love.update(dt)
     old_update(dt)
-    Gamestate.current:update(dt)
-end

Note: Only works when called in love.load() or any other function that is executedafter the whole file is loaded.

Parameters:
table callbacks (optional)
Names of the callbacks to register. If omitted, register all callbacks.
Returns:
Nothing
Example:
function love.load()
+    return Gamestate.current:update(dt)
+end
+
+ +

Note: Only works when called in love.load() or any other function that is +executed after the whole file is loaded.

+
Parameters:
+
table callbacks (optional)
+
Names of the callbacks to register. If omitted, register all love callbacks.
+
Returns:
Nothing
Examples:
function love.load()
     Gamestate.registerEvents()
     Gamestate.switch(menu)
-end
function love.load()
+end
+
+-- love callback will still be invoked
+function love.update(dt)
+    Timer.update(dt)
+    -- no need for Gamestate.update(dt)
+end
+
+
function love.load()
+    -- only register draw, update and quit
     Gamestate.registerEvents{'draw', 'update', 'quit'}
     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 be executed after some amount time has passed. For example, you can use a timer to set the player invincible for a short amount of time.

In addition, the module offers facilities to create functions that interpolate or oscillate over time. An interpolator could fade the color or a text message, whereas an oscillator could be used for the movement of foes in a shmup.

Module overview

new()
Create new timer instance.
add()
Schedule a function.
addPeriodic()
Add a periodic function.
do_for()
Run a function for the next few seconds.
cancel()
Cancel a scheduled function.
clear()
Remove all timed and periodic functions.
update()
Update scheduled functions.

function new()^ top

If you don't need multiple independent schedulers, you can use the global/default timer (see examples).

Creates a new timer instance that is independent of the global timer: It will manage it's own list of scheduled functions and does not in any way affect the the global timer. Likewise, the global timer does not affect the timer instance.

Note: Timer instances use the colon-notation (e.g. instance:update(dt)), while the global timer uses the dot-notation (e.g. Timer.update(dt)).

Parameters:
None
Returns:
Timer
A timer instance
Example:
menuTimer = Timer.new()

function add(delay, func)^ top

function instance:add(delay, func)^ top

Schedule a function. The function will be executed after delay seconds have elapsed, given that update(dt) is called every frame.

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

It is an error to schedule a function again if it is not yet finished or canceled.

func will receive itself as only parameter. This is useful to implement periodic behavior (see the example).

Parameters:
number delay
Number of seconds the function will be delayed.
function func
The function to be delayed.
Returns:
table
The timer handle.
Example:
-- grant the player 5 seconds of immortality
+end
+
+

hump.timer^top

Timer = require "hump.timer"
+
+ +

hump.timer offers a simple interface to schedule the execution of functions. It +is possible to run functions after and for some amount of time. For +example, a timer could be set to move critters every 5 seconds or to make the +player invincible for a short amount of time.

+

Module overview

new()
Create new timer instance.
add()
Schedule a function.
addPeriodic()
Add a periodic function.
do_for()
Run a function for the next few seconds.
cancel()
Cancel a scheduled function.
clear()
Remove all timed and periodic functions.
update()
Update scheduled functions.

function new()^top

If you don't need multiple independent schedulers, you can use the +global/default timer (see examples).

+ +

Creates a new timer instance that is independent of the global timer: It will +manage it's own list of scheduled functions and does not in any way affect the +the global timer. Likewise, the global timer does not affect timer instances.

+ +

Note: Timer instances use the colon-notation (e.g. instance:update(dt)), +while the global timer uses the dot-notation (e.g. Timer.update(dt)).

+
Parameters:
None
Returns:
+
Timer
+
A timer instance.
+
Example:
menuTimer = Timer.new()
+
+

function add(delay, func)^top

Schedule a function. The function will be executed after delay seconds have +elapsed, given that update(dt) is called every frame.

+ +

Note: There is no guarantee that the delay will not be exceeded, it is only +guaranteed that the function will not be executed before the delay has +passed.

+ +

func will receive itself as only parameter. This is useful to implement +periodic behavior (see the example).

+
Parameters:
+
number delay
+
Number of seconds the function will be delayed.
function func
+
The function to be delayed.
+
Returns:
+
table
+
The timer handle.
+
Examples:
-- grant the player 5 seconds of immortality
 player.isInvincible = true
-Timer.add(5, function() player.isInvincible = false end)
-- print "foo" every second. See addPeriodic.
-Timer.add(1, function(func) print("foo") Timer.add(1, func) end)
menuTimer:add(1, finishAnimation)

function addPeriodic(delay, func, count)^ top

function instance:addPeriodic(delay, func, count)^ top

Add a function that will be called count times every delay seconds.

If count is omitted, the function will be called until it returns false or clear() is called.

Parameters:
number delay
Number of seconds between two consecutive function calls.
function func
The function to be called periodically.
number count (optional)
Number of times the function is to be called.
Returns:
table
The timer handle.
Example:
Timer.addPeriodic(1, function() lamp:toggleLight() end)
mothership_timer:addPeriodic(0.3, function() self:spawnFighter() end, 5)
-- flicker player's image as long as he is invincible
+Timer.add(5, function() player.isInvincible = false end)
+
+
-- print "foo" every second. See also addPeriodic()
+Timer.add(1, function(func) print("foo") Timer.add(1, func) end)
+
+
--Using a timer instance:
+menuTimer:add(1, finishAnimation)
+
+

function addPeriodic(delay, func)^top

Add a function that will be called count times every delay seconds.

+ +

If count is omitted, the function will be called until it returns false or +cancel(handle) or clear() is +called.

+
Parameters:
+
number delay
+
Number of seconds between two consecutive function calls.
function func
+
The function to be called periodically.
number count (optional)
+
Number of times the function is to be called.
+
Returns:
+
table
+
The timer handle. See also cancel().
+
Examples:
-- toggle light on and off every second
+Timer.addPeriodic(1, function() lamp:toggleLight() end)
+
+
-- launch 5 fighters in quick succession (using a timer instance)
+mothership_timer:addPeriodic(0.3, function() self:launchFighter() end, 5)
+
+
-- flicker player's image as long as he is invincible
 Timer.addPeriodic(0.1, function()
     player:flipImage()
     return player.isInvincible
-end)

function do_for(delta, func, after)^ top

function instance:do_for(delta, func, after)^ top

Run a func(dt) for the next delta seconds. The function is called every time update(dt) is called. Optionally run after() once delta seconds have passed.

after will receive itself as only parameter.

The same constraints as with add() apply.

Parameters:
number delta
Number of seconds the func will be called.
function func
The function to be called upon update(dt).
function after (optional)
A function to be called after delta seconds.
Returns:
table
The timer handle.
Example:
-- play an animation for 5 seconds
-Timer.do_for(5, function(dt) animation:update(dt) end)
-- shake the camera for one second
+end)
+
+

function do_for(delay, func, after)^top

Run func(dt) for the next delta seconds. The function is called every time +update(dt) is called. Optionally run after() once delta seconds have +passed.

+ +

after() will receive itself as only parameter.

+ +

Note: You should not add new timers in func(dt), as this can lead to random +crashes.

+
Parameters:
+
number delta
+
Number of seconds the func will be called.
function func
+
The function to be called on update(dt).
function after (optional)
+
A function to be called after delta seconds.
+
Returns:
+
table
+
The timer handle.
+
Examples:
-- play an animation for 5 seconds
+Timer.do_for(5, function(dt) animation:update(dt) end)
+
+
-- shake the camera for one second
 local orig_x, orig_y = camera:pos()
 Timer.do_for(1, function()
-	camera:lookAt(orig_x + math.random(-2,2), orig_y + math.random(-2,2))
+    camera:lookAt(orig_x + math.random(-2,2), orig_y + math.random(-2,2))
 end, function()
-	-- reset camera position
-	camera:lookAt(orig_x, orig_y)
-end)
player.isInvincible = true
+    -- reset camera position
+    camera:lookAt(orig_x, orig_y)
+end)
+
+
player.isInvincible = true
 -- flash player for 3 seconds
 local t = 0
 player.timer:do_for(3, function(dt)
-	t = t + dt
-	player.visible = (t % .2) < .1
+    t = t + dt
+    player.visible = (t % .2) < .1
 end, function()
-	-- make sure the player is visible after three seconds
-	player.visible = true
-	player.isInvincible = false
-end)

function cancel(handle)^ top

function instance:cancel(handle)^ top

Prevent a timer from being executed in the future.

Always use the function handle returned by add()/addPeriodic() to cancel a timer.

Never use this inside a scheduled function.

Parameters:
table handle
The function to be canceled.
Returns:
Nothing
Example:
function tick()
+    -- make sure the player is visible after three seconds
+    player.visible = true
+    player.isInvincible = false
+end)
+
+

function cancel(handle)^top

Prevent a timer from being executed in the future.

+
Parameters:
+
table handle
+
The function to be canceled.
+
Returns:
Nothing
Example:
function tick()
     print('tick... tock...')
 end
 handle = Timer.addPeriodic(1, tick)
 -- later
-Timer.cancel(handle) -- NOT: Timer.cancel(tick)

function clear()^ top

function instance:clear()^ top

Remove all timed and periodic functions. Functions that have not yet been executed will discarded. Never use this inside a scheduled function.

Parameters:
None
Returns:
Nothing
Example:
Timer.clear()

function update(dt)^ top

function instance:update(dt)^ top

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

Parameters:
number dt
Time that has passed since the last update().
Returns:
Nothing
Example:
function love.update(dt)
+Timer.cancel(handle) -- NOT: Timer.cancel(tick)
+
+

function clear()^top

Remove all timed and periodic functions. Functions that have not yet been +executed will discarded.

+
Parameters:
None
Returns:
Nothing
Examples:
Timer.clear()
+
+
menu_timer:clear()
+
+

function update(dt)^top

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

+
Parameters:
+
number dt
+
Time that has passed since the last update().
+
Returns:
Nothing
Examples:
function love.update(dt)
     do_stuff()
     Timer.update(dt)
-end

hump.vector^ top

vector = require "hump.vector"

A handy 2D vector class providing most of the things you do with vectors.

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

Module overview

operators
Arithmetics and relations
new()
Create a 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()
Distance to other 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:mirrorOn()
Mirrors vector on other vector
vector:cross()
Cross product of two vectors.

Arithmetics and relations^ top

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
Scalar multiplication (scaling).
vector * number = vector
Scalar multiplication.
vector / number = vector
Scalar multiplication.

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, player.velocity and player.position are vectors
+end
+
+
-- using hump.gamestate and a timer instance
+function menuState:update(dt)
+    self.timer:update(dt)
+end
+
+

hump.vector^top

vector = require "hump.vector"
+
+ +

A handy 2D vector class providing most of the things you do with vectors.

+ +

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

+

Module overview

Operators
Arithmetics and relations.
new()
Create a 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()
Distance to other 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:mirrorOn()
Mirrors vector on other vector
vector:cross()
Cross product of two vectors.

Operators ^top

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
+
Scalar multiplication (scaling).
vector * number = vector
+
Scalar multiplication.
vector / number = vector
+
Scalar multiplication.
+ +

Relational operators are defined, too:

+ +
+
a == b
+
Same as a.x == b.x and a.y == b.y.
a <= b
+
Same as a.x <= b.x and a.y <= b.y.
a < b
+
Lexical sort: a.x < b.x or (a.x == b.x and a.y < b.y).
+ +

Example:

+ +
-- acceleration, player.velocity and player.position are vectors
 acceleration = vector(0,-9)
 player.velocity = player.velocity + acceleration * dt
-player.position = player.position + player.velocity * dt

function new(x,y)^ top

Create a 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:
-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
+player.position = player.position + player.velocity * dt
+
+

function new(x,y)^top

Create a new vector.

+
Parameters:
+
numbers x,y
+
Coordinates.
+
Returns:
+
vector
+
The vector.
+
Examples:

a = vector.new(10,10)

+

-- as a shortcut, you can call the module like a function: + 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 modifying the vector referenced by the new variable would also change the old one:

a = vector(1,1) -- create vector
+end
+
+

function vector:clone()^top

Copy a vector. Simply assigning a vector a vector to a variable will create a +reference, so when modifying the vector referenced by the new variable would +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
Copy of the 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
The new vector as described 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
Squared length of the vector.
Example:
-- get closest vertex to a given vector
+print(a,b,c)    -- prints '(1,0), (1,0), (1,1)'
+
+
Parameters:
None
Returns:
+
vector
+
Copy of the vector
+
Example:
copy = original:clone()
+
+

function vector:unpack()^top

Extract coordinates.

+
Parameters:
None
Returns:
+
numbers
+
The coordinates
+
Examples:
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
+
The new vector as described 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
+
Squared length of the vector.
+
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
+    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 to.
Returns:
number
The distance of the vectors.
Example:
-- get closest vertex to a given vector
+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 to.
+
Returns:
+
number
+
The distance of the 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
+    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 with 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:
direction = velocity:normalized()

function vector:normalize_inplace()^ top

Normalize a vector, i.e. make the vector unit length. Great to use on intermediate results.

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

Parameters:
None
Returns:
vector
Itself - 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
+end
+
+

function vector:normalized()^top

Get normalized vector, i.e. a vector with the same direction as the input +vector, but with 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:
direction = velocity:normalized()
+
+

function vector:normalize_inplace()^top

Normalize a vector, i.e. make the vector unit length. Great to use on +intermediate results.

+ +

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

+
Parameters:
None
Returns:
+
vector
+
Itself - the normalized vector
+
Example:
normal = (b - a):perpendicular():normalize_inplace()
+
+

function vector:rotated(angle)^top

Get a rotated vector.

+ +

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

+
Parameters:
+
number angle
+
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:

function vector:rotate_inplace(phi)^ top

Rotate a vector in-place. Great to use on intermediate results.

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

Parameters:
number phi
Rotation angle in radians.
Returns:
vector
Itself - 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 (but faster) as vec:rotate(math.pi/2)

Parameters:
None
Returns:
vector
A vector perpendicular to the input vector
Example:
normal = (b - a):perpendicular():normalize_inplace()
Sketch:

function vector:projectOn(v)^ top

Project vector onto another vector (see sketch).

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

function vector:mirrorOn(v)^ top

Mirrors vector on the axis defined by the other vector.

Parameters:
vector v
The vector to mirror on.
Returns:
vector
The mirrored vector.
Example:
deflected_velocity = ball.velocity:mirrorOn(surface_normal)
Sketch:

function vector:cross(other)^ top

Get cross product of both vectors. Equals the area of the parallelogram spanned by both vectors.

Parameters:
vector other
Vector to compute the cross product with.
Returns:
number
Cross product of both vectors.
Example:
parallelogram_area = a:cross(b)
Sketch:

hump.vector-light^ top

vector = require "hump.vector-light"

An table-free version of hump.vector. Instead of a vector class, hump.vector-light provides functions that operate on numbers.

Using this module instead of vector might result in faster code, but does so at the expense of readability. Unless you are sure that it causes a significant performance penalty, I recommend to use hump.vector.

Module overview

str()
String representation.
mul()
Product of a vector and a scalar.
div()
Product of a vector and the inverse of a scalar.
add()
Sum of two vectors.
sub()
Difference of two vectors.
permul()
Per element multiplication.
dot()
[^http://en.wikipedia.org/wiki/Dot_product Dot product]
det()
Cross product
cross()
Cross product
eq()
Equality.
le()
Partial lexical order.
lt()
Strict lexical order.
len()
Get length.
len2()
Get squared length.
dist()
Distance of two points.
normalize()
Normalize vector.
rotate()
Rotate vector.
perpendicular()
Get perpendicular vector.
project()
Project projection onto another vector.
mirror()
Mirrors vector on other vector.

function str(x,y)^ top

Transforms a vector to a string of the form (x,y).

Parameters:
numbers x,y
The vector
Returns:
string
The string representation
Example:
print(vector.str(love.mouse.getPosition()))

function mul(s, x,y)^ top

function div(s, x,y)^ top

Computes x*s,y*s and x/s,y/s respectively. The order of arguments is chosen so that it's possible to chain multiple operations (see example).

Parameters:
number s
The scalar.
numbers x,y
The vector.
Returns:
numbers
The result of the operation.
Example:
velx,vely = vec.mul(dt, vec.add(velx,vely, accx,accy))
x,y = vec.div(self.zoom, x-w/2, y-h/2)

function add(x1,y1, x2,y2)^ top

function sub(x1,y1, x2,y2)^ top

Computes the sum/difference of vectors. Same as x1+x2,y1+y2 and x1-x2,y1-y2 respectively. Meant to be used in conjunction with other functions.

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
numbers
The result of the operation.
Example:
player.x,player.y = vector.add(player.x,player.y, vector.mul(dt, dx,dy))
dx,dy = vector.sub(400,300, love.mouse.getPosition())

function permul(x1,y1, x2,y2)^ top

Multiplies vectors coordinate wise, i.e. x1*x2,y1*y2.

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
numbers
The result of the operation.
Example:
x,y = vector.permul(x,y, 1,1.5)

function dot(x1,y1, x2,y2)^ top

Computes the dot product of two vectors, x1*x2+y1*y2.

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
number
The dot product.
Example:
cosphi = vector.dot(rx,ry, vx,vy)

function det(x1,y1, x2,y2)^ top

function cross(x1,y1, x2,y2)^ top

Computes the cross product/determinant of two vectors, x1*y2-y1*x2.

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
number
The cross product.
Example:
parallelogram_area = vector.det(ax,ay, bx,by)

function eq(x1,y1, x2,y2)^ top

function le(x1,y1, x2,y2)^ top

function lt(x1,y1, x2,y2)^ top

Compares two vectors according to

vector.eq(x1,y1, x2,y2)
x1 == x2 and y1 == y2
vector.le(x1,y1, x2,y2)
x1 <= x2 and y1 <= y2
vector.lt(x1,y1, x2,y2)
x1 < x2 or (x1 == x2) and y1 <= y2

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
boolean
The result of the operation.
Example:
...

function len(x,y)^ top

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

Parameters:
numbers x,y
The vector.
Returns:
number
Length of the vector.
Example:
distance = vector.len(love.mouse.getPosition())

function len2(x,y)^ top

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

Parameters:
numbers x,y
The vector.
Returns:
number
Squared length of the vector.
Example:
-- get closest vertex to a given vector
+end
+
+
Sketch:

Rotated vector sketch

+

function vector:rotate_inplace(angle)^top

Rotate a vector in-place. Great to use on intermediate results.

+ +

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

+
Parameters:
+
number angle
+
Rotation angle in radians.
+
Returns:
+
vector
+
Itself - 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 (but faster) as +vec:rotate(math.pi/2).

+
Parameters:
None
Returns:
+
vector
+
A vector perpendicular to the input vector
+
Example:
normal = (b - a):perpendicular():normalize_inplace()
+
+
Sketch:

Perpendiculat vector sketch

+

function vector:projectOn(v)^top

Project vector onto another vector (see sketch).

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

Projected vector sketch

+

function vector:mirrorOn(v)^top

Mirrors vector on the axis defined by the other vector.

+
Parameters:
+
vector v
+
The vector to mirror on.
+
Returns:
+
vector
+
The mirrored vector.
+
Example:
deflected_velocity = ball.velocity:mirrorOn(surface_normal)
+
+
Sketch:

Mirrored vector sketch

+

function vector:cross(other)^top

Get cross product of both vectors. Equals the area of the parallelogram spanned +by both vectors.

+
Parameters:
+
vector other
+
Vector to compute the cross product with.
+
Returns:
+
number
+
Cross product of both vectors.
+
Example:
parallelogram_area = a:cross(b)
+
+

hump.vector-light^top

vector = require "hump.vector-light"
+
+ +

An table-free version of hump.vector. Instead of a vector +type, hump.vector-light provides functions that operate on numbers.

+ +

Note: Using this module instead of hump.vector might +result in faster code, but does so at the expense of readability. Unless you +are sure that it causes a significant performance penalty, I recommend using +hump.vector.

+

Module overview

str()
String representation.
mul()
Product of a vector and a scalar.
mul()
Product of a vector and the inverse of a scalar.
add()
Sum of two vectors.
sub()
Difference of two vectors.
permul()
Per element multiplication.
dot()
Dot product.
cross()
Cross product.
eq()
Equality.
le()
Partial lexical order.
lt()
Strict lexical order.
len()
Get length.
len2()
Get squared length.
dist()
Distance of two points.
normalize()
Normalize vector.
rotate()
Rotate vector.
perpendicular()
Get perpendicular vector.
project()
Project vector onto another vector.
mirror()
Mirror vector on other vector.

function str(x,y)^top

Transforms a vector to a string of the form (x,y).

+
Parameters:
+
numbers x,y
+
The vector
+
Returns:
+
string
+
The string representation
+
Example:
print(vector.str(love.mouse.getPosition()))
+
+

function mul(s, x,y)^top

Computes x*s,y*s. The order of arguments is chosen so that it's possible to +chain multiple operations (see example).

+
Parameters:
+
number s
+
The scalar.
numbers x,y
+
The vector.
+
Returns:
+
numbers
+
x*s, y*s
+
Example:
velx,vely = vec.mul(dt, vec.add(velx,vely, accx,accy))
+
+

function mul(s, x,y)^top

Computes x/s,y/s. The order of arguments is chosen so that it's possible to +chain multiple operations.

+
Parameters:
+
number s
+
The scalar.
numbers x,y
+
The vector.
+
Returns:
+
numbers
+
x/s, y/s
+
Example:
x,y = vec.div(self.zoom, x-w/2, y-h/2)
+
+

function add(x1,y1, x2,y2)^top

Computes the sum (x1+x2,y1+y2) of two vectors. Meant to be used in +conjunction with other functions.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
numbers
+
x1+x2, x1+x2
+
Example:
player.x,player.y = vector.add(player.x,player.y, vector.mul(dt, dx,dy))
+
+

function sub(x1,y1, x2,y2)^top

Computes the difference (x1-x2,y1-y2) of two vectors. Meant to be used in +conjunction with other functions.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
numbers
+
x1-x2, x1-x2
+
Example:
dx,dy = vector.sub(400,300, love.mouse.getPosition())
+
+

function permul(x1,y1, x2,y2)^top

Multiplies vectors coordinates, i.e.: x1*x2, y1*y2.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
numbers
+
x1*x2, y1*y2
+
Example:
x,y = vector.permul(x,y, 1,1.5)
+
+

function dot(x1,y1, x2,y2)^top

Computes the dot product of two +vectors: x1*x2 + y1*y2.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
number
+
x1*x2 + y1*y2
+
Example:
cosphi = vector.dot(rx,ry, vx,vy)
+
+

function cross(x1,y1, x2,y2)^top

Computes the cross product of two +vectors, x1*y2 - y1*x2.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
number
+
x1*y2 - y1*x2
+
+
number
+
x1*y2 - y1*x2
+
Examples:
parallelogram_area = vector.cross(ax,ay, bx,by)
+
+ +

Alias to [vector.cross(x1,y1, x2,y2)].

+
parallelogram_area = vector.det(ax,ay, bx,by)
+
+

function eq(x1,y1, x2,y2)^top

Test for equality.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
boolean
+
x1 == x2 and y1 == y2
+
Example:
if vector.eq(x1,y1, x2,y2) then be.happy() end
+
+

function le(x1,y1, x2,y2)^top

Test for partial lexical order, <=.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
boolean
+
x1 <= x2 and y1 <= y2
+
Example:
if vector.le(x1,y1, x2,y2) then be.happy() end
+
+

function lt(x1,y1, x2,y2)^top

Test for strict lexical order, <.

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
boolean
+
x1 < x2 or (x1 == x2) and y1 <= y2
+
Example:
if vector.lt(x1,y1, x2,y2) then be.happy() end
+
+

function len(x,y)^top

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

+
Parameters:
+
numbers x,y
+
The vector.
+
Returns:
+
number
+
Length of the vector.
+
Example:
distance = vector.len(love.mouse.getPosition())
+
+

function len2(x,y)^top

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

+
Parameters:
+
numbers x,y
+
The vector.
+
Returns:
+
number
+
Squared length of the vector.
+
Example:
-- get closest vertex to a given vector
 closest, dsq = vertices[1], vector.len2(px-vertices[1].x, py-vertices[1].y)
 for i = 2,#vertices do
     local temp = vector.len2(px-vertices[i].x, py-vertices[i].y)
-    if temp < dsq then
+    if temp < dsq then
         closest, dsq = vertices[i], temp
     end
-end

function dist(x1,y1, x2,y2)^ top

Get distance of two points. The same as vector.len(x1-x2, y1-y2).

Parameters:
numbers x1,y1
First vector.
numbers x2,y2
Second vector.
Returns:
number
The distance of the points.
Example:
-- get closest vertex to a given vector
+end
+
+

function dist(x1,y1, x2,y2)^top

Get distance of two points. The same as vector.len(x1-x2, y1-y2).

+
Parameters:
+
numbers x1,y1
+
First vector.
numbers x2,y2
+
Second vector.
+
Returns:
+
number
+
The distance of the points.
+
Example:
-- get closest vertex to a given vector
 -- slightly slower than the example using len2()
 closest, dist = vertices[1], vector.dist(px,py, vertices[1].x,vertices[1].y)
 for i = 2,#vertices do
     local temp = vector.dist(px,py, vertices[i].x,vertices[i].y)
-    if temp < dist then
+    if temp < dist then
         closest, dist = vertices[i], temp
     end
-end

function normalize(x,y)^ top

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

Parameters:
numbers x,y
The vector.
Returns:
numbers
Vector with same direction as the input vector, but length 1.
Example:
dx,dy = vector.normalize(vx,vy)

function rotate(phi, x,y)^ top

Get a rotated vector.

Parameters:
number phi
Rotation angle in radians.
numbers x,y
The vector.
Returns:
numbers
The rotated vector
Example:
-- approximate a circle
+end
+
+

function normalize(x,y)^top

Get normalized vector, i.e. a vector with the same direction as the input
+vector, but with length 1.
+
+
Parameters:
+
numbers x,y
+
The vector.
+
Returns:
+
numbers
+
Vector with same direction as the input vector, but length 1.
+
Example:
dx,dy = vector.normalize(vx,vy)
+
+

function rotate(phi, x,y)^top

Get a rotated vector.

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

function perpendicular(x,y)^ top

Quick rotation by 90°. The same (but faster) as vector.rotate(math.pi/2, x,y)

Parameters:
numbers x,y
The vector.
Returns:
numbers
A vector perpendicular to the input vector
Example:
nx,ny = vector.normalize(vector.perpendicular(bx-ax, by-ay))

function project(x,y, u,v)^ top

Project vector onto another vector.

Parameters:
numbers x,y
The vector to project.
numbers u,v
The vector to project onto.
Returns:
numbers
The projected vector.
Example:
vx_p,vy_p = vector.project(vx,vy, ax,ay)

function mirror(x,y, u,v)^ top

Mirrors vector on the axis defined by the other vector.

Parameters:
numbers x,y
The vector to mirror.
numbers u,v
The vector defining the axis.
Returns:
numbers
The mirrored vector.
Example:
vx,vy = vector.mirror(vx,vy, surface.x,surface.y)

hump.class^ top

Class = require "hump.class"

A small, fast class implementation with multiple inheritance support

Module overview

new()
Declare a new class.
class.construct()
Call class constructor.
class:inherit()
Explicit class inheritance/mixin support.
object:is_a()
Test object's type.
caveats
Caveats

function new{constructor, name = the_name, inherits = super}^ top

Declare a new class.

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

You can check if an object is an instance of a class using object:is_a().

The name of the variable that holds the module can be used as a shortcut to new() (see example).

Parameters:
function constructor (optional)
Class constructor. Can be accessed with theclass.construct(object, ...)
string the_name (optional)
Class name (used only to make the class compliant to tostring().
class or table of classes super (optional)
Classes to inherit from. Can either be a single class or a table of classes
Returns:
class
The class
Example:
Class = require 'hump.class' -- `Class' is now a shortcut to new()
+end
+
+

function perpendicular(x,y)^top

Quick rotation by 90°. The same (but faster) as vector.rotate(math.pi/2, x,y).

+
Parameters:
+
numbers x,y
+
The vector.
+
Returns:
+
numbers
+
A vector perpendicular to the input vector
+
Example:
nx,ny = vector.normalize(vector.perpendicular(bx-ax, by-ay))
+
+

function project(x,y, u,v)^top

Project vector onto another vector.

+
Parameters:
+
numbers x,y
+
The vector to project.
numbers u,v
+
The vector to project onto.
+
Returns:
+
numbers
+
The projected vector.
+
Example:
vx_p,vy_p = vector.project(vx,vy, ax,ay)
+
+

function mirror(x,y, u,v)^top

Mirrors vector on the axis defined by the other vector.

+
Parameters:
+
numbers x,y
+
The vector to mirror.
numbers u,v
+
The vector defining the axis.
+
Returns:
+
numbers
+
The mirrored vector.
+
Example:
vx,vy = vector.mirror(vx,vy, surface.x,surface.y)
+
+

hump.class^top

Class = require "hump.class"
+
+ +

A small, fast class implementation with multiple inheritance support.

+ +

Implements class commons.

+

Module overview

new()
Declare a new class.
class.construct()
Call class constructor.
class:inherit()
Explicit class inheritance/mixin support.
object:is_a()
Test object's type.
Caveats
Common gotchas.

function new{constructor, name = the_name, inherits = super}^top

Declare a new class.

+ +

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

+ +

You can check if an object is an instance of a class using +object:is_a().

+ +

The name of the variable that holds the module can be used as a shortcut to +new() (see example).

+
Parameters:
+
function constructor (optional)
+
Class constructor. Can be accessed with theclass.construct(object, ...)
string the_name (optional)
+
Class name (used only to make the class compliant to tostring().
class or table of classes super (optional)
+
Classes to inherit from. Can either be a single class or a table of classes
+
Returns:
+
class
+
The class
+
Examples:
Class = require 'hump.class' -- `Class' is now a shortcut to new()
 
 -- define unnamed class
 Feline = Class{function(self, size, weight)
     self.size = size
     self.weight = weight
 end}
-print(Feline) -- prints '
+print(Feline) -- prints '
 
 -- define class method
 function Feline:stats()
@@ -160,7 +815,8 @@ garfield = Feline(.7, 45)
 felix = Feline(.8, 12)
 
 print("Garfield: " .. garfield:stats(), "Felix: " .. felix:stats())
-
Class = require 'hump.class'
+
+
Class = require 'hump.class'
 
 -- define class with explicit name 'Feline'
 Feline = Class{name = "Feline", function(self, size, weight)
@@ -169,8 +825,9 @@ Feline = Class{name = "Feline", function(self, size, weight)
 end}
 
 garfield = Feline(.7, 45)
-print(Feline, garfield) -- prints '	>'
-
Class = require 'hump.class'
+print(Feline, garfield) -- prints ' >'
+
+
Class = require 'hump.class'
 A = Class{}
 function A:foo()
     print('foo')
@@ -191,7 +848,19 @@ D = Class{inherits = {A,B}}
 instance = D()
 instance:foo() -- prints 'foo'
 instance:bar() -- prints 'bar'
-

function class.construct(object, ...)^ top

Calls class constructor of a class on an object

Derived classes use this function their constructors to initialize the parent class(es) portions of the object.

Parameters:
Object object
The object. Usually self.
mixed ...
Arguments to pass to the constructor
Returns:
mixed
Whatever the parent class constructor returns
Example:
Class = require 'hump.class'
+
+

function class.construct(object, ...)^top

Calls class constructor of a class on an object.

+ +

Derived classes use this function their constructors to initialize the parent +class(es) portions of the object.

+
Parameters:
+
Object object
+
The object. Usually self.
mixed ...
+
Arguments to pass to the constructor.
+
Returns:
+
mixed
+
Whatever the parent class constructor returns.
+
Examples:
Class = require 'hump.class'
 
 Shape = Class{function(self, area)
     self.area = area
@@ -215,7 +884,8 @@ function Rectangle:__tostring()
 end
 
 print( Rectangle(2,4) ) -- prints 'width = 2, height = 4, area = 8'
-
Menu = Class{function(self)
+
+
Menu = Class{function(self)
     self.entries = {}
 end}
 function Menu:add(title, entry)
@@ -238,7 +908,25 @@ Submenu = Class{inherits = {Menu, Entry}, function(self, title)
     -- redirect self:execute() to self:display()
     Entry.construct(self, title, Menu.display)
 end}
-

function class:inherit(...)^ top

Inherit functions and variables of another class, if they are not already defined for the class. This is done by simply copying the functions and variables over to the subclass. The Lua rules for copying apply (i.e. tables are referenced, functions and primitive types are copied by value).

Be careful with changing table values in a subclass: This will change the value in the parent class too.

If more than one parent class is specified, inherit from all of these, in order of occurrence. That means that when two parent classes define the same method, the one from the first class will be inherited.

Note: class:inherit() doesn't actually care if the arguments supplied are hump classes. Just any table will work.

Parameters:
tables ...
Parent classes to inherit from
Returns:
Nothing
Example:
Class = require 'hump.class'
+
+

function class:inherit(...)^top

Inherit functions and variables of another class, if they are not already +defined for the class. This is done by simply copying the functions and +variables over to the subclass. The Lua rules for copying apply (i.e. tables +are referenced, functions and primitive types are copied by value).

+ +

Be careful with changing table values in a subclass: This will change the +value in the parent class too.

+ +

If more than one parent class is specified, inherit from all of these, in order +of occurrence. That means that when two parent classes define the same method, +the one from the first class will be inherited.

+ +

Note: class:inherit() doesn't actually care if the arguments supplied are +hump classes. Just any table will work.

+
Parameters:
+
tables ...
+
Parent classes to inherit from
+
Returns:
Nothing
Example:
Class = require 'hump.class'
 
 Entity = Class{function(self)
     GameObjects.register(self)
@@ -266,24 +954,37 @@ Spaceship:inherit(Collidable)
 function Spaceship:collision_handler["Spaceship"](other, dx, dy)
     -- ...
 end
-

function object:is_a(cls)^ top

Tests whether an object is an instance of a class.

Parameters:
class cls
Class to test. Note: this is the class itself, not the name of the class.
Returns:
Boolean
true if the object is an instance of the class, false otherwise
Example:
Class = require 'hump.class'
+
+

function object:is_a(cls)^top

Tests whether an object is an instance of a class.

+
Parameters:
+
class cls
+
Class to test. Note: this is the class itself, not the name of the class.
+
Returns:
+
boolean
+
true if the object is an instance of the class, false otherwise
+
Example:
Class = require 'hump.class'
 
 A = Class{}
 B = Class{inherits=A}
 C = Class{inherits=B}
 a, b, c = A(), B(), C()
-print(a:is_a(A), a:is_a(B), a:is_a(C)) --> true   false  false
-print(b:is_a(A), b:is_a(B), b:is_a(C)) --> true   true   false
-print(c:is_a(A), c:is_a(B), c:is_a(C)) --> true   true   true
+print(a:is_a(A), a:is_a(B), a:is_a(C)) --> true   false  false
+print(b:is_a(A), b:is_a(B), b:is_a(C)) --> true   true   false
+print(c:is_a(A), c:is_a(B), c:is_a(C)) --> true   true   true
 
 D = Class{}
 E = Class{inherits={B,D}}
 d, e = D(), E()
-print(d:is_a(A), d:is_a(B), d:is_a(D)) --> false  false  true
-print(e:is_a(A), e:is_a(B), e:is_a(D)) --> true   true   true
-

Caveats^ top

Be careful when using metamethods like __add or __mul: If 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'
+print(d:is_a(A), d:is_a(B), d:is_a(D)) --> false  false  true
+print(e:is_a(A), e:is_a(B), e:is_a(D)) --> true   true   true
+
+

Caveats ^top

Be careful when using metamethods like __add or __mul: If 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:

-A = Class{function(self, x) self.x = x end} +

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
 
@@ -294,7 +995,15 @@ 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

Note that while you can define the __index metamethod of the class, this is not a good idea: It will break the class. To add a custom __index metamethod without breaking the class system, you have to use rawget(). But beware that this won't affect subclasses:

Class = require 'hump.class'
+result:foo()    -- error: method does not exist
+
+ +

Note that while you can define the __index metamethod of the class, this is +not a good idea: It will break the class. To add a custom __index metamethod +without breaking the class system, you have to use rawget(). But beware that +this won't affect subclasses:

+ +
Class = require 'hump.class'
 
 A = Class{}
 function A:foo() print('bar') end
@@ -305,92 +1014,410 @@ function A:__index(key)
 end
 
 instance = A()
-instance:foo() -- prints foo  bar
+instance:foo() -- prints foo  bar
 
 B = Class{inherits = A}
 instance = B()
-instance:foo() -- prints only foo

hump.signal^ top

Signal = require "hump.signal"

A simple yet effective implementation of Signals and Slots, also known as Observer pattern: Functions can be dynamically bound to signals. When a signal is emitted, all registered functions will be invoked. Simple as that.

hump.signal makes things more interesing by allowing to emit all signals that match a Lua string - pattern.

Module overview

new()
Create new signal registry.
register()
Register function with a signal.
emit()
Call all functions bound to a signal.
remove()
Remove functions from registry.
clear()
Clears a signal registry.
emit_pattern()
Emits signals matching a pattern.
remove_pattern()
Remove functions from signals matching a pattern.
clear_pattern()
Clears signal registry matching a pattern.

function new()^ top

If you don't need multiple independent registries, you can use the global/default registry (see examples).

Creates a new signal registry that is independent of the default registry: It will manage it's own list of signals and does not in any way affect the the global registry. Likewise, the global registry does not affect the instance.

Note: Independent registries use the colon-notation (e.g. instance:emit("foo")), while the global registry uses the dot-notation (e.g. Signal.emit("foo")).

Parameters:
None
Returns:
Registry
A new signal registry.
Example:
player.signals = Signals.new()

function register(s, f)^ top

function instance:register(s, f)^ top

Registers a function f to be called when signal s is emitted.

Parameters:
string s
The signal identifier.
function f
The function to register.
Returns:
function
A function handle to use in remove.
Example:
Signal.register('level-complete', function() self.fanfare:play() end)
handle = Signal.register('level-load', function(level) level.show_help() end)
menu:register('key-left', select_previous_item)

function emit(s, ...)^ top

function instance:emit(s, ...)^ top

Calls all functions bound to signal s with the supplied arguments.

Parameters:
string s
The signal identifier.
mixed ... (optional)
Arguments to pass to the bound functions.
Returns:
Nothing
Example:
function love.keypressed(key)
-    if key == 'left' then menu:emit('key-left') end
-end
if level.is_finished() then
-    Signal.emit('level-load', level.next_level)
-end
function on_collide(dt, a,b, dx,dy)
-    a.signals:emit('collide', b,  dx, dy)
-    b.signals:emit('collide', a, -dx,-dy)
-end

function remove(s, ...)^ top

function instance:remove(s, ...)^ top

Unbinds (removes) functions from signal s.

Parameters:
string s
The signal identifier.
functions ...
Functions to unbind from the signal.
Returns:
Nothing
Example:
Signal.remove('level-load', handle)

function clear(s)^ top

function instance:clear(s)^ top

Removes all functions from signal s.

Parameters:
string s
The signal identifier.
Returns:
Nothing
Example:
Signal.clear('key-left')

function emit_pattern(p, ...)^ top

function instance:emit_pattern(p, ...)^ top

Emits all signals matching a string pattern.

Parameters:
string p
The signal identifier pattern.
mixed ... (optional)
Arguments to pass to the bound functions.
Returns:
Nothing
Example:
Signal.emit_pattern('^update%-.*', dt)

function remove_pattern(p, ...)^ top

function instance:remove_pattern(p, ...)^ top

Removes functions from all signals matching a string pattern.

Parameters:
string p
The signal identifier pattern.
functions ...
Functions to unbind from the signals.
Returns:
Nothing
Example:
Signal.remove_pattern('key%-.*', play_click_sound)

function clear_pattern(p)^ top

function instance:clear_pattern(p)^ top

Removes all functions from all signals matching a string pattern.

Parameters:
string p
The signal identifier pattern.
Returns:
Nothing
Example:
Signal.clear_pattern('sound%-.*')
Signal.clear_pattern('.*') -- clear all signals

hump.camera^ top

Camera = require "hump.camera"

A camera utility for LÖVE. A camera can "look" at a position. It can zoom in and out and it can rotate it's view. In the background, this is done by actually moving, scaling and rotating everything in the game world. But don't worry about that.

Module overview

new()
Create a new camera.
camera:rotate()
Rotate camera.
camera:rotation()
Get or set camera rotation.
camera:move()
Move camera.
camera:lookAt()
Move camera to a position.
camera:pos()
Get camera position..
camera:attach()
Attach camera.
camera:detach()
Detach camera.
camera:draw()
Attach, draw and detach.
camera:worldCoords()
Convert point to world coordinates.
camera:cameraCoords()
Convert point to camera coordinates.
camera:mousepos()
Get mouse position in world coordinates.

function new(x,y, zoom, rot)^ top

Creates a new camera. You can access the camera position using camera.x, camera.y, the zoom using camera.zoom and the rotation using camera.rot.

The module variable name can be used at a shortcut to new().

Parameters:
numbers x,y
Point for the camera to look at.
number zoom
Camera zoom.
number rot
Camera rotation in radians.
Returns:
camera
A new camera.
Example:
camera = require 'hump.camera'
+instance:foo() -- prints only foo
+
+

hump.signal^top

A simple yet effective implementation of Signals and +Slots, also known as Observer +pattern: Functions can be +dynamically bound to signals. When a signal is emitted, all registered +functions will be invoked. Simple as that.

+

hump.signal makes things more interesing by allowing to emit all signals that +match a Lua string pattern.

+

Module overview

new()
Create a new signal registry
register()
Register function with signal.
emit()
Call all functions bound to a signal.
remove()
Remove functions from registry.
clear()
Clears a signal registry.
emit_pattern()
Emits signals matching a pattern.
remove_pattern()
Remove functions from signals matching a pattern.
clear_pattern()
Clears signal registry matching a pattern.

function new()^top

If you don't need multiple independent registries, you can use the +global/default registry (see examples).

+ +

Creates a new signal registry that is independent of the default registry: It +will manage it's own list of signals and does not in any way affect the the +global registry. Likewise, the global registry does not affect the instance.

+ +

Note: Independent registries use the colon-notation (e.g. +instance:emit("foo")), while the global registry uses the dot-notation (e.g. +Signal.emit("foo")).

+
Parameters:
None
Returns:
+
Registry
+
A new signal registry.
+
Example:
player.signals = Signals.new()
+
+

function register(s, f)^top

Registers a function f to be called when signal s is emitted.

+
Parameters:
+
string s
+
The signal identifier.
function f
+
The function to register.
+
Returns:
+
function
+
A function handle to use in remove().
+
Examples:
Signal.register('level-complete', function() self.fanfare:play() end)
+
+
handle = Signal.register('level-load', function(level) level.show_help() end)
+
+
menu:register('key-left', select_previous_item)
+
+

function emit(s, ...)^top

Calls all functions bound to signal s with the supplied arguments.

+
Parameters:
+
string s
+
The signal identifier.
mixed ... (optional)
+
Arguments to pass to the bound functions.
+
Returns:
Nothing
Examples:
function love.keypressed(key)
+    -- using a signal instance
+    if key == 'left' then menu:emit('key-left') end
+end
+
+
if level.is_finished() then
+    -- adding arguments
+    Signal.emit('level-load', level.next_level)
+end
+
+

function remove(s, ...)^top

Unbinds (removes) functions from signal s.

+
Parameters:
+
string s
+
The signal identifier.
functions ...
+
Functions to unbind from the signal.
+
Returns:
Nothing
Example:
Signal.remove('level-load', handle)
+
+

function clear(s)^top

Removes all functions from signal s.

+
Parameters:
+
string s
+
The signal identifier.
+
Returns:
Nothing
Example:
Signal.clear('key-left')
+
+

function emit_pattern(p, ...)^top

Emits all signals matching a string pattern.

+
Parameters:
+
string p
+
The signal identifier pattern.
mixed ... (optional)
+
Arguments to pass to the bound functions.
+
Returns:
Nothing
Example:
Signal.emit_pattern('^update%-.*', dt)
+
+

function remove_pattern(p, ...)^top

Removes functions from all signals matching a string pattern.

+
Parameters:
+
string p
+
The signal identifier pattern.
functions ...
+
Functions to unbind from the signals.
+
Returns:
Nothing
Example:
Signal.remove_pattern('key%-.*', play_click_sound)
+
+

function clear_pattern(p)^top

Removes all functions from all signals matching a string pattern.

+
Parameters:
+
string p
+
The signal identifier pattern.
+
Returns:
Nothing
Examples:
Signal.clear_pattern('sound%-.*')
+
+
player.signals:clear_pattern('.*') -- clear all signals
+
+

hump.camera^top

Camera = require "hump.camera"
+
+ +

A camera utility for LÖVE. A camera can "look" at a position. It can zoom in +and out and it can rotate it's view. In the background, this is done by +actually moving, scaling and rotating everything in the game world. But don't +worry about that.

+

Module overview

new()
Create a new camera.
camera:rotate()
Rotate camera.
camera:rotation()
Get or set camera rotation.
camera:move()
Move camera.
camera:lookAt()
Move camera to position.
camera:pos()
Get camera position.
camera:attach()
Attach camera.
camera:detach()
Detach camera.
camera:draw()
Attach, draw, then detach.
camera:worldCoords()
Convert point to world coordinates.
camera:cameraCoords()
Convert point to camera coordinates.
camera:mousepos()
Get mouse position in world coordinates.

function new(x,y, zoom, rot)^top

Creates a new camera. You can access the camera position using camera.x, +camera.y, the zoom using camera.zoom and the rotation using camera.rot.

+ +

The module variable name can be used at a shortcut to new().

+
Parameters:
+
numbers x,y (optional)
+
Point for the camera to look at.
number zoom (optional)
+
Camera zoom.
number rot (optional)
+
Camera rotation in radians.
+
Returns:
+
camera
+
A new camera.
+
Example:
camera = require 'hump.camera'
 -- camera looking at (100,100) with zoom 2 and rotated by 45 degrees
 cam = camera(100,100, 2, math.pi/2)
-

function camera:rotate(angle)^ top

Rotate the camera by some angle. To set the angle use camera.rot = new_angle.

This function is shortcut to camera.rot = camera.rot + angle.

Parameters:
number angle
Rotation angle in radians
Returns:
camera
The camera.
Example:
function love.update(dt)
+
+

function camera:rotate(angle)^top

Rotate the camera by some angle. To set the angle use camera.rot = new_angle.

+ +

This function is shortcut to camera.rot = camera.rot + angle.

+
Parameters:
+
number angle
+
Rotation angle in radians
+
Returns:
+
camera
+
The camera.
+
Examples:
function love.update(dt)
     camera:rotate(dt)
-end
function love.update(dt)
+end
+
+
function love.update(dt)
     camera:rotate(dt):move(dt,dt)
-end

function camera:rotation(angle)^ top

Returns camera.rot.

If given an angle, set rotation: camera.rot = angle.

Parameters:
number angle (optional)
Rotation angle in radians
Returns:
number
Rotation angle in radians.
Example:
love.graphics.print(camera:rotation(), 10, 10)
camera:rotation(math.pi/2)

function camera:move(dx,dy)^ top

Move the camera by some vector. To set the position, use camera:lookAt(x,y).

This function is shortcut to camera.x,camera.y = camera.x+dx, camera.y+dy.

Parameters:
numbers dx,dy
Direction to move the camera.
Returns:
camera
The camera.
Example:
function love.update(dt)
+end
+
+

function camera:rotation(angle)^top

Returns camera.rot.

+ +

If given an angle, set rotation: camera.rot = angle.

+
Parameters:
+
number angle (optional)
+
Rotation angle in radians
+
Returns:
+
number
+
Rotation angle in radians.
+
Example:
love.graphics.print(camera:rotation(), 10, 10)
+camera:rotation(math.pi/2)
+
+

function camera:move(dx,dy)^top

Move the camera by some vector. To set the position, use +camera:lookAt(x,y).

+ +

This function is shortcut to camera.x,camera.y = camera.x+dx, camera.y+dy.

+
Parameters:
+
numbers dx,dy
+
Direction to move the camera.
+
Returns:
+
camera
+
The camera.
+
Examples:
function love.update(dt)
     camera:move(dt * 5, dt * 6)
-end
function love.update(dt)
+end
+
+
function love.update(dt)
     camera:move(dt * 5, dt * 6):rotate(dt)
-end

function camera:lookAt(x,y)^ top

Let the camera look at a point. In other words, it sets the camera position. To move the camera by some amount, use camera:move(x,y).

This function is shortcut to camera.x,camera.y = x, y.

Parameters:
numbers x,y
Position to look at.
Returns:
camera
The camera.
Example:
function love.update(dt)
+end
+
+

function camera:lookAt(x,y)^top

Let the camera look at a point. In other words, it sets the camera position. To +move the camera by some amount, use camera:move(x,y).

+ +

This function is shortcut to camera.x,camera.y = x, y.

+
Parameters:
+
numbers x,y
+
Position to look at.
+
Returns:
+
camera
+
The camera.
+
Examples:
function love.update(dt)
     camera:lookAt(player.pos:unpack())
-end
function love.update(dt)
+end
+
+
function love.update(dt)
     camera:lookAt(player.pos:unpack()):rotation(player.rot)
-end

function camera:pos()^ top

Returns camera.x, camera.y.

Parameters:
None
Returns:
numbers
Camera position.
Example:
-- let the camera fly!
+end
+
+

function camera:pos()^top

Returns camera.x, camera.y.

+
Parameters:
None
Returns:
+
numbers
+
Camera position.
+
Example:
-- let the camera fly!
 local cam_dx, cam_dy = 0, 0
+
 function love.mousereleased(x,y)
-	local cx,cy = camera:position()
-	dx, dy = x-cx, y-cy
+    local cx,cy = camera:position()
+    dx, dy = x-cx, y-cy
 end
 
 function love.update(dt)
-	camera:move(dx * dt, dy * dt)
-end

function camera:attach()^ top

Start looking through the camera.

Apply camera transformations, i.e. move, scale and rotate everything until camera:detach() as if looking through the camera.

Parameters:
None
Returns:
Nothing
Example:
function love.draw()
+    camera:move(dx * dt, dy * dt)
+end
+
+

function camera:attach()^top

Start looking through the camera.

+ +

Apply camera transformations, i.e. move, scale and rotate everything until +camera:detach() as if looking through the camera.

+
Parameters:
None
Returns:
Nothing
Example:
function love.draw()
     camera:attach()
     draw_world()
     cam:detach()
 
     draw_hud()
-end

function camera:detach()^ top

Stop looking through the camera.

Parameters:
None
Returns:
Nothing
Example:
function love.draw()
+end
+
+

function camera:detach()^top

Stop looking through the camera.

+
Parameters:
None
Returns:
Nothing
Example:
function love.draw()
     camera:attach()
     draw_world()
     cam:detach()
 
     draw_hud()
-end

function camera:draw(func)^ top

Wrap a function between a camera:attach()/camera:detach() pair:

cam:attach()
+end
+
+

function camera:draw(func)^top

Wrap a function between a camera:attach()/camera:detach() pair:

+ +
cam:attach()
 func()
-cam:detach()

Parameters:
function func
Drawing function to be wrapped.
Returns:
Nothing
Example:
function love.draw()
+cam:detach()
+
+
Parameters:
+
function func
+
Drawing function to be wrapped.
+
Returns:
Nothing
Example:
function love.draw()
     camera:draw(draw_world)
     draw_hud()
-end

function camera:worldCoords(x, y)^ top

function camera:cameraCoords(x, y)^ top

Because a camera has a point it looks at, a rotation and a zoom factor, it defines a coordinate system. A point now has two sets of coordinates: One defines where the point is to be found in the game world, and the other describes the position on the computer screen. The first set of coordinates is called world coordinates, the second one camera coordinates. Sometimes it is needed to convert between the two coordinate systems, for example to get the position of a mouse click in the game world in a strategy game, or to see if an object is visible on the screen.

These two functions convert a point between these two coordinate systems.

Parameters:
numbers x, y
Point to transform.
Returns:
numbers
Transformed point.
Example:
x,y = camera:worldCoords(love.mouse.getPosition())
-selectedUnit:plotPath(x,y)
-
x,y = cam:cameraCoords(player.pos)
-love.graphics.line(x, y, love.mouse.getPosition())
-

function camera:mousepos()^ top

Shortcut to camera:worldCoords(love.mouse.getPosition()).

Parameters:
None
Returns:
numbers
Mouse position in world coordinates.
Example:
x,y = camera:mousepos()
-selectedUnit:plotPath(x,y)
-

hump.ringbuffer^ top

Ringbuffer = require "hump.ringbuffer"

A ring-buffer is a circular array: It does not have a first nor a last item, but it has a selected or current element.

A ring-buffer can be used to implement Tomb Raider style inventories, looping play-lists, 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 ring-buffer.

The module name is a shortcut to this function.

Parameters:
mixed ...
Initial elements.
Returns:
Ringbuffer
The ring-buffer object.
Example:
Ringbuffer = require 'hump.ringbuffer'
+end
+
+

function camera:worldCoords(x, y)^top

Because a camera has a point it looks at, a rotation and a zoom factor, it +defines a coordinate system. A point now has two sets of coordinates: One +defines where the point is to be found in the game world, and the other +describes the position on the computer screen. The first set of coordinates is +called world coordinates, the second one camera coordinates. Sometimes it +is needed to convert between the two coordinate systems, for example to get the +position of a mouse click in the game world in a strategy game, or to see if an +object is visible on the screen.

+

camera:worldCoords(x,y) and camera:cameraCoords(x,y) transform a point +between these two coordinate systems.

+
Parameters:
+
numbers x, y
+
Point to transform.
+
Returns:
+
numbers
+
Transformed point.
+
Example:
x,y = camera:worldCoords(love.mouse.getPosition())
+selectedUnit:plotPath(x,y)
+
+

function camera:cameraCoords(x, y)^top

Because a camera has a point it looks at, a rotation and a zoom factor, it +defines a coordinate system. A point now has two sets of coordinates: One +defines where the point is to be found in the game world, and the other +describes the position on the computer screen. The first set of coordinates is +called world coordinates, the second one camera coordinates. Sometimes it +is needed to convert between the two coordinate systems, for example to get the +position of a mouse click in the game world in a strategy game, or to see if an +object is visible on the screen.

+ +

camera:worldCoords(x,y) and camera:cameraCoords(x,y) transform a point +between these two coordinate systems.

+
Parameters:
+
numbers x, y
+
Point to transform.
+
Returns:
+
numbers
+
Transformed point.
+
Example:
x,y = cam:cameraCoords(player.pos)
+love.graphics.line(x, y, love.mouse.getPosition())
+
+

function camera:mousepos()^top

Shortcut to camera:worldCoords(love.mouse.getPosition()).

+
Parameters:
None
Returns:
+
numbers
+
Mouse position in world coordinates.
+
Example:
x,y = camera:mousepos()
+selectedUnit:plotPath(x,y)
+
+

hump.ringbuffer^top

Ringbuffer = require "hump.ringbuffer"
+
+ +

A ring-buffer is a circular array: It does not have a first nor a last item, +but it has a selected or current element.

+ +

A ring-buffer can be used to implement Tomb Raider style +inventories, looping play-lists, +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 a new ringbuffer.
ringbuffer:insert()
Inser elements.
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 ring-buffer.

+ +

The module name is a shortcut to this function.

+
Parameters:
+
mixed ...
+
Initial elements.
+
Returns:
+
Ringbuffer
+
The ring-buffer object.
+
Example:
ringbuffer = require 'hump.ringbuffer'
+rb = ringbuffer.new(1,2,3)
+-- or:
 rb = ringbuffer(1,2,3)
-

function ringbuffer:insert(...)^ top

Insert items behind current element.

Parameters:
mixed ...
Items to insert.
Returns:
Nothing
Example:
rb = RingbuffeR(1,5,6) -- content: 1,5,6
+
+

function ringbuffer:insert(...)^top

Insert items behind current element.

+
Parameters:
+
mixed ...
+
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 current item, return it and select next element.

Parameters:
None
Returns:
mixed
The removed item.
Example:
rb = Ringbuffer(1,2,3,4) -- content: 1,2,3,4
+
+

function ringbuffer:remove()^top

Remove current item, return it and select next element.

+
Parameters:
None
Returns:
+
mixed
+
The removed item.
+
Example:
rb = Ringbuffer(1,2,3,4) -- content: 1,2,3,4
 val = rb:remove()        -- content: 2,3,4
 print(val)               -- prints `1'
-

function ringbuffer:removeAt(pos)^ top

Remove the item at a position relative to the current element.

Parameters:
number pos
Position of the item to remove.
Returns:
mixed
The removed item.
Example:
rb = Ringbuffer(1,2,3,4,5) -- content: 1,2,3,4,5
+
+

function ringbuffer:removeAt(pos)^top

Remove the item at a position relative to the current element.

+
Parameters:
+
number pos
+
Position of the item to remove.
+
Returns:
+
mixed
+
The removed item.
+
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 the next element.

Parameters:
None
Returns:
mixed
The next item.
Example:
rb = Ringbuffer(1,2,3)
+
+

function ringbuffer:next()^top

Select and return the next element.

+
Parameters:
None
Returns:
+
mixed
+
The next item.
+
Example:
rb = Ringbuffer(1,2,3)
 rb:next()     -- content: 2,3,1
 rb:next()     -- content: 3,1,2
 x = rb:next() -- content: 1,2,3
 print(x)      -- prints `1'
-

function ringbuffer:prev()^ top

Select and return the previous item.

Parameters:
None
Returns:
mixed
The previous item.
Example:
rb = Ringbuffer(1,2,3)
+
+

function ringbuffer:prev()^top

Select and return the previous item.

+
Parameters:
None
Returns:
+
mixed
+
The previous item.
+
Example:
rb = Ringbuffer(1,2,3)
 rb:prev())    -- content: 3,1,2
 rb:prev())    -- content: 2,3,1
 x = rb:prev() -- content: 1,2,3
 print(x)      -- prints `1'
-

function ringbuffer:get()^ top

Return the current element.

Parameters:
None
Returns:
mixed
The currently selected element.
Example:
rb = Ringbuffer(1,2,3)
+
+

function ringbuffer:get()^top

Return the current element.

+
Parameters:
None
Returns:
+
mixed
+
The currently selected element.
+
Example:
rb = Ringbuffer(1,2,3)
 rb:next()       -- content: 2,3,1
 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)
+
+

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'
-

License^ top

Yay, free software:

Copyright (c) 2010 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.

Download^ top

You can view and download the individual modules on github: vrld/hump. You may also download the whole packed sourcecode either in zip or tar formats.

You can clone the project with Git by running:

git clone git://github.com/vrld/hump
Once done, you can check for updates by running
git pull

\ No newline at end of file +
+

License^top

Yay, free software

+ +

Copyright (c) 2010-2012 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.

+

Download^top

You can view and download the individual modules on github: vrld/hump +You may also download the whole packed sourcecode either in +zip or +tar formats.

+ +

Using Git, you can clone the project by running:

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

Once done, tou can check for updates by running

+ +
git pull
+
+
diff --git a/makedoc.lua b/makedoc.lua deleted file mode 100644 index ea2516a..0000000 --- a/makedoc.lua +++ /dev/null @@ -1,256 +0,0 @@ -function markup(str) - local function trim(tbl) - for i=#tbl,1,-1 do - if tbl[i] == ' ' then - tbl[i] = nil - else - return tbl - end - end - end - - local parse, block, block2, element, code, url, title, def, dt, dd - function parse(out, next) - local c = next() - if not c then return out end - if c == ' ' or c == '\t' then return parse(out, next) end - out[#out+1] = '

' - if c == '[' then return element(out, next) end - out[#out+1] = c - return block(out, next) - end - - function block(out, next) - local c = next() - if not c then out[#out+1] = '

' return out end - if c == '[' then return element(out, next) end - if c == '\n' then return block2(out, next) end - out[#out+1] = c - return block(out, next) - end - - function block2(out, next) - local c = next() - if not c then out[#out+1] = '

' return out end - if c == '[' then return element(out, next) end - if c == '\n' then out[#out+1] = '

' return parse(out, next) end - - if c ~= ' ' and c ~= '\t' then out[#out+1] = c - elseif out[#out] ~= ' ' then out[#out+1] = ' ' end - return block(out, next) - end - - function element(out, next) - local c = assert(next(), 'markup error') - if c == '^' then out[#out+1] = '' return code(out, next) end - out[#out+1] = '['..c - return block(out, next) - end - - function url(out, next) - local c = assert(next(), 'markup error') - assert(c ~= ']', 'incomplete link definition') - if c == ' ' then out[#out+1] = '">' return title(out, next) end - out[#out+1] = c - return url(out, next) - end - - function title(out, next) - local c = assert(next(), 'markup error') - if c == ']' then out[#out+1] = '' return block(out, next) end - out[#out+1] = c - return title(out, next) - end - - function def(out, next) - local c = assert(next(), 'markup error') - if c == ' ' or c == '\t' or c == '\n' then return def(out, next) end - if c == ']' then out[#out+1] = '' return block(out, next) end - out[#out+1] = '
' .. c - return dt(out, next) - end - - function dt(out, next) - local c = assert(next(), 'markup error') - if c == ':' then trim(out) out[#out+1] = '
' return dd(out, next) end - out[#out+1] = c - return dt(out, next) - end - - function dd(out, next) - local c = assert(next(), 'markup error') - if c == '\n' then out[#out+1] = '
' return def(out, next) end - out[#out+1] = c - return dd(out, next) - end - - function code(out, next) - local c = assert(next(), 'markup error') - if c == ']' then out[#out+1] = '
' return block(out, next) end - out[#out+1] = c - return code(out, next) - end - - local function spans(m) - local cmd,rest = m:match('^{(.)(.+)}$') - if cmd == '#' then return ''..rest..'' end - if cmd == '*' then return ''..rest..'' end - if cmd == '!' then return ''..rest..'' end - return m - end - - return table.concat(parse({}, str:gmatch('.'))):gsub('%b{}', spans):gsub('%b{}', spans) -end - - --- PREPARE DOCUMENTATION MARKUP -local DOC = { short = {}, long = {} } - -function Module(M) - for _,field in ipairs{'name', 'title', 'short', 'long'} do - assert(M[field], "Module: Required field `"..field.."' is missing") - end - - DOC.short[#DOC.short+1] = ('
%s
%s
'):format(M.title, M.name, M.short) - - local long = {} - local function F(s, ...) long[#long+1] = select('#', ...) > 0 and s:format(...) or s end - F('', M.title, M.title) - F('
') -- outer block> - F('

%s^ top

', M.name) - F('
') -- preamble> - F('
%s = require "%s"
', M.title:gsub("^(%w+)%W.+", "%1"), M.name) - F(markup(M.long)) - F('
') --

Module overview

') -- overview> - for _,item in ipairs(M) do if item.short then F(item.short) end end - F('
') -- ') -- %s
%s
'):format(M.name, M.name, M.title) - - local long = {} - local function F(s, ...) long[#long+1] = select('#', ...) > 0 and s:format(...) or s end - F('', M.name, M.name) - F('

%s^ top

', M.title) -- section block> - F(markup(M.content)) - if M.example then - if type(M.example) ~= 'table' then M.example = {M.example} end - F('
Example:') - for i=1,#M.example do - F('
')
-			F(M.example[i])
-			F('
') - end - F('
') - end - F('
') --
= #M.short) - - local short = {} - for i=1,#M.short do - short[i] = ('
%s()
%s
'):format(M.name[i], M.name[i], M.short[i]) - end - short = table.concat(short) - - local args - if #M.params == 0 then - args = '()' - elseif M.params.table_argument then - args = {} - for i,p in ipairs(M.params) do - if p.name then - args[i] = p.name..' = '.. p[2] - else - args[i] = p[2] - end - end - args = '{'..table.concat(args, ', ')..'}' - else - args = {} - for i,p in ipairs(M.params) do - args[i] = p[2] - end - args = '('..table.concat(args, ', ')..')' - end - - local long = {} - local function F(s, ...) long[#long+1] = select('#', ...) > 0 and s:format(...) or s end - - -- header(s) - for i=1,#M.name do F('', M.name[i], M.name[i]) end - F('
') - for i=1,#M.name do - F('

function %s%s^ top

', M.name[i], args) -- section block> - end - - -- description - F(markup(M.long)) - - -- parameters - F('
Parameters:
') - if #M.params == 0 then F('
None
') end - for _,p in ipairs(M.params) do - F('
%s %s%s
%s
', p[1], p[2], p.optional and ' (optional)' or '', markup(p[3]):sub(4,-5)) - end - F('
') - - -- return values - F('
Returns:
') - if #M.returns == 0 then F('
Nothing
') end - for _,r in ipairs(M.returns) do - F('
%s
%s
', r[1], markup(r[2]):sub(4,-5)) - end - F('
') - - -- example(s) - if type(M.example) ~= 'table' then M.example = {M.example} end - F('
Example:') - for i=1,#M.example do - F('
')
-		F(M.example[i])
-		F('
') - end - F('
') - - -- sketch - if M.sketch then - F('
Sketch:
', M.sketch[1], M.sketch.width, M.sketch.height) - end - - F('
') --
hump - LÖVE Helper Utilities for More Productivity

Introduction^ top

Helper Utilities for a Multitude of Problems is a set of lightweight helpers for the awesome LÖVE Engine.

hump differs from other libraries in that every component is independent of the remaining ones. hump's footprint is very small and thus should fit nicely into your projects.

Documentation^ top

]]) -io.write('
'..table.concat(DOC.short):gsub('Ö', 'Ö')..'
') -io.write([[
]]) -io.write(''..table.concat(DOC.long):gsub('Ö', 'Ö')) -io.write[[

License^ top

Yay, free software:

Copyright (c) 2010 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.

Download^ top

You can view and download the individual modules on github: vrld/hump. You may also download the whole packed sourcecode either in zip or tar formats.

You can clone the project with Git by running:

git clone git://github.com/vrld/hump
Once done, you can check for updates by running
git pull

]]