Gravity (quick noob question)

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
gibberwocky
Prole
Posts: 3
Joined: Sat Dec 06, 2014 3:14 pm

Gravity (quick noob question)

Post by gibberwocky »

I'm entirely new to lua and using a physics API, but have prior experience with a variety of languages. I thought I'd give writing a simple game a bash to get back into the swing of things after a long break.

I would like to fix the centre of gravity to the centre of a circle. After which, the plan is to attach a series of objects to the outside of the circle and rotate it to give the impression of a moving cityscape. If anyone can spare a few minutes to point me in the right direction it would be appreciated!

Cheers
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Gravity (quick noob question)

Post by ivan »

Gravity in Box2d (Love2d's physics module) is just a vector. If you want to have non-uniform gravity you have to apply forces to all dynamic bodies in your simulation. Basically you have to iterate all bodies and apply a force to each one in direction of your circle center.
If you have A LOT of objects you may want to create them dynamically, rather than creating the entire "cityscape" and then rotating it.
gibberwocky
Prole
Posts: 3
Joined: Sat Dec 06, 2014 3:14 pm

Re: Gravity (quick noob question)

Post by gibberwocky »

Thanks, that makes sense.

Before looking at the dynamic option, I'd still like to resolve the physics method. I've taken one of the tutorial scripts as a start and edited it to attempt to apply force to some blocks, however they all fly away. Can you spot where I'm going wrong, or what I've missed?

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, 4*love.physics.getMeter(), true)
  width, height = love.graphics.getDimensions()
  
  
  objects = {} -- table to hold all our physical objects
 
  -- create ground sphere
  objects.ground = {}
  objects.ground.body = love.physics.newBody(world, width/2, height/2)
  objects.ground.shape = love.physics.newCircleShape(width/4) --make globe
  objects.ground.fixture = love.physics.newFixture(objects.ground.body, objects.ground.shape) --attach shape to body
  
  -- create some buildings
  num_buildings = 7
  objects.building = {}
  for i=1, num_buildings do
    gX, gY = objects.ground.body:getX(), objects.ground.body:getY()
    gX = gX - (50 * num_buildings) + (100*i) - 50
    gY = gY /2
    objects.building[i] = {}
    objects.building[i].body = love.physics.newBody(world, gX, gY, "dynamic")
    objects.building[i].shape = love.physics.newRectangleShape(0,0,width*0.02,width*0.05)
    objects.building[i].fixture = love.physics.newFixture(objects.building[i].body, objects.building[i].shape,10)
  end
  
    --initial graphics setup
  love.graphics.setBackgroundColor(0, 0, 0) 
  love.window.setMode(width, height) 
  
end


function love.update(dt)
  world:update(dt) --this puts the world into motion
  
  --apply force
  gX, gY = objects.ground.body:getX(), objects.ground.body:getY()
  for i=1, num_buildings do
    objects.building[i].body:applyForce(gX, gY)
  end
    
end


function love.draw()
  -- draw the centre sphere
  love.graphics.setColor(77, 0, 75, 255) 
  love.graphics.circle("fill", objects.ground.body:getX(), objects.ground.body:getY(), objects.ground.shape:getRadius())
  
  -- draw buildings
  love.graphics.setColor(50, 50, 50)
  for i=1, num_buildings do
    love.graphics.polygon("fill", objects.building[i].body:getWorldPoints(objects.building[i].shape:getPoints()))
  end   

  -- add fps to corner
  love.graphics.setColor(255,255,100,200)
  love.graphics.print(love.timer.getFPS(), 10, 10)

  -- add marker for values used in applying force
  love.graphics.print("X",objects.ground.body:getX(),objects.ground.body:getY())

end
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Gravity (quick noob question)

Post by ivan »

I would suggest something like:

Code: Select all

  local building_width = math.pi*2*ground_radius/num_buildings -- circumference/num_buildings
  for i=1, num_buildings do
    local i2 = i/num_buldings -- i in range 0 to 1
    local a = i2*math.pi*2 -- angle in radians
    local building_height = math.random(5, 20) -- random value
    local x = math.cos(a)*(ground_radius + building_height/2)
    local y = math.sin(a)*(ground_radius + building_height/2)
    -- create a body at position "x", "y" with a rotation of "a" radians
    -- create a box fixture with size "building_width" by "building_height"
gibberwocky
Prole
Posts: 3
Joined: Sat Dec 06, 2014 3:14 pm

Re: Gravity (quick noob question)

Post by gibberwocky »

I've adapted that for building placement:

Code: Select all

  
  local building_width = (( math.pi*2*objects.ground.shape:getRadius() ) / num_buildings)-- circumference/num_buildings
  for i=1, num_buildings do
    local i2 = i/num_buildings -- i in range 0 to 1
    local a = i2*math.pi*2 -- angle in radians
    local building_height = math.random(10, 50) -- random value
    local x = objects.ground.body:getX() + math.cos(a)*(objects.ground.shape:getRadius() + building_height/2)
    local y = objects.ground.body:getY() + math.sin(a)*(objects.ground.shape:getRadius() + building_height/2)
      objects.building[i] = {}
      objects.building[i].body = love.physics.newBody(world, x, y, "dynamic")
      objects.building[i].body:setAngle(a)
      objects.building[i].shape = love.physics.newRectangleShape(0,0,building_width,building_height)
      objects.building[i].fixture = love.physics.newFixture(objects.building[i].body, objects.building[i].shape,10)
   end
All of the blocks still slip off of the sphere unless I change them from 'dynamic' to 'static' or 'kinematic'. Applying force to the dynamic objects towards the centre of the sphere, or any other [x,y] position, does not counter the gravity.



*EDIT

I've solved this using a static sphere and dynamic blocks by using distance joints and rotations instead of applying force:

Code: Select all

  local building_width = (( math.pi*2*objects.ground.shape:getRadius() ) / num_buildings)-- circumference/num_buildings
  for i=1, num_buildings do
    local i2 = i/num_buildings -- i in range 0 to 1
    local a = i2*math.pi*2 -- angle in radians
    local building_height = math.random(50, 100) -- random value
    local x = objects.ground.body:getX() + math.cos(a)*(objects.ground.shape:getRadius() + building_height/2)
    local y = objects.ground.body:getY() + math.sin(a)*(objects.ground.shape:getRadius() + building_height/2)
      objects.building[i] = {}
      objects.building[i].body = love.physics.newBody(world, x, y, "dynamic")
      objects.building[i].body:setAngle(a)
      objects.building[i].shape = love.physics.newRectangleShape(0,0,building_width,building_height)
      objects.building[i].fixture = love.physics.newFixture(objects.building[i].body, objects.building[i].shape,10)
      objects.building[i].joint = love.physics.newDistanceJoint( objects.ground.body, objects.building[i].body, x, y, x, y )
   end

Code: Select all

  rot = -0.0001
  objects.ground.body:setAngle(objects.ground.body:getAngle()+rot)
  for i=1, num_buildings do
    objects.building[i].body:setAngle(objects.building[i].body:getAngle()+rot)
  end
If there is a better way please keep me posted!
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Gravity (quick noob question)

Post by ivan »

gibberwocky wrote:All of the blocks still slip off of the sphere unless I change them from 'dynamic' to 'static' or 'kinematic'. Applying force to the dynamic objects towards the centre of the sphere, or any other [x,y] position, does not counter the gravity.
Make sure your global gravity is zero: "world:setGravity(0, 0)"
Static objects are basically immovable which is one way to go, in that case you can have 1 static body with the "buildings" represented as fixtures on it.
If you want your buildings to be dynamic (so you can knock them over) then it gets a little more complicated.
In particular the base of the buildings (in your case) is flat while the "ground" object is circular: imagine balancing a rectangle top of a circle.
I suppose it might work better if each building is represented as two triangle fixtures so that they look like 'chairs':

Code: Select all

  _____
 | /  \ |
 |/    \|
So ya, it depends on the effect that you are going for. :)
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests