-
-
Save jrasanen/c216f096c392db83fc44061ebc98bf07 to your computer and use it in GitHub Desktop.
Example code for nice-feeling player movement in Love
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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