Page 1 of 1

[SOLVED] Angry Birds Physics

Posted: Tue Jan 06, 2015 8:04 am
by yegorf1
Hi!
I tried to calculate impulse for body in order to body flew through the mouse coordinates, but my calculations were wrong. After many attempts I tried this:

Code: Select all

local x = self.target.x - self.position.x
local y = self.target.y - self.position.y

res.body:applyLinearImpulse(x * 10 ^ 10, y * 10 ^ 10)
I thought that error will be minimal, but it didn't work too. Body flew in, about, 30 pixels from target.
What am I doing wrong?

UPD:
When I changed love.physics.setMeter(1) to love.physics.setMeter(4) it worked better. Why?

Re: Angry Birds Physics

Posted: Tue Jan 06, 2015 9:01 am
by nfey
How are you calculating self.target and self.position? Are they correct?
Why are you using the distance to calculate the amount of impulse to be applied?
What's the mass of the object you're trying to push? (read the wiki entry for :applyLinearImpulse)

Also, it would be easier to help out if you upload the .love file.

Re: Angry Birds Physics

Posted: Tue Jan 06, 2015 9:21 am
by yegorf1
I solved this. My love file is really big and there are a lot of other stuff.
Solution is

Code: Select all

function Catapult:pushRock()
    local pos = getDrawPosition(self)
    --rock spawn position
    pos.x = pos.x + 3
    pos.y = pos.y - 3
    
    --distance on both axises
    local x = self.target.x - pos.x
    local y = self.target.y - pos.y
    
    local _, g = world:getGravity() --world:getGravity() returns gravity.x and gravity.y; gravity.x = 0
    
    local t = 6                    --time. Can be any, except zero
    local vx = x / t                --velocity on X
    local vy = y / t - g * t / 2    --velocity on Y
    
    Rock:new(pos.x, pos.y, vx + math.random(4) - 2, vy - math.random(4) + 2)
end

Re: Angry Birds Physics

Posted: Tue Jan 06, 2015 9:36 am
by ivan
In Box2D, the trajectory of a moving body is affected by
1. gravity (including the gravity scale of the body)
2. linear damping
For starters, set the gravity to (0, 0) and the linear damping to 0 and see if it works.
Also, check out the following post.

Code: Select all

-- STEP ONE: figure out the velocity required to reach the target
-- vector to target:
local dx = self.target.x - self.position.x
local dy = self.target.y - self.position.y
-- distance to target:
local d = math.sqrt(dx*dx + dy*dy)
assert(d > 0, "target == position")
-- normalized vector to target:
local nx = dx/d
local ny = dy/d
-- velocity required to reach the target:
local vx = nx*desiredLV
local vy = ny*desiredLV
-- minimum time to reach the target:
local dt = d/desiredLV

-- STEP TWO: factor in gravity and linear damping
-- adjust the velocity to compensate for the effects of gravity and linear damping:
-- v = v - g
vx, vy = steering.compG(vx, vy, gx, gy, dt) -- ignore if "gx" and "gy" are 0
vx, vy = steering.compLD(vx, vy, damping, maxLV, dt) -- ignore if "damping" is 0 

-- STEP THREE: find the force based on the velocity: F = m*a, a = (fv - iv)/dt, dt = d/desiredLV
-- initial velocity, in this case 0, 0:
local ivx, ivy = 0, 0 -- body:GetLinearVelocity()
-- final velocity:
local fvx, fvy = vx, vy
-- force required to reach the final velocity:
local fx, fy = steering.force(ivx, ivy, fvx, fvy, mass, dt)
where:

Code: Select all

gx, gy: world gravity
damping: linear damping of the body
mass: mass of the body
maxLV: maximum linear velocity (Box2D constant)
desiredLV: desired linear velocity (0 < desired LV <= maxLV)
dt: time interval (> 0) in this case: dt = d/desiredLV
Once you know the force required to direct the body to a given target then you have to convert that to an impulse (from the Box2D forums):
p = F * s (where p is the change of impulse, F a force and s the time, here dt). That means applyImpulse(10) and 10 seconds applyForce(1) will result in the same velocity for the body
These calculations work assuming that the body is not attached to a joint and doesn't collides with other bodies.