Skip to content

Instantly share code, notes, and snippets.

@idbrii
Last active April 18, 2025 19:04
Show Gist options
  • Save idbrii/55392e5888640ba6f8a17452760e7694 to your computer and use it in GitHub Desktop.
Save idbrii/55392e5888640ba6f8a17452760e7694 to your computer and use it in GitHub Desktop.
Love2d Physics Tutorial -- but with kinematic player body
-- Demonstration of love physics with a kinematic body
-- based on dynamic version: https://love2d.org/wiki/Tutorial:Physics
--
--
-- When an object is controlled by setting its position instead of applying
-- forces, it should be kinematic. But when it interacts with dynamic
-- bodies, sometimes they are sleeping and do not respond to collisions.
--
-- Possible solutions:
-- * set velocity instead of position
-- * detect collision and awaken bodies that collided
-- * disable sleeping for all bodies in the world
local objects, world
function love.load()
love.physics.setMeter(64)
-- One possibility is to prevent any bodies from sleeping. Costs
-- performance: physics must now calculate all bodies instead of only
-- awake ones. Change can_bodies_sleep to false and setPosition-based
-- movement works as expected.
local can_bodies_sleep = true
-- create a world for the bodies to exist in with no gravity
world = love.physics.newWorld(0, 0, can_bodies_sleep)
objects = {}
objects.ground = {}
objects.ground.body = love.physics.newBody(world, 650/2, 650-50/2)
objects.ground.shape = love.physics.newRectangleShape(650, 50)
objects.ground.fixture = love.physics.newFixture(objects.ground.body,
objects.ground.shape)
objects.ball = {}
objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "kinematic")
objects.ball.shape = love.physics.newCircleShape(20)
objects.ball.fixture = love.physics.newFixture(objects.ball.body,
objects.ball.shape, 1)
objects.ball.fixture:setRestitution(0.9)
objects.block1 = {}
objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100)
objects.block1.fixture = love.physics.newFixture(objects.block1.body,
objects.block1.shape, 5)
objects.blocks = { objects.block1 }
for i=1,5 do
local b = {}
b.body = love.physics.newBody(world, 200, 400, "dynamic")
b.shape = love.physics.newRectangleShape(0, 0, 100, 50)
b.fixture = love.physics.newFixture(b.body, b.shape, 2)
table.insert(objects.blocks, b)
end
love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
love.window.setMode(650, 650)
end
-- Unlike position, we need to set velocity even when not moving so we can go
-- back to 0 velocity.
local used_velocity = false
function love.update(dt)
world:update(dt)
-- provide two ways of moving the ball:
-- * position (arrow keys)
-- * veloctiy (wasd)
local x,y = objects.ball.body:getPosition()
local modified_position = false
local speed = 100
if love.keyboard.isDown("right") then
modified_position = true
x = x + speed * dt
elseif love.keyboard.isDown("left") then
modified_position = true
x = x - speed * dt
elseif love.keyboard.isDown("up") then
modified_position = true
y = y - speed * dt
elseif love.keyboard.isDown("down") then
modified_position = true
y = y + speed * dt
elseif love.keyboard.isDown("u") then
-- wake Up
-- When setting position, you can force all blocks to awaken to show how
-- awaking bodies solves collision problems. In a real game, maybe you'd do
-- this in a collision callback?
for key,b in pairs(objects.blocks) do
b.body:setAwake(true)
end
print("awaken")
end
if modified_position then
objects.ball.body:setPosition(x,y)
used_velocity = false
end
x,y = 0,0
speed = 5000
if love.keyboard.isDown("d") then
used_velocity = true
x = speed * dt
elseif love.keyboard.isDown("a") then
used_velocity = true
x = - speed * dt
elseif love.keyboard.isDown("w") then
used_velocity = true
y = - speed * dt
elseif love.keyboard.isDown("s") then
used_velocity = true
y = speed * dt
end
if used_velocity then
objects.ball.body:setLinearVelocity(x,y)
end
if love.keyboard.isDown("escape") then
love.event.quit()
elseif love.keyboard.isDown("g") then
-- Change gravity for fun.
local gx,gy = world:getGravity()
if love.keyboard.isDown("lshift", "rshift") then
gy = math.min(gy + 0.1, 9.81*64*4)
else
gy = math.max(gy - 0.1, 0)
end
world:setGravity(gx, gy)
end
end
function love.draw()
love.graphics.setColor(0.28, 0.63, 0.05)
love.graphics.polygon("fill", objects.ground.body:getWorldPoints(
objects.ground.shape:getPoints()))
love.graphics.setColor(0.76, 0.18, 0.05)
love.graphics.circle("fill", objects.ball.body:getX(),
objects.ball.body:getY(), objects.ball.shape:getRadius())
love.graphics.setColor(0.20, 0.20, 0.20)
for key,b in pairs(objects.blocks) do
love.graphics.polygon(
"fill",
b.body:getWorldPoints(
b.shape:getPoints()))
end
love.graphics.setColor(1,1,1)
local x,y = world:getGravity()
love.graphics.printf(string.format("gravity: %.2f,%.2f", x,y), 0,0, 100, "left")
love.graphics.printf("arrow keys to move with position\nwasd to move with velocity", 0,50, 300, "left")
love.graphics.printf("g or G to change gravity and u to awaken blocks.", 300,0, 350, "left")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment