Making a chain of physics bodies
Posted: Wed Jan 24, 2018 4:39 pm
I'm trying to make a chain with the physics module (not too different from the chains in the Box2D testbed). However, something has gone horribly wrong. After a few seconds, the segments of the chain appear disjointed and move jerkily. After a minute...chain links go flying everywhere, and most of them are off of the screen.
I'm not sure if the problem is in the part where I set up the physics bodies/fixtures or if it's how I'm drawing the bodies on the screen. I've looked at the source code from the Box2D testbed chains example, but I can't get to the bottom of it.
Here's my setup code:
Here's the code for generating segments (the head is the same except that it has 3 points instead of 4):
Here are a couple videos showing the situations in the screenshots below.
After a few seconds:
After a minute:
I'm not sure if the problem is in the part where I set up the physics bodies/fixtures or if it's how I'm drawing the bodies on the screen. I've looked at the source code from the Box2D testbed chains example, but I can't get to the bottom of it.
Here's my setup code:
Code: Select all
function love.load()
world = love.physics.newWorld(0, 9.8)
floor = love.physics.newBody(world, love.graphics.getWidth()/2, 300, "static")
love.physics.newFixture(floor, love.physics.newRectangleShape(love.graphics.getWidth(), 1), 1)
local anchorX, anchorY = love.graphics.getWidth()/2, love.graphics.getHeight()/2
anchor = love.physics.newBody(world, anchorX, anchorY)
segments = {}
segmentLength = 30
for i = 1,6 do
table.insert(segments, makeSegment(anchorX+segmentLength*i, anchorY))
end
head = makeHead(anchorX+segmentLength*7, anchorY)
love.physics.newRevoluteJoint(
anchor, segments[1].body,
anchorX, anchorY
)
for i = 1,#segments-1 do
love.physics.newRevoluteJoint(
segments[i].body, segments[i+1].body,
segments[i]:rightJoint()
)
end
love.physics.newRevoluteJoint(
segments[#segments].body, head.body,
segments[#segments]:rightJoint()
)
end
function love.update(dt)
world:update(dt)
end
function love.draw(dt)
for _, segment in pairs(segments) do
love.graphics.setColor(100, 100, 100)
love.graphics.polygon('fill', segment:getPoints())
love.graphics.setColor(180, 180, 180)
love.graphics.polygon('line', segment:getPoints())
end
love.graphics.setColor(100, 100, 100)
love.graphics.polygon('fill', head:getPoints())
love.graphics.setColor(180, 180, 180)
love.graphics.polygon('line', head:getPoints())
love.graphics.setColor(255, 255, 255)
love.graphics.print(love.timer.getFPS(), 10, 10)
love.graphics.line(love.graphics.getWidth()/2, love.graphics.getHeight()/2,
segments[1].body:getX(), segments[1].body:getY())
love.graphics.setColor(255, 0, 255)
love.graphics.points(love.graphics.getWidth()/2, love.graphics.getHeight()/2)
end
Code: Select all
function makeSegment(x, y)
local segment = {}
segment.length = 30
segment.height = 10
function segment:getPoints()
local x, y = x, y
local r = 0
if self.body then
x = self.body:getX()
y = self.body:getY()
r = self.body:getAngle()
end
local length = self.length
local height = self.height
local sinr = math.sin(r)
local cosr = math.cos(r)
return {
x + (-length/2 * cosr) - (-height/2 * sinr), y + (-length/2 * sinr) + (-height/2 * cosr),
x + ( length/2 * cosr) - (-height/2 * sinr), y + ( length/2 * sinr) + (-height/2 * cosr),
x + ( length/2 * cosr) - ( height/2 * sinr), y + ( length/2 * sinr) + ( height/2 * cosr),
x + (-length/2 * cosr) - ( height/2 * sinr), y + (-length/2 * sinr) + ( height/2 * cosr)
}
end
function segment:leftJoint()
local length = self.length
local r = self.body:getAngle()
local sinr = math.sin(r)
local cosr = math.cos(r)
return x + (-length/2 * cosr) - 0, y + (-length/2 * sinr) + 0
end
function segment:rightJoint()
local length = self.length
local r = self.body:getAngle()
local sinr = math.sin(r)
local cosr = math.cos(r)
return x + ( length/2 * cosr) - 0, y + ( length/2 * sinr) + 0
end
local body = love.physics.newBody(world, x, y, 'dynamic')
local fixture = love.physics.newFixture(
body,
love.physics.newPolygonShape(segment:getPoints())
)
segment.body = body
return segment
end
After a few seconds:
After a minute: