beginContact physics callback doesn't trigger at random
Posted: Thu Dec 24, 2015 11:48 pm
So I'm trying to make a basic Breakout type game and it seems like my beginContact physics callback doesn't trigger at random. I'm sure there's a reason, but I can't find it. Did I set up my physics objects wrong? Or am I handling moving the paddle wrong? Ignore the fact that the actual physics code in my beginContact function is wrong. I know it's wrong.
The first debug printout doesn't execute sometimes though, which is how I know the function isn't even getting called. The "ball" will phase through both the paddle and the walls at random or collide at a point that isn't right on the paddle object. Any thoughts? My full code is below.
The code is all self-contained and no external files are needed. Left/right arrow keys to move the paddle and space bar to set the ball's velocity to move straight down. Fiddle with it a little and eventually you'll see the ball phase right through the paddle and/or walls.
Edit: Fixed it! I just want to thank ThatTreeOverThere for pointing out my error. I was using instead of what I should have been using: In essence, I was not drawing the paddle where it actually was. The getX() and getY() of the body was referencing the center of the body, but when you draw, the origin is the top-left of the body. So I was drawing a rectangle starting at the center of the body, but the body was actually positioned up and to the left of where I was drawing it. Glad to have that one figured out!
The first debug printout doesn't execute sometimes though, which is how I know the function isn't even getting called. The "ball" will phase through both the paddle and the walls at random or collide at a point that isn't right on the paddle object. Any thoughts? My full code is below.
The code is all self-contained and no external files are needed. Left/right arrow keys to move the paddle and space bar to set the ball's velocity to move straight down. Fiddle with it a little and eventually you'll see the ball phase right through the paddle and/or walls.
Code: Select all
function love.load()
-- One meter is 32px in physics engine
love.physics.setMeter( 32 )
-- Create physics world with no gravity
world = love.physics.newWorld(0,0,true)
-- Create walls
wallPos = {{0,0,800,10},{790,0,10,600},{0,590,800,10},{0,0,10,600}}
walls = {}
for i = 1, #wallPos, 1 do
walls[i] = {
body = love.physics.newBody(world,wallPos[i][1],wallPos[i][2],"static"),
shape = love.physics.newRectangleShape(0,0,wallPos[i][3],wallPos[i][4])
}
walls[i].fixture = love.physics.newFixture(walls[i].body, walls[i].shape)
walls[i].body:setMassData(walls[i].shape:computeMass(1))
end
-- Create blocks
-- Create paddle at (300, 500) dynamic
paddle = love.physics.newBody(world,300,500,"dynamic")
paddle_shape = love.physics.newRectangleShape(0, 0, 200, 10)
paddle_fixture = love.physics.newFixture(paddle, paddle_shape)
paddle_fixture:setUserData("Paddle")
paddle:setMassData(paddle_shape:computeMass(1))
-- Load the image of the ball
--ball = love.graphics.newImage("love-ball.png")
-- Create a Body for the circle
circle = love.physics.newBody(world, 400, 200, "dynamic")
-- Attach a shape to the body
circle_shape = love.physics.newCircleShape(0,0,32)
-- Create a fixture between body and shape
circle_fixture = love.physics.newFixture(circle, circle_shape)
circle_fixture:setUserData("Ball")
-- Calculate the mass of the body based on attached shapes for realistic simulation
circle:setMassData(circle_shape:computeMass(1))
-- Set collision callbacks
world:setCallbacks(beginContact,endContact)
end
function love.update(dt)
world:update(dt)
end
function love.draw()
for i = 1, #walls, 1 do
topLeftX, topLeftY, botRightX, botRightY = walls[i].fixture:getBoundingBox()
love.graphics.rectangle("line", walls[i].body:getX(), walls[i].body:getY(), botRightX-topLeftX, botRightY-topLeftY)
end
love.graphics.rectangle("line", 1, 1, 798, 10)
love.graphics.rectangle("fill", paddle:getX(), paddle:getY(), 200, 10)
love.graphics.circle("line", circle:getX(), circle:getY(), circle_shape:getRadius())
end
function love.keypressed(key)
if key == "escape" then
love.event.quit()
elseif key == "left" then
paddle:setLinearVelocity(-150,0)
elseif key == "right" then
paddle:setLinearVelocity(150,0)
elseif key == " " then
circle:setLinearVelocity(0,150)
end
end
function love.keyreleased(key)
if key == "left" or key == "right" then
if love.keyboard.isDown("left") then
paddle:setLinearVelocity(-150,0)
elseif love.keyboard.isDown("right") then
paddle:setLinearVelocity(150,0)
else
paddle:setLinearVelocity(0,0)
end
end
end
function beginContact(a, b, c)
print(a, b, c:getNormal())
-- Reflective bounce on collision
local nX, nY = c:getNormal()
if a:getUserData() == "Ball" then
local aBody = a:getBody()
local aVelX, aVelY = aBody:getLinearVelocity()
aVelX = aVelX * math.cos(nX)
aVelY = aVelY * math.sin(ny)
-- Add paddle's X velocity to the ball
if b:getUserData() == "Paddle" then
aVelX = aVelX + b:getBody():getLinearVelocity()
end
aBody:setLinearVelocity(aVelX, aVelY)
end
if b:getUserData() == "Ball" then
local bBody = b:getBody()
local bVelX, bVelY = bBody:getLinearVelocity()
bVelX = bVelX * math.cos(nX)
bVelY = bVelY * math.sin(nY)
-- Add paddle's X velocity to the ball
if a:getUserData() == "Paddle" then
bVelX = bVelX + a:getBody():getLinearVelocity()
end
bBody:setLinearVelocity(bVelX, bVelY)
end
end
function endContact(a, b, c)
if a:getUserData() == "Block" then
--delete block
end
if b:getUserData() == "Block" then
--delete block
end
end
Edit: Fixed it! I just want to thank ThatTreeOverThere for pointing out my error. I was using
Code: Select all
love.graphics.rectangle("fill", paddle:getX(), paddle:getY(), 200, 10)
Code: Select all
love.graphics.polygon("line", paddle:getWorldPoints(paddle_shape:getPoints()))