diff --git a/doc.lua b/doc.lua
new file mode 100644
index 0000000..d03616b
--- /dev/null
+++ b/doc.lua
@@ -0,0 +1,1711 @@
+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 = {
+ {"function", "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 = {
+ {"function", "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 = {"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 = {
+ {"function", "func", "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]===],
+ },
+
+ Function { name = "Interpolator",
+ short = "Create a new interpolating function.",
+ long = [===[
+ Create a wrapper for an interpolating function, i.e. a function that
+ acts depending on how much time has passed.
+
+ The wrapper will have the prototype:
+ [%function wrapper(dt, ...)]
+ where {#dt} is the time that has passed since the last call of the
+ wrapper and {#...} are arguments passed to the interpolating function.
+ It will return whatever the interpolating functions returns if the
+ interpolation is not yet finished or nil if the interpolation is done.
+
+ The prototype of the interpolating function is:
+ [%function interpolator(fraction, ...)]
+ where {#fraction} is a number between 0 and 1 depending on how much
+ time has passed and {#...} are additional arguments supplied to the
+ wrapper.]===],
+ params = {
+ {"number", "length", "Interpolation length in seconds."},
+ {"function", "func", "Interpolating function."},
+ },
+ returns = {
+ {"function", "The wrapper function."}
+ },
+ example = [===[
+fader = Timer.Interpolator(5, function(frac, r,g,b)
+ love.graphics.setBackgroundColor(frac*r,frac*g,frac*b)
+end)
+
+function love.update(dt)
+ fader(dt, 255,255,255)
+end]===],
+ },
+
+ Function { name = "Oscillator",
+ short = "Create a new oscillating function.",
+ long = [===[
+ Create a wrapper for an oscillating function, which is basically a
+ looping interpolating function.
+
+ The function prototypes are the same as with {#Interpolator()}:
+ [%function wrapper(dt, ...)]
+ [%function oscillator(fraction, ...)]
+
+ As with {#Interpolator}, the wrapper will return whatever
+ {#oscillator()} returns.]===],
+ params = {
+ {"number", "length", "Length of one interpolation period."},
+ {"function", "func", "Oscillating function."},
+ },
+ returns = {
+ {"function", "The wrapper function."}
+ },
+ example = [===[
+mover = Timer.Oscillator(10, function(frac)
+ return 400 + 300 * math.sin(2*math.pi*frac)
+end)
+
+local xpos = 100
+function love.update(dt)
+ xpos = mover(dt)
+end
+
+function love.draw()
+ love.graphics.circle('fill', xpos, 300, 80, 36)
+end]===],
+ },
+}
+
+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 ' hump is a collection of lightweight, yet powerful modules to speed up
- game development with LÖVE. It offers
- solutions to various small but annoyingly reccurent problems. You can download the latest packaged version of hump as zip-
- or tar-archive directly from
- github. You can also view and download the sourcecode
- of individual modules here. If you use the Git command line client, you can clone
- the repository by running: Once done, you can check for updates by running: from inside the directory. Copyright (c) 2010-2011 Matthias Richter Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software. Except as contained in this notice, the name(s) of the above copyright holders
- shall not be used in advertising or otherwise to promote the sale, use or
- other dealings in this Software without prior written authorization. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE. A gamestate encapsulates independant data an behaviour into a single entity. A typical game could consist of a menu-state, a level-state and a game-over-state. A gamestate can define (nearly) all callbacks that LÖVE defines. In addition, there are callbacks
- for entering and leaving a state.: When using registerEvents(), all these
- callbacks will receive the same arguments as the LÖVE callbacks do. 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 (apart from camera.lua, which does depends on vector-light.lua). hump's footprint is very small and thus should fit nicely into your projects. 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. A gamestate can define (nearly) all callbacks that LÖVE defines. In addition, there are callbacks for entering and leaving a state.: When using Declare a new gamestate. A gamestate can define several callbacks. Switch to a gamestate, with any additional arguments passed to the new state. Switching a gamestate will call the Calls the corresponding function on the current gamestate (see callbacks). Only needed when not using Declare a new gamestate. A gamestate can define several callbacks. Switch to a gamestate, with any additional arguments passed to the new state. Switching a gamestate will call the Calls the corresponding function on the current gamestate (see callbacks). Only needed when not using Register all love callbacks to call This is achieved by overwriting the love callbacks, e.g.: Register love callbacks to call This is by done by overwriting the love callbacks, e.g.: Note: Only works when called in hump.timer provides a simple interface to use delayed functions, i.e.
- functions that will only be executed after some amount time. In addition, the module offers facilities to create functions that
- interpolate or oscillate over time. Add a timed function. The function will be executed when Note that there is no guarantee that the delay will be exceeded. It is, however, guaranteed that the
- function will not be executed before the delay has passed. The function 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. 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. Schedule a function. The function will be executed after 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. Add a periodic timed function, i.e. a function that will be called Returning If Add a function that will be called If Clears all timers. Update timers and execute functions if the deadline is reached. Use this in Prevent a timer from being executed in the future. Always use the function handle returned by Never use this inside a scheduled function. Remove all timed and periodic functions. Functions that have not yet been executed will discarded. Never use this inside a scheduled function. Update timers and execute functions if the deadline is reached. Use this in Create a wrapper for an interpolating function, i.e. a function that acts depending on how much time has passed. The wrapper will have the prototype:
- The prototype of the interpolating function is:
- Create a wrapper for an interpolating function, i.e. a function that acts depending on how much time has passed. The wrapper will have the prototype: The prototype of the interpolating function is: Create a wrapper for an oscillating function, which is basically a looping interpolating function. The function prototypes are the same as with The wrapper function will return whatever Create a wrapper for an oscillating function, which is basically a looping interpolating function. The function prototypes are the same as with As with A handy 2D vector class defining the most common things you do with vectors. You can access the individual coordinates by using Vector arithmetic is implemented by using Relational operators are defined, too: A handy 2D vector class providing most of the things you do with vectors. You can access the individual coordinates by using Vector arithmetic is implemented by using Relational operators are defined, too: Create new vector As a shortcut, you can call the module like a function, i.e.: Test whether a variable is a vector. Create a new vector. Test whether a variable is a vector. Copy a vector. Simply assigning a vector a vector to a variable will create
- a reference, so when you modify the vector referenced by the new variable, will
- also change the old one: 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: Extract coordinates. Multiplies vectors coordinate wise, i.e. This does not change either argument vectors, but creates a new one. Get length of a vector, i.e. Get squared length of a vector, i.e. Extract coordinates. Multiplies vectors coordinate wise, i.e. This does not change either argument vectors, but creates a new one. Get length of a vector, i.e. Get squared length of a vector, i.e. Get distance of two vectors. The same as Get distance of two vectors. The same as Get normalized vector, i.e. a vector with the same direction as the input vector,
- but length 1. This does not change the input vector, but creates a new vector. Normalize a vector, i.e. make the vector unit length. This modifies the vector. If in doubt, use Get a rotated vector. This does not change the input vector, but creates a new 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. Normalize a vector, i.e. make the vector unit length. Great to use on intermediate results. This modifies the vector. If in doubt, use Get a rotated vector. This does not change the input vector, but creates a new vector. Rotate a vector in-place. Great to use on intermediate results. This modifies the vector. If in doubt, use Quick rotation by 90°. Creates a new vector. The same (but faster) as Project vector onto another vector (see sketch). Mirrors vector on the axis defined by the other vector. Get cross product of both vectors. Equals the area of the parallelogram spanned by both vectors. An table-free version of Using this module instead of Transforms a vector to a string of the form Computes Computes the sum/difference of vectors. Same as Multiplies vectors coordinate wise, i.e. Computes the dot product of two vectors, Computes the cross product/determinant of two vectors, Compares two vectors according to Get length of a vector, i.e. Get squared length of a vector, i.e. Get distance of two points. The same as Get normalized vector, i.e. a vector with the same direction as the input vector, but with length 1. Get a rotated vector. Quick rotation by 90°. The same (but faster) as Project vector onto another vector. Mirrors vector on the axis defined by the other vector. A small, fast class implementation with multiple inheritance support 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 The name of the variable that holds the module can be used as a shortcut to Rotate a vector. This modifies the vector. If in doubt, use Quick rotation by 90°. Creates a new vector. The same as (but faster): Project vector onto another vector. Get cross product of both vectors. For the math geeks: The cross product not be defined for 2D vectors. To nonetheless get a result,
- treat the vectors as being 3D vectors (x,y,0). The cross product of both
- vectors has just a z-component, and this is what this function returns.
- It's also the determinant of both vectors: d = det(a,b). Define a new class. The constructor will receive the newly created object as first argument. If no name is given, the module tries to guess the name. However, this will only
- work if the class is assigned to a global variable. You can check if an object is an instance of a class using If you 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. Calls class constructor of a class. Needed in constructors of child classes to initialize parts of the object that the parent classes define. Inherit functions (but not class variables). This is done by simply copying
- the function-references over to the subclass. If you change the function of a superclass
- at runtime, these changes will not affect the subclasses. If multiple super-classes are defined inherit from all of these. If two super-classes define
- a method of the same name, inherit it from the one mentioned first. 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: Tests whether an object is an instance of a class. Tests whether an object is an instance of a class. Be careful when using metamethods like Be careful when using metamethods like Note that while you can define the Note that while you can define the 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. 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. Registers a function Calls all functions bound to signal Unbinds (removes) functions from signal Removes all functions from signal Emits all signals matching a string pattern. Removes functions from all signals matching a string pattern. Removes all functions from all signals matching a string pattern. Depends on hump.vector-light 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. Creates a new camera object. You can access the camera position using The module variable name can be used at a shortcut to Depends on vector Camera abstraction for LÖVE. A camera "looks" at a position and can be moved,
- zoomed and rotated. A camera defines it's own coordinate system, meaning that an object shown on
- the screen likely has different coordinates in the game world than it has on the screen. For example, the mouse position could be at pixel The camera class defines methods to convert between both coordinate systems. Create new camera object. You can access and modify the camera parameters using If you assigned the module to a variable, you can call the module as a
- shortcut to Rotate the camera. Same as Move the camera. Same as Apply camera transformations, i.e. move, scale and rotate everything so that you see
- what you would see when looking through the camera. Everything until the next Rotate the camera by some angle. To set the angle use This function is shortcut to Move the camera by some vector. To set the position, use This function is shortcut to Start looking through the camera. Apply camera transformations, i.e. move, scale and rotate everything until Revert camera transformations done by Stop looking through the camera. Wrap a function between Wrap a function between a 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. Shortcut to 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. Create new ring-buffer. The module name is a shortcut to this function. Convert world coordinates to camera coordinates. Convert camera coordinates to world coordinates. A ring-buffer is a circular array. That means it does not have a first nor a
- last, but only a selected/current element. You can use this to implement Tomb Raider style inventories, looping
- playlists, recurring dialogs (like a unit's answers when selecting it multiple times in Warcraft)
- and generally everything that has a circular or looping structure. Create new ringbuffer. Insert items behind current element. Remove currently selected item and select next item. Remove item at position relative to current item. Insert items behind current element. Remove current item, return it and select next element. Remove the item at a position relative to the current element. Select and return next item. Select and return previous item. Get currently selected item. Select and return the next element. Select and return the previous item. Return the current element. Get number of items in the buffer. Get number of items in the buffer 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. '
+ 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] = 'hump Helper Utilities for More Productivity
- Documentation
-Download
- git clone git://github.com/vrld/hump
- git pull
- License
-
-
-
- Gamestate = require "hump.gamestate"
Module overview
-
-
- Gamestate Callbacks
-
-
- menu = Gamestate.new()
+
hump Helper Utilities for More Productivity
Introduction^ top
Documentation^ top
hump.gamestate^ top
Gamestate = require "hump.gamestate"
Module overview
Gamestate Callbacks^ top
init()
switch()
.enter(previous, ...)
switch()
.leave()
switch()
.update()
draw()
focus()
keypressed()
keyreleased()
mousepressed()
mousereleased()
joystickpressed()
joystickreleased()
quit()
registerEvents()
, all these callbacks will receive the same arguments as the LÖVE callbacks do.
- menu = Gamestate.new()
function menu:init() -- run only once
self.background = love.graphics.newImage('bg.jpg')
Buttons.initialize()
@@ -201,94 +35,7 @@ function menu:mousereleased(x,y, mouse_btn)
button:onClick()
end
end
-end
-
-
-
-
- menu = Gamestate.new()
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.
-
- to
...
to:enter()
.
-
- to:enter()
.
- Gamestate.switch(game, level_two)
registerEvents()
.
-
- ...
-
- function love.update(dt)
+end
function new()^ top
menu = Gamestate.new()
function switch(to, ...)^ top
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.to
...
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
registerEvents()
....
- function love.update(dt)
Gamestate.update(dt)
end
@@ -299,238 +46,38 @@ end
function love.keypressed(key, code)
Gamestate.keypressed(key, code)
-end
Gamestate.update()
, Gamestate.draw()
, etc. automatically.local _update = love.update
+end
function registerEvents(callbacks)^ top
Gamestate.update()
, Gamestate.draw()
, etc. automatically.
-
- local old_update = love.update
function love.update(dt)
- _update(dt)
+ old_update(dt)
Gamestate.current:update(dt)
-end
-
-
-
- function love.load()
+end
love.load()
or any other function that is executedafter the whole file is loaded.callbacks
(optional)
- function love.load()
Gamestate.registerEvents()
Gamestate.switch(menu)
-end
- Timer = require "hump.timer"
Module overview
-
-
- delay
seconds have elapsed.func
will receive itself as only parameter. This may be useful to implement
- the periodic behavior of Timer.addPeriodic
.
-
- delay
func
-
- -- grant the player 5 seconds of immortality
+end
function love.load()
+ Gamestate.registerEvents{'draw', 'update', 'quit'}
+ Gamestate.switch(menu)
+end
hump.timer^ top
Timer = require "hump.timer"
Module overview
function new()^ top
instance:update(dt)
), while the global timer uses the dot-notation (e.g. Timer.update(dt)
).menuTimer = Timer.new()
function add(delay, func)^ top
function instance:add(delay, func)^ top
delay
seconds have elapsed, given that update(dt)
is called every frame.func
will receive itself as only parameter. This is useful to implement periodic behavior (see the example).delay
func
- -- grant the player 5 seconds of immortality
player.isInvincible = true
-Timer.add(5, function() player.isInvincible = false end)
- -- print "foo" every second
-Timer.add(1, function(func) print("foo") Timer.add(1, func) end)
count
times every delay
seconds.false
will immediately stop the timer, regardless if it was called count
times or not.count
is omitted, the function loops until the function returns false
or clear()
is called.
-
- delay
func
count
-
-
- Timer.addPeriodic(1, function() lamp:toggleLight() end)
- Timer.addPeriodic(0.3, function() mothership: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 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
count
times every delay
seconds.count
is omitted, the function will be called until it returns false
or clear()
is called.delay
func
count
(optional)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)
-
-
-
-
- Timer.clear()
love.update()
.
-
- dt
update()
.
-
- function love.update(dt)
+end)
function cancel(func)^ top
function instance:cancel(func)^ top
add()
/addPeriodic()
to cancel a timer.func
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
Timer.clear()
function update(dt)^ top
function instance:update(dt)^ top
love.update(dt)
.dt
- function love.update(dt)
do_stuff()
Timer.update(dt)
-end
- function wrapper(dt, ...)
dt
is the time that has passed since the last call and ...
are arguments passed to the
- interpolating function. It will return whatever the interpolating functions returns if the interpolation is not yet finished or
- nil
if the interpolation is done.
-
- where function inter(fraction, ...)
fraction
is a number between 0 and 1 and ...
are additional arguments supplied to
- the wrapper.
-
-
- length
func
-
- fader = Timer.Interpolator(5, function(frac, r,g,b)
+end
function Interpolator(length, func)^ top
where function wrapper(dt, ...)
dt
is the time that has passed since the last call of the wrapper and ...
are arguments passed to the interpolating function. It will return whatever the interpolating functions returns if the interpolation is not yet finished or nil if the interpolation is done.
where function interpolator(fraction, ...)
fraction
is a number between 0 and 1 depending on how much time has passed and ...
are additional arguments supplied to the wrapper.length
func
- fader = Timer.Interpolator(5, function(frac, r,g,b)
love.graphics.setBackgroundColor(frac*r,frac*g,frac*b)
end)
function love.update(dt)
fader(dt, 255,255,255)
-end
Interpolator()
:
-
- function wrapper(dt, ...)
- function oscillator(fraction, ...)
oscillator()
returns.
-
- length
func
-
- mover = Timer.Oscillator(10, function(frac)
+end
function Oscillator(length, func)^ top
Interpolator()
: function wrapper(dt, ...)
function oscillator(fraction, ...)
Interpolator
, the wrapper will return whatever oscillator()
returns.length
func
- mover = Timer.Oscillator(10, function(frac)
return 400 + 300 * math.sin(2*math.pi*frac)
end)
@@ -541,513 +88,66 @@ end
function love.draw()
love.graphics.circle('fill', xpos, 300, 80, 36)
-end
- vector = require "hump.vector"
vec.x
and vec.y
.Module overview
-
-
- __add
, __mul
and other metamethods:
-
-
- vector + vector = vector
vector - vector = vector
vector * vector = number
number * vector = vector
vector * number = vector
vector / number = vector
-
-
- 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
true
, if a.x < b.x
or a.x == b.x
and a.y < b.y
.acceleration = vector(0,-9)
+end
hump.vector^ top
vector = require "hump.vector"
vec.x
and vec.y
.Module overview
Arithmetics and relations^ top
__add
, __mul
and other metamethods:vector + vector = vector
vector - vector = vector
vector * vector = number
number * vector = vector
vector * number = vector
vector / number = vector
true
, if a.x == b.x
and a.y == b.y
.true
, if a.x <= b.x
and a.y <= b.y
.true
, if a.x < b.x
or a.x == b.x
and a.y < b.y
.
- -- 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
-
- x, y
-
-
- a = vector.new(10,10)
- vector = require 'hump.vector'
-a = vector(10,10)
-
- v
-
- true
if v
is a vector, false
otherwise.if not vector.isvector(v) then
+player.position = player.position + player.velocity * dt
function new(x,y)^ top
x,y
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
v
true
if v
is a vector, false
otherwise
- if not vector.isvector(v) then
v = vector(v,0)
-end
a = vector(1,1) -- create vector
+end
function vector:clone()^ top
- 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)'
-
-
-
-
- copy = original:clone()
-
-
-
-
- x,y = pos:unpack()
- love.graphics.draw(self.image, self.pos:unpack())
result = vector(a.x * b.x, a.y * b.y)
.
-
- other
-
-
- scaled = original:permul(vector(1,1.5))
math.sqrt(vec.x * vec.x + vec.y * vec.y)
.
-
-
-
-
- distance = (a - b):len()
vec.x * vec.x + vec.y * vec.y
.
-
-
-
- -- get closest vertex to a given vector
+print(a,b,c) -- prints '(1,0), (1,0), (1,1)'
copy = original:clone
function vector:unpack()^ top
x,y = pos:unpack()
love.graphics.draw(self.image, self.pos:unpack())
function vector:permul(other)^ top
result = vector(a.x * b.x, a.y * b.y)
.other
scaled = original:permul(vector(1,1.5))
function vector:len()^ top
math.sqrt(vec.x * vec.x + vec.y * vec.y)
.distance = (a - b):len()
function vector:len2()^ top
vec.x * vec.x + vec.y * vec.y
.
- -- 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
(a - b):len()
.
-
- other
-
- -- get closest vertex to a given vector
+end
function vector:dist(other)^ top
(a - b):len()
.other
- -- 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
-
-
-
-
- normal = edge:normalized()
vector:normalized()
.
-
-
-
-
- normal = (b - a):perpendicular():normalize_inplace()
-
- phi
-
- -- approximate a circle
+end
function vector:normalized()^ top
direction = velocity:normalized()
function vector:normalize_inplace()^ top
vector:normalized()
.normal = (b - a):perpendicular():normalize_inplace()
function vector:rotated(phi)^ top
phi
- -- 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
function vector:rotate_inplace(phi)^ top
vector:rotate()
phi
-- ongoing rotation
+spawner.direction:rotate_inplace(dt)
function vector:perpendicular()^ top
vec:rotate(math.pi/2)
normal = (b - a):perpendicular():normalize_inplace()
function vector:projectOn(v)^ top
v
velocity_component = velocity:projectOn(axis)
function vector:mirrorOn(v)^ top
v
deflected_velocity = ball.velocity:mirrorOn(surface_normal)
function vector:cross(other)^ top
other
parallelogram_area = a:cross(b)
hump.vector-light^ top
vector = require "hump.vector-light"
hump.vector
. Instead of a vector class, hump.vector-light
provides functions that operate on numbers.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
function str(x,y)^ top
(x,y)
.x,y
print(vector.str(love.mouse.getPosition()))
function mul(s, x,y)^ top
function div(s, x,y)^ top
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).s
x,y
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
x1+x2,y1+y2
and x1-x2,y1-y2
respectively. Meant to be used in conjunction with other functions.x1,y1
x2,y2
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
x1*x2,y1*y2
.x1,y1
x2,y2
x,y = vector.permul(x,y, 1,1.5)
function dot(x1,y1, x2,y2)^ top
x1*x2+y1*y2
.x1,y1
x2,y2
cosphi = vector.dot(rx,ry, vx,vy)
function det(x1,y1, x2,y2)^ top
function cross(x1,y1, x2,y2)^ top
x1*y2-y1*x2
.x1,y1
x2,y2
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
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
x1,y1
x2,y2
...
function len(x,y)^ top
math.sqrt(x*x + y*y)
.x,y
distance = vector.len(love.mouse.getPosition())
function len2(x,y)^ top
x*x + y*y
.x,y
-- 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)^ top
vector.len(x1-x2, y1-y2)
.x1,y1
x2,y2
-- 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)^ top
x,y
dx,dy = vector.normalize(vx,vy)
function rotate(phi, x,y)^ top
phi
x,y
-- 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
vector.rotate(math.pi/2, x,y)
x,y
nx,ny = vector.normalize(vector.perpendicular(bx-ax, by-ay))
function project(x,y, u,v)^ top
x,y
u,v
vx_p,vy_p = vector.project(vx,vy, ax,ay)
function mirror(x,y, u,v)^ top
x,y
u,v
vx,vy = vector.mirror(vx,vy, surface.x,surface.y)
hump.class^ top
Class = require "hump.class"
Module overview
function new{constructor, name = the_name, inherits = super}^ top
object:is_a()
.new()
(see example).constructor
(optional)theclass.construct(object, ...)
the_name
(optional)tostring()
.super
(optional)Class = require 'hump.class' -- `Class' is now a shortcut to new()
-
-
vector:rotate()
.
-
- phi
-
-
- -- ongoing rotation
-spawner.direction:rotate_inplace(dt)
- vec:rotate(math.pi/2)
-
-
-
-
- normal = (b - a):perpendicular():normalize_inplace()
-
- v
-
-
- velocity_component = velocity:projectOn(axis)
-
- other
-
-
- parallelogram_area = a:cross(b)
- A small, handy class implementation with multiple inheritance.
- Class = require "hump.class"
Module overview
-
-
- object:is_a(class)
.require
d the module to a variable, you can use the variable
- as a shortcut to new()
.
-
- constructor
the_name
tostring()
on the class.super
-
-
- Class = require 'hump.class'
-
--- define class with implicit name 'Feline'
-Feline = Class(function(self, size, weight)
+-- define unnamed class
+Feline = Class{function(self, size, weight)
self.size = size
self.weight = weight
-end)
-print(Feline) -- prints 'Feline'
+end}
+print(Feline) -- prints '
Class = require 'hump.class'
+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)
@@ -1068,8 +168,8 @@ Feline = Class{name = "Feline", function(self, size, weight)
end}
garfield = Feline(.7, 45)
-print(Feline, garfield) -- prints 'Feline <instance of Feline>'
Class = require 'hump.class'
+print(Feline, garfield) -- prints '
- Class = require 'hump.class'
A = Class{}
function A:foo()
print('foo')
@@ -1089,169 +189,111 @@ instance:foo() -- prints 'foo'
D = Class{inherits = {A,B}}
instance = D()
instance:foo() -- prints 'foo'
-instance:bar() -- prints 'bar'
function class.construct(object, ...)^ top
object
self
....
Class = require 'hump.class'
-
-
-
- object
self
....
-
- Class = require 'hump.class'
-
-Feline = Class{function(self, size, weight)
- self.size = size
- self.weight = weight
+Shape = Class{function(self, area)
+ self.area = area
end}
-
-Cat = Class{function(self, name, size, weight)
- Feline.construct(self, size, weight)
- self.name = name
-end}
-Cat:inherit(Feline)
-
- class
super, ...
-
- Class = require 'hump.class'
-
-Feline = Class{function(self, size, weight)
- self.size = size
- self.weight = weight
-end}
-
-function Feline:stats()
- return string.format("size: %.02f, weight %.02f", self.size, self.weight)
+function Shape:__tostring()
+ return "area = " .. self.area
end
-function Feline:speak() print("meow") end
-
-Cat = Class{function(self, name, size, weight)
- Feline.construct(self, size, weight)
- self.name = name
+Rectangle = Class{inherits = Shape, function(self, width, height)
+ Shape.construct(self, width * height)
+ self.width = width
+ self.height = height
end}
-Cat:inherit(Feline)
-
-function Cat:stats()
- return string.format("name: %s, %s", self.name, Feline.stats(self))
+function Rectangle:__tostring()
+ local strs = {
+ "width = " .. self.width,
+ "height = " .. self.height,
+ Shape.__tostring(self)
+ },
+ return table.concat(strs, ", ")
end
-Tiger = Class{function(self, size, weight)
- Feline.construct(self, size, weight)
+print( Rectangle(2,4) ) -- prints 'width = 2, height = 4, area = 8'
+
Menu = Class{function(self)
+ self.entries = {}
end}
-Tiger:Inherit(Feline)
+function Menu:add(title, entry)
+ self.entries[#self.entries + 1] = entry
+end
+function Menu:display()
+ -- ...
+end
-function Tiger:speak() print("ROAR!") end
+Entry = Class{function(self, title, command)
+ self.title = title
+ self.command = command
+end}
+function Entry:execute()
+ return self.command()
+end
-felix = Cat("Felix", .8, 12)
-hobbes = Tiger(2.2, 68)
+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(...)^ top
class:inherit()
doesn't actually care if the arguments supplied are hump classes. Just any table will work....
- Class = require 'hump.class'
-print(felix:stats()) -- "name: Felix, size: 0.80, weight 12.00"
-print(hobbes:stats()) -- "size: 2.20, weight 68.00"
-felix:speak() -- "meow"
-hobbes:speak() -- "ROAR!"
-
- class
-
- true
, if object is an instance of class, false
otherwiseClass = require 'hump.class'
+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)^ top
cls
true
if the object is an instance of the class, false
otherwise
- 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
__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'
-
-
Caveats
- __add
or __mul
:
- When subclass inherits those methods from a superclass, but does not overwrite them,
- the result of the operation may be of the type superclass. Consider the following:
- Class = require 'hump.class'
-
-A = Class(function(self, x) self.x = x end)
+A = Class{function(self, x) self.x = x end}
function A:__add(other) return A(self.x + other.x) end
function A:show() print("A:", self.x) end
-B = Class(function(self, x, y) A.construct(self, x) self.y = y end)
-B:Inherit(A)
+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
__index
metamethod
- of the class, this is not a good idea, as 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 method won't
- affect subclasses.Class = require 'hump.class'
+result:foo() -- error: method does not exist
__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
@@ -1262,489 +304,77 @@ function A:__index(key)
end
instance = A()
-instance:foo() -- prints foo <newline> bar
+instance:foo() -- prints foo
hump.signal^ top
Signal = require "hump.signal"
hump.signal
makes things more interesing by allowing to emit all signals that match a Lua string
+ pattern.Module overview
function new()^ top
instance:emit("foo")
), while the global registry uses the dot-notation (e.g. Signal.emit("foo")
).player.signals = Signals.new()
function register(s, f)^ top
function instance:register(s, f)^ top
f
to be called when signal s
is emitted. s
f
remove
.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
s
with the supplied arguments. s
...
(optional)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
s
. s
...
Signal.remove('level-load', handle)
function clear(s)^ top
function instance:clear(s)^ top
s
. s
Signal.clear('key-left')
function emit_pattern(p, ...)^ top
function instance:emit_pattern(p, ...)^ top
p
...
(optional)Signal.emit_pattern('^update%-.*', dt)
function remove_pattern(p, ...)^ top
function instance:remove_pattern(p, ...)^ top
p
...
Signal.remove_pattern('key%-.*', play_click_sound)
function clear_pattern(p)^ top
function instance:clear_pattern(p)^ top
p
Signal.clear_pattern('sound%-.*')
Signal.clear_pattern('.*') -- clear all signals
hump.camera^ top
Camera = require "hump.camera"
Module overview
function new(x,y, zoom, rot)^ top
camera.x, camera.y
, the zoom using camera.zoom
and the rotation using camera.rot
.new()
.x,y
zoom
rot
camera = require 'hump.camera'
-
- camera = require "hump.camera"
400,400
on the screen
- (= camera coordinates), but the camera looks at the point 100,100
and
- is rotated by 90°
. The world coordinates of the mouse cursor are 200,100
.Module overview
-
-
- camera.pos
, camera.zoom
and
- camera.rot
.
-
- pos
(screen center)zoom
(1)rot
(0)
-
-
- cam = hump.camera.new(vector(400,300), 2)
hump.camera.new()
:
- camera = require 'hump.camera'
-vector = require 'hump.vector'
-
-cam = camera(vector(400,300), 2)
cam.rot = cam.rot + phi
.
-
- phi
-
-
- cam:rotate(dt)
cam.pos = cam.pos + direction
-
- direction
-
-
- cam:translate(vector(100,0) * dt)
camera:postdraw()
will be transformed.
-
-
-
- function love.draw()
- cam:predraw()
+-- 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
camera.rot = new_angle
.camera.rot = camera.rot + angle
.angle
function love.update(dt)
+ camera:rotate(dt)
+end
function love.update(dt)
+ camera:rotate(dt):move(dt,dt)
+end
function camera:move(dx,dy)^ top
camera.x,camera.y = new_x,new_y
.camera.x,camera.y = camera.x+dx, camera.y+dy
.dx,dy
function love.update(dt)
+ camera:move(dt * 5, dt * 6):rotate(dt)
+end
function camera:attach()^ top
camera:detach()
as if looking through the camera.
- function love.draw()
+ camera:attach()
draw_world()
- cam:postdraw()
- draw_hud()
-end
camera:predraw()
.
-
-
-
- function love.draw()
- cam:predraw()
+ draw_hud()
+end
function camera:detach()^ top
- function love.draw()
+ camera:attach()
draw_world()
- cam:postdraw()
- draw_hud()
-end
predraw()
and postdraw()
:cam:predraw()
+ draw_hud()
+end
function camera:draw(func)^ top
camera:attach()
/camera:detach()
pair:
- cam:attach()
func()
-cam:postdraw()
-
- func
-
- function love.draw()
- cam:draw( draw_world )
+cam:detach()
func
- function love.draw()
+ camera:draw(draw_world)
draw_hud()
-end
function camera:worldCoords(x, y)^ top
function camera:cameraCoords(x, y)^ top
x, y
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
camera:worldCoords(love.mouse.getPosition())
.x,y = camera:mousepos()
+selectedUnit:plotPath(x,y)
+
hump.ringbuffer^ top
Ringbuffer = require "hump.ringbuffer"
Module overview
function new(...)^ top
...
Ringbuffer = require 'hump.ringbuffer'
-
-
-
- pos
-
-
- screen_pos = cam:toCameraCoords( player.pos )
-love.graphics.line(love.mouse.getX(), love.mouse.getY(), screen_pos:unpack()
-
- pos
-
-
- target = cam:toWorldCoords( vector(love.mouse.getPosition()) )
-unit:plotPathTo(target)
- ringbuffer = require "hump.ringbuffer"
Module overview
-
-
-
-
- ...
-
-
-
- item, ...
-
-
- rb = ringbuffer(1,5,6) -- content: 1,5,6
-rb:insert(2,3,4) -- content: 1,2,3,4,5,6
-
-
-
-
- rb = ringbuffer(1,2,3,4) -- content: 1,2,3,4
-rb:next() -- content: 2,3,4,1
-rb:remove() -- content: 3,4,1
-
- pos
-
- rb = ringbuffer(1,2,3,4,5) -- content: 1,2,3,4,5
+rb = ringbuffer(1,2,3)
+
function ringbuffer:insert(...)^ top
...
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
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
pos
- 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
-
-
-
-
- rb = ringbuffer(1,2,3)
-print(rb:next()) -- prints '2'
-print(rb:next()) -- prints '3'
-print(rb:next()) -- prints '1'
-
-
-
-
- rb = ringbuffer(1,2,3)
-print(rb:prev()) -- prints '3'
-print(rb:prev()) -- prints '2'
-print(rb:prev()) -- prints '1'
-
-
-
- rb = ringbuffer(1,2,3)
-rb:next()
+rb:removeAt(-1) -- content: 1,2,4
+
function ringbuffer:next()^ top
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
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
- rb = Ringbuffer(1,2,3)
+rb:next() -- content: 2,3,1
print(rb:get()) -- prints '2'
-
-
-
-
- rb = ringbuffer(1,2,3)
+
function ringbuffer:size()^ top
- rb = Ringbuffer(1,2,3)
print(rb:size()) -- prints '3'
rb:remove()
-print(rb:size()) -- prints '2'
License^ top
Download^ top
'..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 = require "%s"
', M.title:gsub("^(%w+)%W.+", "%1"), M.name)
+ F(markup(M.long))
+ F('')
+ F(M.example[i])
+ F('
')
+ end
+ F('%s
%s')
+ F(M.example[i])
+ F('
')
+ end
+ F('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 (apart from camera.lua, which does depends on vector-light.lua). hump's footprint is very small and thus should fit nicely into your projects.
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.