mirror of
https://github.com/vrld/hump.git
synced 2024-10-15 09:04:18 +00:00
Initial commit
This commit is contained in:
commit
f491a92eaa
95
README.textile
Normal file
95
README.textile
Normal 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
50
camera.lua
Normal 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
42
class.lua
Normal 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
66
gamestate.lua
Normal 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
104
vector.lua
Normal 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
|
Loading…
Reference in New Issue
Block a user