Difference between revisions of "Tutorial:Physics"

m (Updated colors)
m (The main.lua: Use a sane number of columns in code example)
Line 106: Line 106:
 
<source lang="lua">
 
<source lang="lua">
 
function love.load()
 
function love.load()
   love.physics.setMeter(64) --the height of a meter our worlds will be 64px
+
   -- 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
+
   love.physics.setMeter(64)
 +
  -- create a world for the bodies to exist in with horizontal gravity
 +
  -- of 0 and vertical gravity of 9.81
 +
  world = love.physics.newWorld(0, 9.81*64, true)
  
 
   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 = {}
   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)
+
   -- remember, the shape (the rectangle we create next) anchors to the
   objects.ground.shape = love.physics.newRectangleShape(650, 50) --make a rectangle with a width of 650 and a height of 50
+
  -- body from its center, so we have to move it to (650/2, 650-50/2)
   objects.ground.fixture = love.physics.newFixture(objects.ground.body, objects.ground.shape); --attach shape to body
+
   objects.ground.body = love.physics.newBody(world, 650/2, 650-50/2)
 
+
  -- make a rectangle with a width of 650 and a height of 50
   --let's create a ball
+
  objects.ground.shape = love.physics.newRectangleShape(650, 50)
 +
  -- attach shape to body
 +
   objects.ground.fixture = love.physics.newFixture(objects.ground.body,
 +
                                                  objects.ground.shape)
 +
 
 +
   -- let's create a ball
 
   objects.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
+
  -- place the body in the center of the world and make it dynamic, so
   objects.ball.shape = love.physics.newCircleShape(20) --the ball's shape has a radius of 20
+
  -- it can move around
   objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1) -- Attach fixture to body and give it a density of 1.
+
   objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "dynamic")
   objects.ball.fixture:setRestitution(0.9) --let the ball bounce
+
  -- the ball's shape has a radius of 20
 +
   objects.ball.shape = love.physics.newCircleShape(20)
 +
  -- Attach fixture to body and give it a density of 1.
 +
   objects.ball.fixture = love.physics.newFixture(objects.ball.body,
 +
                                                objects.ball.shape, 1)
 +
   objects.ball.fixture:setRestitution(0.9) -- let the ball bounce
  
   --let's create a couple blocks to play around with
+
   -- let's create a couple blocks to play around with
 
   objects.block1 = {}
 
   objects.block1 = {}
 
   objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
 
   objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
 
   objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100)
 
   objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100)
   objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) -- A higher density gives it more mass.
+
  -- A higher density gives it more mass.
 +
   objects.block1.fixture = love.physics.newFixture(objects.block1.body,
 +
                                                  objects.block1.shape, 5)
  
 
   objects.block2 = {}
 
   objects.block2 = {}
 
   objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
 
   objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
 
   objects.block2.shape = love.physics.newRectangleShape(0, 0, 100, 50)
 
   objects.block2.shape = love.physics.newRectangleShape(0, 0, 100, 50)
   objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)
+
   objects.block2.fixture = love.physics.newFixture(objects.block2.body,
 +
                                                  objects.block2.shape, 2)
  
   --initial graphics setup
+
   -- initial graphics setup
   love.graphics.setBackgroundColor(0.41, 0.53, 0.97) --set the background color to a nice blue
+
  -- set the background color to a nice blue
   love.window.setMode(650, 650) --set the window dimensions to 650 by 650
+
   love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
 +
   love.window.setMode(650, 650) -- set the window dimensions to 650 by 650
 
end
 
end
  
  
 
function love.update(dt)
 
function love.update(dt)
   world:update(dt) --this puts the world into motion
+
   world:update(dt) -- this puts the world into motion
 
+
 
   --here we are going to create some keyboard events
+
   -- 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
+
   -- press the right arrow key to push the ball to the right
 +
  if love.keyboard.isDown("right") then
 
     objects.ball.body:applyForce(400, 0)
 
     objects.ball.body:applyForce(400, 0)
   elseif love.keyboard.isDown("left") then --press the left arrow key to push the ball to the left
+
   -- press the left arrow key to push the ball to the left
 +
  elseif love.keyboard.isDown("left") then
 
     objects.ball.body:applyForce(-400, 0)
 
     objects.ball.body:applyForce(-400, 0)
   elseif love.keyboard.isDown("up") then --press the up arrow key to set the ball in the air
+
   -- press the up arrow key to set the ball in the air
 +
  elseif love.keyboard.isDown("up") then
 
     objects.ball.body:setPosition(650/2, 650/2)
 
     objects.ball.body:setPosition(650/2, 650/2)
     objects.ball.body:setLinearVelocity(0, 0) --we must set the velocity to zero to prevent a potentially large velocity generated by the change in position
+
     -- we must set the velocity to zero to prevent a potentially large
 +
    -- velocity generated by the change in position
 +
    objects.ball.body:setLinearVelocity(0, 0)
 
   end
 
   end
 
end
 
end
  
 
function love.draw()
 
function love.draw()
   love.graphics.setColor(0.28, 0.63, 0.05) -- set the drawing color to green for the ground
+
  local points
   love.graphics.polygon("fill", objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())) -- draw a "filled in" polygon using the ground's coordinates
+
 
 +
  -- set the drawing color to green for the ground
 +
   love.graphics.setColor(0.28, 0.63, 0.05)
 +
  -- draw a "filled in" polygon using the ground's coordinates
 +
   points = objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())
 +
  love.graphics.polygon("fill", points)
  
   love.graphics.setColor(0.76, 0.18, 0.05) --set the drawing color to red for the ball
+
  -- 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(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) -- set the drawing color to grey for the blocks
+
  -- set the drawing color to grey for the blocks
   love.graphics.polygon("fill", objects.block1.body:getWorldPoints(objects.block1.shape:getPoints()))
+
   love.graphics.setColor(0.20, 0.20, 0.20)
   love.graphics.polygon("fill", objects.block2.body:getWorldPoints(objects.block2.shape:getPoints()))
+
   points = objects.block1.body:getWorldPoints(objects.block1.shape:getPoints())
 +
   love.graphics.polygon("fill", points)
 +
  points = objects.block2.body:getWorldPoints(objects.block2.shape:getPoints())
 +
  love.graphics.polygon("fill", points)
 
end
 
end
 
</source>
 
</source>

Revision as of 12:16, 25 September 2019

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, shapes, and fixture 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(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.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, 1) -- Attach fixture to body and give it a density 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.shape = love.physics.newRectangleShape(0, 0, 50, 100)
  objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) -- A higher density gives it more mass.

  objects.block2 = {}
  objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
  objects.block2.shape = love.physics.newRectangleShape(0, 0, 100, 50)
  objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.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(0.41, 0.53, 0.97) --set the background color to a nice blue
  love.window.setMode(650, 650) --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 to 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:setPosition(650/2, 650/2)
    objects.ball.body:setLinearVelocity(0, 0) --we must set the velocity to zero to prevent a potentially large velocity generated by the change in position
  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(0.28, 0.63, 0.05) -- 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(0.76, 0.18, 0.05) --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(0.20, 0.20, 0.20) -- 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()))
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 mostly finished product.


The main.lua

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

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

  -- let's create the ground
  objects.ground = {}
  -- 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, 650-50/2)
  -- make a rectangle with a width of 650 and a height of 50
  objects.ground.shape = love.physics.newRectangleShape(650, 50)
  -- attach shape to body
  objects.ground.fixture = love.physics.newFixture(objects.ground.body,
                                                   objects.ground.shape)

  -- let's create a ball
  objects.ball = {}
  -- place the body in the center of the world and make it dynamic, so
  -- it can move around
  objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "dynamic")
  -- the ball's shape has a radius of 20
  objects.ball.shape = love.physics.newCircleShape(20)
  -- Attach fixture to body and give it a density of 1.
  objects.ball.fixture = love.physics.newFixture(objects.ball.body,
                                                 objects.ball.shape, 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.shape = love.physics.newRectangleShape(0, 0, 50, 100)
  -- A higher density gives it more mass.
  objects.block1.fixture = love.physics.newFixture(objects.block1.body,
                                                   objects.block1.shape, 5)

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

  -- initial graphics setup
  -- set the background color to a nice blue
  love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
  love.window.setMode(650, 650) -- 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
  -- press the right arrow key to push the ball to the right
  if love.keyboard.isDown("right") then
    objects.ball.body:applyForce(400, 0)
  -- press the left arrow key to push the ball to the left
  elseif love.keyboard.isDown("left") then
    objects.ball.body:applyForce(-400, 0)
  -- press the up arrow key to set the ball in the air
  elseif love.keyboard.isDown("up") then
    objects.ball.body:setPosition(650/2, 650/2)
    -- we must set the velocity to zero to prevent a potentially large
    -- velocity generated by the change in position
    objects.ball.body:setLinearVelocity(0, 0)
  end
end

function love.draw()
  local points

  -- set the drawing color to green for the ground
  love.graphics.setColor(0.28, 0.63, 0.05)
  -- draw a "filled in" polygon using the ground's coordinates
  points = objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())
  love.graphics.polygon("fill", points)

  -- set the drawing color to red for the ball
  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())

  -- set the drawing color to grey for the blocks
  love.graphics.setColor(0.20, 0.20, 0.20)
  points = objects.block1.body:getWorldPoints(objects.block1.shape:getPoints())
  love.graphics.polygon("fill", points)
  points = objects.block2.body:getWorldPoints(objects.block2.shape:getPoints())
  love.graphics.polygon("fill", points)
end



Other languages