Difference between revisions of "Tutorial:Physics"

m (Corrected world creation code to reflect what the comments are saying)
(Adapted to 0.8, added some blocks to play around with)
Line 10: Line 10:
 
<source lang="lua">
 
<source lang="lua">
 
function love.load()
 
function love.load()
   world = love.physics.newWorld(0, 0, 650, 650) --create a world for the bodies to exist in with width and height of 650
+
  love.physics.setMeter(64) --the height of a meter our worlds will be 64px
  world:setGravity(0, 700) --the x component of the gravity will be 0, and the y component of the gravity will be 700
+
   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
  world:setMeter(64) --the height of a meter in this world will be 64px
 
 
</source>
 
</source>
  
Line 18: Line 17:
  
 
<source lang="lua">
 
<source lang="lua">
  objects = {} -- table to hold all our physical objects
+
  objects = {} -- table to hold all our physical objects
 
    
 
    
 
   --let's create the ground
 
   --let's create the ground
 
   objects.ground = {}
 
   objects.ground = {}
  --we need to give the ground a mass of zero so that the ground wont move
+
   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.body = love.physics.newBody(world, 650/2, 625, 0, 0) --remember, the shape anchors to the body from its center
+
   objects.ground.shape = love.physics.newRectangleShape(0, 0, 650, 50) --anchor the shape to the body, and make it a width of 650 and a height of 50
   objects.ground.shape = love.physics.newRectangleShape(objects.ground.body, 0, 0, 650, 50, 0) --anchor the shape to the body, and make it 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
 
   --let's create a ball
 
   objects.ball = {}
 
   objects.ball = {}
   objects.ball.body = love.physics.newBody(world, 650/2, 650/2, 15, 0) --place the body in the center of the world, with a mass of 15
+
   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.shape = love.physics.newCircleShape(objects.ball.body, 0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
+
  objects.ball.body:setMass(15); --give it a mass of 15
 +
   objects.ball.shape = love.physics.newCircleShape(0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
 +
  objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1.0); --attach shape to body and give it a friction of 1.0
 +
  objects.ball.fixture:setRestitution(0.9) --let the ball bounce
 +
 
 +
  --let's create 4 blocks to play around
 +
  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)
 +
  objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) --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.newRectangleShape(0, 0, 50, 100)
 +
  objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)
 +
 
 +
  objects.block3 = {}
 +
  objects.block3.body = love.physics.newBody(world, 200, 250, "dynamic")
 +
  objects.block3.body:setMass(200)
 +
  objects.block3.shape = love.physics.newRectangleShape(0, 0, 50, 100)
 +
  objects.block3.fixture = love.physics.newFixture(objects.block3.body, objects.block3.shape, 2)
 +
 
 +
  objects.block4 = {}
 +
  objects.block4.body = love.physics.newBody(world, 200, 250, "dynamic")
 +
  objects.block4.body:setMass(200)
 +
  objects.block4.shape = love.physics.newRectangleShape(0, 0, 100, 50)
 +
  objects.block4.fixture = love.physics.newFixture(objects.block4.body, objects.block4.shape, 2)
 
</source>
 
</source>
  
Line 70: Line 97:
 
function love.draw()
 
function love.draw()
 
   love.graphics.setColor(72, 160, 14) -- set the drawing color to green for the ground
 
   love.graphics.setColor(72, 160, 14) -- set the drawing color to green for the ground
   love.graphics.polygon("fill", objects.ground.shape:getPoints()) -- draw a "filled in" polygon using the ground's coordinates
+
   love.graphics.polygon("fill", objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())) -- draw a "filled in" polygon using the ground's coordinates
 +
 
 
</source>
 
</source>
  
And finally, we can draw the circle that represents the ball.
+
And finally, we can draw the circle that represents the ball and the blocks.
  
 
<source lang="lua">
 
<source lang="lua">
 
   love.graphics.setColor(193, 47, 14) --set the drawing color to red for the ball
 
   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(), 20) -- we want 20 line segments to form the "circle"
 
   love.graphics.circle("fill", objects.ball.body:getX(), objects.ball.body:getY(), objects.ball.shape:getRadius(), 20) -- we want 20 line segments to form the "circle"
 +
 +
  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()))
 +
  love.graphics.polygon("fill", objects.block3.body:getWorldPoints(objects.block3.shape:getPoints()))
 +
  love.graphics.polygon("fill", objects.block4.body:getWorldPoints(objects.block4.shape:getPoints()))
 
end
 
end
 
</source>
 
</source>
Line 89: Line 123:
 
<source lang="lua">
 
<source lang="lua">
 
function love.load()
 
function love.load()
   world = love.physics.newWorld(0, 0, 650, 650) --create a world for the bodies to exist in with width and height of 650
+
  love.physics.setMeter(64) --the height of a meter our worlds will be 64px
  world:setGravity(0, 700) --the x component of the gravity will be 0, and the y component of the gravity will be 700
+
   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
  world:setMeter(64) --the height of a meter in this world will be 64px
+
 
 
 
 
   objects = {} -- table to hold all our physical objects
 
   objects = {} -- table to hold all our physical objects
 
    
 
    
 
   --let's create the ground
 
   --let's create the ground
 
   objects.ground = {}
 
   objects.ground = {}
  --we need to give the ground a mass of zero so that the ground wont move
+
   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.body = love.physics.newBody(world, 650/2, 625, 0, 0) --remember, the body anchors from the center of the shape
+
   objects.ground.shape = love.physics.newRectangleShape(0, 0, 650, 50) --anchor the shape to the body, and make it a width of 650 and a height of 50
   objects.ground.shape = love.physics.newRectangleShape(objects.ground.body, 0, 0, 650, 50, 0) --anchor the shape to the body, and make it 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
 
   --let's create a ball
 
   objects.ball = {}
 
   objects.ball = {}
   objects.ball.body = love.physics.newBody(world, 650/2, 650/2, 15, 0) --place the body in the center of the world, with a mass of 15
+
   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.shape = love.physics.newCircleShape(objects.ball.body, 0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
+
  objects.ball.body:setMass(15); --give it a mass of 15
 +
   objects.ball.shape = love.physics.newCircleShape(0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
 +
  objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1.0); --attach shape to body and give it a friction of 1.0
 +
  objects.ball.fixture:setRestitution(0.9) --let the ball bounce
 +
 
 +
  --let's create 4 blocks to play around
 +
  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)
 +
  objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) --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.newRectangleShape(0, 0, 50, 100)
 +
  objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)
 +
 +
  objects.block3 = {}
 +
  objects.block3.body = love.physics.newBody(world, 200, 250, "dynamic")
 +
  objects.block3.body:setMass(200)
 +
  objects.block3.shape = love.physics.newRectangleShape(0, 0, 50, 100)
 +
  objects.block3.fixture = love.physics.newFixture(objects.block3.body, objects.block3.shape, 2)
 +
 +
  objects.block4 = {}
 +
  objects.block4.body = love.physics.newBody(world, 200, 250, "dynamic")
 +
  objects.block4.body:setMass(200)
 +
  objects.block4.shape = love.physics.newRectangleShape(0, 0, 100, 50)
 +
  objects.block4.fixture = love.physics.newFixture(objects.block4.body, objects.block4.shape, 2)
 +
 
 
   --initial graphics setup
 
   --initial graphics setup
 
   love.graphics.setBackgroundColor(104, 136, 248) --set the background color to a nice blue
 
   love.graphics.setBackgroundColor(104, 136, 248) --set the background color to a nice blue
Line 127: Line 188:
 
function love.draw()
 
function love.draw()
 
   love.graphics.setColor(72, 160, 14) -- set the drawing color to green for the ground
 
   love.graphics.setColor(72, 160, 14) -- set the drawing color to green for the ground
   love.graphics.polygon("fill", objects.ground.shape:getPoints()) -- draw a "filled in" polygon using the ground's coordinates
+
   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.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(), 20) -- we want 20 line segments to form the "circle"
 
   love.graphics.circle("fill", objects.ball.body:getX(), objects.ball.body:getY(), objects.ball.shape:getRadius(), 20) -- we want 20 line segments to form the "circle"
 +
 +
  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()))
 +
  love.graphics.polygon("fill", objects.block3.body:getWorldPoints(objects.block3.shape:getPoints()))
 +
  love.graphics.polygon("fill", objects.block4.body:getWorldPoints(objects.block4.shape:getPoints()))
 
end
 
end
 
</source>
 
</source>

Revision as of 15:28, 10 April 2012

In this example we will create a red ball that rolls around on a green ground.

The finished example is at the end of this page. All of these functions may be placed in one file: main.lua

We'll start in the love.load function.

love.load()

First we need to set up a world for the physics bodies to exist in.

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

Now that a world has been created, we can add bodies to it.

   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(0, 0, 650, 50) --anchor the shape to the body, and make it 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(0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
  objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1.0); --attach shape to body and give it a friction of 1.0
  objects.ball.fixture:setRestitution(0.9) --let the ball bounce

  --let's create 4 blocks to play around
  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)
  objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) --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.newRectangleShape(0, 0, 50, 100)
  objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)

  objects.block3 = {}
  objects.block3.body = love.physics.newBody(world, 200, 250, "dynamic")
  objects.block3.body:setMass(200)
  objects.block3.shape = love.physics.newRectangleShape(0, 0, 50, 100)
  objects.block3.fixture = love.physics.newFixture(objects.block3.body, objects.block3.shape, 2)

  objects.block4 = {}
  objects.block4.body = love.physics.newBody(world, 200, 250, "dynamic")
  objects.block4.body:setMass(200)
  objects.block4.shape = love.physics.newRectangleShape(0, 0, 100, 50)
  objects.block4.fixture = love.physics.newFixture(objects.block4.body, objects.block4.shape, 2)

Now to wrap up the love.load function, let's set up the screen size and background color.

  --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 with no fullscreen, vsync on, and no antialiasing
end

Okay, that's enough for the initial set up of the physics engine. Now we need do edit the love.update() function.

love.update()

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:setY(650/2)
  end
end

Now that the world is updating, we can draw the ground and ball.

love.draw()

First, the ground.

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

And finally, we can draw the circle that represents the ball and the blocks.

  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(), 20) -- we want 20 line segments to form the "circle"

  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()))
  love.graphics.polygon("fill", objects.block3.body:getWorldPoints(objects.block3.shape:getPoints()))
  love.graphics.polygon("fill", objects.block4.body:getWorldPoints(objects.block4.shape:getPoints()))
end

There you have it! Put this file in a zip file, rename it to physics.love (or whatever), run it. And you'll have a ball rolling around in a lush green environment like I promised.

Screenshot of the finished product.


The main.lua

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(0, 0, 650, 50) --anchor the shape to the body, and make it 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(0, 0, 20) --the ball's shape has no offset from it's body and has a radius of 20
  objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1.0); --attach shape to body and give it a friction of 1.0
  objects.ball.fixture:setRestitution(0.9) --let the ball bounce

  --let's create 4 blocks to play around
  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)
  objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) --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.newRectangleShape(0, 0, 50, 100)
  objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)

  objects.block3 = {}
  objects.block3.body = love.physics.newBody(world, 200, 250, "dynamic")
  objects.block3.body:setMass(200)
  objects.block3.shape = love.physics.newRectangleShape(0, 0, 50, 100)
  objects.block3.fixture = love.physics.newFixture(objects.block3.body, objects.block3.shape, 2)

  objects.block4 = {}
  objects.block4.body = love.physics.newBody(world, 200, 250, "dynamic")
  objects.block4.body:setMass(200)
  objects.block4.shape = love.physics.newRectangleShape(0, 0, 100, 50)
  objects.block4.fixture = love.physics.newFixture(objects.block4.body, objects.block4.shape, 2)
  
  --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:setY(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(), 20) -- we want 20 line segments to form the "circle"

  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()))
  love.graphics.polygon("fill", objects.block3.body:getWorldPoints(objects.block3.shape:getPoints()))
  love.graphics.polygon("fill", objects.block4.body:getWorldPoints(objects.block4.shape:getPoints()))
end



Other languages