Initial commit

This commit is contained in:
Matthias Richter 2010-08-09 17:52:48 +02:00
commit f491a92eaa
5 changed files with 357 additions and 0 deletions

95
README.textile Normal file
View File

@ -0,0 +1,95 @@
h1. HUMP - Helper Utilities for Massive Progression
__HUMP__ is a small collection of tools for developing games with LÖVE.
h2. Contents:
* *vector.lua*: powerful vector class (pure lua)
* *class.lua*: "class" system supporting function inheritance
* *camera.lua*: translate-, zoom- and rotatable camera
* *gamestate.lua*: class to handle gamestates
h1. Documentation
h2. vector.lua
h4. Basic
@function vector(x,y)@
Creates a new vector. Element access with @v.x@ and @v.y@.
|Parameters:| @x@ _number_ | x coordinate |
| | @y@ _number_ | y coordinate |
|Returns: | the vector | |
@function isvector(v)@
Tests for vector type.
|Parameters:| @v@ |
|Returns: | @true@ if @v@ is a vector |
@function Vector:clone()@
Clones a vector.
|Returns: | new vector with the same coordinates |
@function Vector:unpack()@
Unpacks the vector.
|Returns: | the coordinate tuple @x, y@ |
*Example:*
@v = vector(1,2)
print(v:unpack()) -- prints "1 2"@
h4. Operators
Arithmetic (@+@, @-@, @*@, @/@) and comparative operators (@==@, @<=@, @<@) are defined.
* @+@ and @-@ _only_ work on vectors. @-@ is also the unary minus (e.g. @print(-vector(1,0)) -- prints (-1,0)@
* @a * b@ works on vectors and numbers: ==<br />==If @a@ is a number and @b@ is a vector (or vice versa), the result the scalar multiplication. If @a@ and @b@ are vectors, then the result is the _dot product_.|
* @a / b@ is only defined for @a@ being a vector and @b@ being a number. Result is the same as @a * 1/b@
@<=@ and @<@ sort lexically, i.e. @a <= b@ if it holds: @a.x < b.x@ or @a.y < b.y@ if @a.x == b.x@
h4. Even more!
@function vector:permul(other)@
Perform element-wise multiplication.
@function vector:len()@
Get length of vector.
@function vector:len2()@
Get squared length.
@function vector:dist(other)@
Get distance to other vector.
*Example:*
@a,b = vector(0,1), vector(1,0)
print(a:dist(b)) -- prints 1.4142135623731@
@function vector:normalized()@
Get normalized vector. The original vector remains unchanged.
@function vector:normalize_inplace()@
Normalize vector and return it.
*Warning:* This will change the state of all references to this vector.
@function Vector:rotated(phi)@
Get rotated vector. The original vector remains unchanged.
|Parameters:| @phi@ | Rotation angle in radians. |
@function Vector:rotate_inplace(phi)@
Rotate the vector and return it.
*Warning:* This will change the state of all references to this vector.
h2. class.lua
h2. camera.lua
_Depends on vector.lua_
h2. gamestate.lua

50
camera.lua Normal file
View File

@ -0,0 +1,50 @@
require 'vector'
local camera = {}
camera.__index = camera
function Camera(pos, zoom, rot)
local pos = pos or vector(love.graphics.getWidth(), love.graphics.getHeight()) / 2
local zoom = zoom or 1
local rot = rot or 0
return setmetatable({pos = pos, zoom = zoom, rot = rot}, camera)
end
function camera:rotate(phi)
self.rot = self.rot + phi
end
function camera:translate(t)
self.pos = self.pos + t
end
function camera:apply()
local center = vector(love.graphics.getWidth(), love.graphics.getHeight()) / (self.zoom * 2)
love.graphics.push()
love.graphics.scale(self.zoom)
love.graphics.translate(center:unpack())
love.graphics.rotate(self.rot)
love.graphics.translate((-self.pos):unpack())
end
function camera:deapply()
love.graphics.pop()
end
function camera:draw(func)
self:apply()
func()
self:deapply()
end
function camera:transform(p)
local w,h = love.graphics.getWidth(), love.graphics.getHeight()
-- click to camera coords
p.x, p.y = p.x - w/2, p.y - h/2
-- to world coords
p = vector(p.x / self.zoom, p.y / self.zoom):rotate_inplace(-self.rot)
return p + self.pos
end
function camera:mousepos()
return self:transform(vector(love.mouse.getPosition()))
end

42
class.lua Normal file
View File

@ -0,0 +1,42 @@
local function __NULL__() end
function Class(constructor)
-- check name and constructor
local name = '<unnamed class>'
if type(constructor) == "table" then
if constructor.name then name = constructor.name end
constructor = constructor[1]
end
assert(not constructor or type(constructor) == "function",
string.format('%s: constructor has to be nil or a function', name))
-- build class
local c = {}
c.__index = c
c.__tostring = function() return string.format("<instance of %s>", name) end
c.construct = constructor or __NULL__
local meta = {
__call = function(self, ...)
local obj = {}
self.construct(obj, ...)
return setmetatable(obj, self)
end,
__tostring = function() return tostring(name) end
}
return setmetatable(c, meta)
end
function Interface(name) return Class{name = name or "<unnamed interface>"} end
function Inherit(class, interface, ...)
if not interface then return end
-- __index and construct are not overwritten as for them class[name] is defined
for name, func in pairs(interface) do
if not class[name] and type(func) == "function" then
class[name] = func
end
end
Inherit(class, ...)
end

66
gamestate.lua Normal file
View File

@ -0,0 +1,66 @@
Gamestate = {}
local function __NULL__() end
function Gamestate.new()
return {
enter = __NULL__,
leave = __NULL__,
update = __NULL__,
draw = __NULL__,
keyreleased = __NULL__,
keypressed = __NULL__,
mousereleased = __NULL__,
}
end
function Gamestate.switch(to, ...)
if not to then return end
if Gamestate.current then
Gamestate.current:leave()
end
local pre = Gamestate.current
Gamestate.current = to
Gamestate.current:enter(pre, ...)
end
local _update
function Gamestate.update(dt)
if _update then _update(dt) end
Gamestate.current:update(dt)
end
local _keypressed
function Gamestate.keypressed(key, unicode)
if _keypressed then _keyreleased(key) end
Gamestate.current:keypressed(key, unicode)
end
local _keyreleased
function Gamestate.keyreleased(key)
if _keyreleased then _keyreleased(key) end
Gamestate.current:keyreleased(key)
end
local _mousereleased
function Gamestate.mousereleased(x,y,btn)
if _mousereleased then _mousereleased(x,y,btn) end
Gamestate.current:mousereleased(x,y,btn)
end
local _draw
function Gamestate.draw()
if _draw then _draw() end
Gamestate.current:draw()
end
function Gamestate.registerEvents()
_update = love.update
love.update = Gamestate.update
_keypressed = love.keypressed
love.keypressed = Gamestate.keypressed
_keyreleased = love.keyreleased
love.keyreleased = Gamestate.keyreleased
_mousereleased = love.mousereleased
love.mousereleased = Gamestate.mousereleased
_draw = love.draw
love.draw = Gamestate.draw
end

104
vector.lua Normal file
View File

@ -0,0 +1,104 @@
local Vector = {}
Vector.__index = Vector
function vector(x,y)
local v = {x = x or 0, y = y or 0}
setmetatable(v, Vector)
return v
end
function isvector(v)
return getmetatable(v) == Vector
end
function Vector:clone()
return vector(self.x, self.y)
end
function Vector:unpack()
return self.x, self.y
end
function Vector:__tostring()
return "("..tonumber(self.x)..","..tonumber(self.y)..")"
end
function Vector.__unm(a)
return vector(-a.x, -a.y)
end
function Vector.__add(a,b)
assert(isvector(a) and isvector(b), "Add: wrong argument types (<vector> expected)")
return vector(a.x+b.x, a.y+b.y)
end
function Vector.__sub(a,b)
assert(isvector(a) and isvector(b), "Sub: wrong argument types (<vector> expexted)")
return vector(a.x-b.x, a.y-b.y)
end
function Vector.__mul(a,b)
if type(a) == "number" then
return vector(a*b.x, a*b.y)
elseif type(b) == "number" then
return vector(b*a.x, b*a.y)
else
assert(isvector(a) and isvector(b), "Mul: wrong argument types (<vector> or <number> expected)")
return a.x*b.x + a.y*b.y
end
end
function Vector.__div(a,b)
assert(isvector(a) and type(b) == "number", "wrong argument types (expected <vector> / <number>)")
return vector(a.x / b, a.y / b)
end
function Vector.__eq(a,b)
return a.x == b.x and a.y == b.y
end
function Vector.__lt(a,b)
return a.x < b.x or (a.x == b.x and a.y < b.y)
end
function Vector.__le(a,b)
return a.x <= b.x and a.y <= b.y
end
function Vector.permul(a,b)
assert(isvector(a) and isvector(b), "permul: wrong argument types (<vector> expected)")
return vector(a.x*b.x, a.y*b.y)
end
function Vector:len2()
return self * self
end
function Vector:len()
return math.sqrt(self*self)
end
function Vector.dist(a, b)
assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
return (b-a):len()
end
function Vector:normalize_inplace()
local l = self:len()
self.x, self.y = self.x / l, self.y / l
return self
end
function Vector:normalized()
return self / self:len()
end
function Vector:rotate_inplace(phi)
local c, s = math.cos(phi), math.sin(phi)
self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
return self
end
function Vector:rotated(phi)
return self:clone():rotate_inplace(phi)
end