Skip to content

Instantly share code, notes, and snippets.

@randrews randrews/main.lua
Created Aug 8, 2012

Embed
What would you like to do?
Example code for nice-feeling player movement in Love
require 'point'
function love.load()
math.randomseed(os.time())
love.physics.setMeter(32)
love.graphics.setBackgroundColor(64, 120, 64)
world = love.physics.newWorld(0, 0)
crates = { makeCrate(world, 5, 5),
makeCrate(world, 5, 6) }
player = makePlayer(world)
end
function makeCrate(world, x, y)
local b = love.physics.newBody(world, x*32 + 16, y*32 + 16, 'dynamic')
local s = love.physics.newRectangleShape(0, 0, 32, 32)
love.physics.newFixture(b, s)
b:setFixedRotation(true)
b:setMass(5)
b:setLinearDamping(4)
return {body=b, shape=s}
end
function makePlayer(world)
local b = love.physics.newBody(world, 48, 48, 'dynamic')
local s = love.physics.newCircleShape(16)
love.physics.newFixture(b, s)
b:setMass(1)
return {body=b, shape=s}
end
function love.draw()
local g = love.graphics
-- Draw player
g.setColor(160, 64, 64)
g.circle('fill', player.body:getX(), player.body:getY(), 16)
-- Draw crates
g.setColor(180, 120, 90)
for _, c in ipairs(crates) do
g.rectangle('fill', c.body:getX()-16, c.body:getY()-16, 32, 32)
end
end
--------------------------------------------------
function love.update(dt)
local k = love.keyboard.isDown
local kd = 0
local dir = point(0, 0)
if k('up') then dir = dir + point.up ; kd = kd + 1 end
if k('down') then dir = dir + point.down ; kd = kd + 1 end
if k('left') then dir = dir + point.left ; kd = kd + 1 end
if k('right') then dir = dir + point.right ; kd = kd + 1 end
if kd > 0 then
player.body:setLinearDamping(0)
else
player.body:setLinearDamping(8)
end
max_speed(player.body, 320)
local f = dir * 320
player.body:applyForce(f.x, f.y)
if kd == 1 then
dampenSidewaysVelocity(player.body, dir, dt)
end
for _, c in ipairs(crates) do
local sq = point(
math.floor(c.body:getX() / 32),
math.floor(c.body:getY() / 32))
nudgeToSquare(c.body, sq, 20)
end
world:update(dt)
end
function max_speed(body, spd)
local x, y = body:getLinearVelocity()
if x*x + y*y > spd*spd then
local a = math.atan2(y,x)
body:setLinearVelocity(spd * math.cos(a),
spd * math.sin(a))
end
end
function dampenSidewaysVelocity(body, dir, dt)
local a = 1 - 4 * dt
if a > 1.0 then a = 1.0 elseif a < 0 then a = 0 end
local v = point(body:getLinearVelocity())
if dir.y == 0 then v.y = v.y * a end
if dir.x == 0 then v.x = v.x * a end
body:setLinearVelocity(v())
end
function nudgeToSquare(body, sq, acc)
local y = body:getY() - 16
local ty = sq.y * 32
local f = acc * (ty - y)
body:applyForce(0, f)
local x = body:getX() - 16
local tx = sq.x * 32
local f = acc * (tx - x)
body:applyForce(f, 0)
end
module(..., package.seeall)
local methods = {}
local instance = {__index=methods}
function new(x,y)
local tbl = {x=x, y=y}
return setmetatable(tbl, instance)
end
north = new(0, -1) ; up = north
south = new(0, 1) ; down = south
west = new(-1, 0) ; left = west
east = new(1, 0) ; right = east
local mt = getmetatable(_M)
mt.__call=function(t,x,y)
return t.new(x,y)
end
function methods:copy()
return new(self.x, self.y)
end
function methods:ortho(pt2)
return self.x == pt2.x or self.y == pt2.y
end
function methods:toward(pt2)
if not self:ortho(pt2) then error(self .. ' not in a straight line with ' .. pt2)
else
local v = pt2 - self
if v.x > 0 then v.x=1 end
if v.x < 0 then v.x=-1 end
if v.y > 0 then v.y=1 end
if v.y < 0 then v.y=-1 end
return v
end
end
function methods:adjacent(pt2)
local d = pt2-self
return (d.x == 0 or d.y == 0) and (math.abs(d.x+d.y) == 1)
end
function instance.__add(pt1, pt2)
assert(pt1 and pt2)
return new(pt1.x+pt2.x, pt1.y+pt2.y)
end
function instance.__sub(pt1, pt2)
assert(pt1 and pt2)
return new(pt1.x-pt2.x, pt1.y-pt2.y)
end
function instance.__mul(pt1, pt2)
assert(pt1 and pt2)
if type(pt2) == 'number' then
return new(pt1.x * pt2, pt1.y * pt2)
else
return new(pt1.x*pt2.x, pt1.y*pt2.y)
end
end
methods.translate = instance.__add
function instance.__tostring(pt)
return string.format('(%d, %d)', pt.x, pt.y)
end
function instance.__call(pt)
return pt.x, pt.y
end
function instance.__eq(pt1, pt2)
return pt1.x == pt2.x and pt1.y == pt2.y
end
-- A point is "less than" a point if each
-- coord is less than the corresponding one
function instance.__lt(pt1, pt2)
return pt1.x < pt2.x and pt1.y < pt2.y
end
function instance.__le(pt1, pt2)
return pt1.x <= pt2.x and pt1.y <= pt2.y
end
function test()
local p = point(2,3)
assert(p.x == 2 and p.y == 3)
assert(tostring(p) == "(2, 3)")
p = p + point(1,1)
assert(tostring(p) == "(3, 4)")
local p2 = p:copy()
p2.y = p2.y-1
assert(tostring(p) == "(3, 4)")
assert(tostring(p2) == "(3, 3)")
assert(p2 + point(1, 1) == point(4, 4))
local o1, o2 = point(3, 3), point(3, 5)
assert(o1:ortho(o2))
assert(o2-o1 == point(0, 2))
assert(o1:toward(o2) == point(0, 1))
local a1, a2, a3 = point(2, 2), point(1, 2), point(3, 3)
assert(a1:adjacent(a2))
assert(a2:adjacent(a1))
assert(not a2:adjacent(a3))
assert(not a1:adjacent(a3))
assert(not a1:adjacent(a1))
assert(a2 <= a1)
assert(a1 < a3)
assert(a3 > a1)
assert(not(a2 < a1))
end
test() -- Run the tests on load, error if any fail
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.