Page 1 of 1

Attaching an image to a polygon shape.

Posted: Fri Jul 06, 2012 6:16 pm
by diamondf
So I've been using pixel-perfect collision using a bitmask with my game (I've only been checking the overlap of a previous box-collision, and I only check every 1/16 pixels (4x4)), which has worked perfectly for images that don't change angles. However, that is proving quite difficult with a bitmask, so I need to adapt to the physics system that LOVE is using.

I'm beginning with the system, but I'm having a problem. I can attach an image to a box shape, but I can't attach it to a polygon shape. The program just flat-out crashes. And I don't mean it gives me a blue screen of death with an error (the typical response to a bug), I mean it flat-out crashes. No insight whatsoever.

Here's a full functioning main.lua file (based off of the physics tutorial) that that works fine with my adjustments (an image attached to a box shape).
(Note, you'll need an image named rock_1.png that's 132x108 pixels):

Code: Select all

function love.load()
	love.physics.setMeter(64) --the height of a meter our worlds will be 64px
	world = love.physics.newWorld(0, 9.81*64, true) --create a world for the bodies to exist in with horizontal gravity of 0 and vertical gravity of 9.81

	objects = {} -- table to hold all our physical objects

	--let's create the ground
	objects.ground = {}
	objects.ground.body = love.physics.newBody(world, 650/2, 650-50/2) --remember, the shape (the rectangle we create next) anchors to the body from its center, so we have to move it to (650/2, 650-50/2)
	objects.ground.shape = love.physics.newRectangleShape(650, 50) --make a rectangle with a width of 650 and a height of 50
	objects.ground.fixture = love.physics.newFixture(objects.ground.body, objects.ground.shape); --attach shape to body

	--let's create a ball
	objects.ball = {}
	objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "dynamic") --place the body in the center of the world and make it dynamic, so it can move around
	objects.ball.body:setMass(15) --give it a mass of 15
	objects.ball.shape = love.physics.newCircleShape(20) --the ball's shape has a radius of 20
	objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 2) --attach shape to body and give it a friction of 1
	objects.ball.fixture:setRestitution(0.9) --let the ball bounce

	--let's create a couple blocks to play around with
	objects.block1 = {}
	objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
	objects.block1.body:setMass(3000) --uff, very heavy block at the bottom
	objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100, 45)
	objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 2) --with plenty of friction, will be hard to move around

	--[[
	objects.block2 = {}
	objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
	objects.block2.body:setMass(300)
	objects.block2.shape = love.physics.newPolygonShape(0, 0, 50, 250, 90, 300, 250, 290)
	objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 0.5)
	--]]

	objects.box = {}
	objects.box.body = love.physics.newBody(world, 400, 300, "dynamic") --this is the physics body
	--objects.box.shape = love.physics.newRectangleShape(0, 0, 50, 50, 0) --the shape is for handling collisions
	objects.box.shape = love.physics.newRectangleShape(0, 0, 132, 108, 0) --the shape is for handling collisions
	objects.box.shape = love.physics.newPolygonShape(0, 0, 46, 24, 77, 0)
	--objects.box.shape = love.physics.newPolygonShape(23, 19, 46, 24, 77, 0, 130, 68, 115, 90, 69, 104, 14, 93, 1, 59)
	objects.box.fixture = love.physics.newFixture( objects.box.body, objects.box.shape, 0.1)
	objects.box.body:setMass(1) --give it a mass of 15
	objects.box.image = love.graphics.newImage("rock_1.png")

	--initial graphics setup
	love.graphics.setBackgroundColor(104, 136, 248) --set the background color to a nice blue
	love.graphics.setMode(650, 650, false, true, 0) --set the window dimensions to 650 by 650
end

function love.update(dt)
	world:update(dt) --this puts the world into motion

	--here we are going to create some keyboard events
	if love.keyboard.isDown("right") then --press the right arrow key to push the ball to the right
		objects.ball.body:applyForce(400, 0)
	elseif love.keyboard.isDown("left") then --press the left arrow key to push the ball to the left
		objects.ball.body:applyForce(-400, 0)
	elseif love.keyboard.isDown("up") then --press the up arrow key to set the ball in the air
		objects.ball.body:setPosition(650/2, 650/2)
	end
end

function love.draw()
	love.graphics.setColor(72, 160, 14) -- set the drawing color to green for the ground
	love.graphics.polygon("fill", objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())) -- draw a "filled in" polygon using the ground's coordinates

	love.graphics.setColor(193, 47, 14) --set the drawing color to red for the ball
	love.graphics.circle("fill", objects.ball.body:getX(), objects.ball.body:getY(), objects.ball.shape:getRadius())

	love.graphics.setColor(50, 50, 50) -- set the drawing color to grey for the blocks
	love.graphics.polygon("fill", objects.block1.body:getWorldPoints(objects.block1.shape:getPoints()))
	--love.graphics.polygon("fill", objects.block2.body:getWorldPoints(objects.block2.shape:getPoints()))
	
	local b = objects.box --faster
	love.graphics.draw(b.image, b.body:getX(), b.body:getY(), b.body:getAngle(),  1, 1, b.image:getWidth()/2, b.image:getHeight()/2)
end
If you un-comment the line: objects.box.shape = love.physics.newPolygonShape(23, 19, 46, 24, 77, 0, 130, 68, 115, 90, 69, 104, 14, 93, 1, 59)
Or the line: objects.box.shape = love.physics.newPolygonShape(0, 0, 46, 24, 77, 0)

Or if you otherwise try to make it a valid (as far as I know) polygon shape, the program crashes with no insight into the problem.

Note: the newPolygonShape(23, 19, 46, 24, 77, 0, 130, 68, 115, 90, 69, 104, 14, 93, 1, 59) line indicates an appropriate polygon for the rock.

Anyone have an idea why this is happening in LOVE 0.8.0?

Re: Attaching an image to a polygon shape.

Posted: Fri Jul 06, 2012 7:12 pm
by Boolsheet
The tutorial where you have the code from has issues. Looks like it was updated from the 0.7.2 physics module to the new one. They are fairly different and some things are unnecessary or redundant. 0.8.0 introduced a few new bugs in the physics module and that's probably where the termination comes from. See Body:setMass. Box2D will recalculate the body mass if you attach a new fixture. Setting the mass just before calling the newFixture function has no effect (except trigger bugs :P).

Also, note that this polygon is not convex as required by newPolygonShape. (23, 19, 46, 24, 77, 0, 130, 68, 115, 90, 69, 104, 14, 93, 1, 59)
The simluation will break if you use this shape. Split it up into two convex shapes and attach those to the body.

Re: Attaching an image to a polygon shape.

Posted: Fri Jul 06, 2012 7:41 pm
by diamondf
Interesting, thank you. Sure enough, removing the mass piece did fix the first problem (instant crashing). As for splitting it into two objects, though, how would I achieve that? Would I have to create object.box.shape1 and object.box.shape2? And if so, how do those retain a proper angle and behavior?

Re: Attaching an image to a polygon shape.

Posted: Fri Jul 06, 2012 8:42 pm
by Boolsheet
diamondf wrote:Would I have to create object.box.shape1 and object.box.shape2? And if so, how do those retain a proper angle and behavior?
Pretty much, yeah. Use 2 shapes and 2 fixtures to create the whole rock.

The coordinates you pass to the new*Shape functions are local coordinates, they're relative to the body origin. It's just as if you would draw the shapes on a body that is at the position (0, 0) with an angle of 0.

Code: Select all

local rnd = function() return math.random() - 0.5 end

function love.load()
	World = love.physics.newWorld(0, 100, true)

	local circlePoints = {}

	for i = 1, 30 do
		local angle = (i - 1) / 30 * (math.pi * 2)
		local x, y = math.cos(angle) * 250 + rnd() * 40, math.sin(angle) * 250 + rnd() * 40
		circlePoints[i * 2 - 1], circlePoints[i * 2] = x, y
	end

	Circle = {}
	Circle.body = love.physics.newBody(World, 0, 0, "kinematic")
	Circle.shape = love.physics.newChainShape(true, unpack(circlePoints))
	Circle.fixture = love.physics.newFixture(Circle.body, Circle.shape)
	Circle.body:setAngularVelocity(0.5)


	Stone = {}
	Stone.body = love.physics.newBody(World, 0, 0, "dynamic")
	Stone.shape1 = love.physics.newPolygonShape(23, 19, 46, 24,  69, 104, 14, 93, 1, 59)
	Stone.shape2 = love.physics.newPolygonShape(46, 24, 77, 0, 130, 68, 115, 90, 69, 104)
	Stone.fixture1 = love.physics.newFixture(Stone.body, Stone.shape1, 5)
	Stone.fixture2 = love.physics.newFixture(Stone.body, Stone.shape2, 5)
end


function love.update(dt)
	World:update(dt)
end

function love.draw()
	love.graphics.translate(400, 300)

	love.graphics.line(Circle.body:getWorldPoints(Circle.shape:getPoints()))

	love.graphics.polygon("line", Stone.body:getWorldPoints(Stone.shape1:getPoints()))
	love.graphics.polygon("line", Stone.body:getWorldPoints(Stone.shape2:getPoints()))
end

Re: Attaching an image to a polygon shape.

Posted: Fri Jul 06, 2012 8:58 pm
by diamondf
Wow. That was an extremely impressive and helpful example you posted. Yep, that pretty much summarizes absolutely everything I needed. Thank you!