Page 1 of 1

Simulate physics integration

Posted: Wed May 02, 2012 4:32 pm
by Roland_Yonaba
Hi,

I am actually working on a little game. I am actually working with Love 0.8.0, but my question it not really specific to this version.
In some part of my game, I need to simulate physics. Please, don't tell me to use love.physics. I just want to make it on my own. :awesome:

I wrote a custom vector class with deals with common operations (adding, substracting, multiplying, dividing vectors, dot product, etc...) and it works fine.
I also wrote a Object class, which represents objects moving under physics laws. I didn't wanted to call that Body or Rigid body, cause they just don't have all the real properties of Bodies. My Objects class just implements some basics methods (getters and setters for position, velocity, acceleration) and the main method for integration (Object:integrate)

Here is the code :

Code: Select all

function Object:integrate(world)
	local resultingAcceleration = (self:getAcceleration()+ world.gravity)
	local resultingVelocity = (acceleration*world.dt) + (self:getVelocity())
	resultingVelocity = resultingVelocity - world.damping
	self:setVelocity(resultingVelocity)
	self:setPosition(self:getPosition() + (resultingVelocity*world.dt))
end
As you can see, world is a table given as argument containing a key name dt (delta time number for updating), another key named gravity which is actually a vector representing the gravity (acting upon object's acceleration) and a last key named damping, representing a vector (and acting upon velocity).

To resolve integration, each delta-time, we compute the new acceleration, taking account the gravity. The we update velocity, taking into account the damping, then we get the position.

Well, what do you think of it ? Am I doing something wrong ?
Fact is, in my game, objects are motionless at first, then they are being given a strong impulse and they moves in a 2D plane until they stop naturally.

Now, my point is...If i want to run this with löve (any version), how can i choose values/define units to have a nice simulation ? If i want the world gravity have the real gravity value (meaning vector(0, -9.81)), how can I use dt in love.update callback to have something which doesn't moves extremely fast... which moves really lövely ? :awesome: :cool:

I hope ou get what I want to mean; sorry if my english sucks... :(

Re: Simulate physics integration

Posted: Wed May 02, 2012 5:02 pm
by Robin
No-one will be sad if you don't want to use love.physics. ;)

First, resultingVelocity = resultingVelocity * world.damping, not resultingVelocity = resultingVelocity - world.damping. Otherwise, you will see very weird things happening. Just imagine an object sitting still, and then subtracting some damping value... what will happen?
(Actually, I haven't taken dt in account here, so it will be something a bit more complicated... I think it should be resultingVelocity = resultingVelocity * world.damping ^ dt, not sure though.

Second, you use resultingAcceleration in one place and acceleration in another. Pick one and stick with it. :P

Third:
Roland_Yonaba wrote:Now, my point is...If i want to run this with löve (any version), how can i choose values/define units to have a nice simulation ? If i want the world gravity have the real gravity value (meaning vector(0, -9.81)), how can I use dt in love.update callback to have something which doesn't moves extremely fast... which moves really lövely ? :awesome: :cool:
I don't know what you mean by that. If you multiply by dt, all is well, on any computer and any version of LÖVE.

Re: Simulate physics integration

Posted: Wed May 02, 2012 6:32 pm
by Roland_Yonaba
Robin wrote: First, resultingVelocity = resultingVelocity * world.damping, not resultingVelocity = resultingVelocity - world.damping. Otherwise, you will see very weird things happening. Just imagine an object sitting still, and then subtracting some damping value... what will happen?
(Actually, I haven't taken dt in account here, so it will be something a bit more complicated... I think it should be resultingVelocity = resultingVelocity * world.damping ^ dt, not sure though.
You're definitely right.
Robin wrote: Second, you use resultingAcceleration in one place and acceleration in another. Pick one and stick with it. :P
Well, my mistake, Here the code reviewed.

Code: Select all

function Object:integrate(world)
	local resultingAcceleration = (self:getAcceleration()+ world.gravity)
	local resultingVelocity = (resultingAcceleration*world.dt) + (self:getVelocity())
	resultingVelocity = resultingVelocity * (world.damping ^ world.dt)
	self:setVelocity(resultingVelocity)
	self:setPosition(self:getPosition() + (resultingVelocity*world.dt))
end
Robin wrote: I don't know what you mean by that. If you multiply by dt, all is well, on any computer and any version of LÖVE.
About that, i'll be positing an example soon.

Re: Simulate physics integration

Posted: Wed May 02, 2012 8:51 pm
by ivan
Hi Roland! Damping in box2d work as follows:

Code: Select all

d = clamp(1 - damping * dt, 0, 1)
velocity = velocity * d
When the damping value is greater than 1 it becomes increasingly sensitive to dt.
how can i choose values/define units to have a nice simulation ? If i want the world gravity have the real gravity value (meaning vector(0, -9.81)), how can I use dt in love.update callback to have something which doesn't moves extremely fast... which moves really lövely ?
Depends on what sort of units you want to use.
If you want to use impulses or forces than you also have to take mass into account:
force = mass*acceleration
or
acceleration = force/mass
or
acceleration = force*(1/mass)

Many physics sims clamp the velocity of objects so that they don't exceed a given speed.

The way you render objects also comes into play. If you want to use meters for the positions of objects, then velocity becomes meters per second, etc. However you probably wouldn't want to render 2 objects that are 10 meters apart at 10 pixels apart (depends on the scale of your objects).

Collision resolution is another beast entirely and can get real hairy. :)

Re: Simulate physics integration

Posted: Thu May 03, 2012 1:16 pm
by Roland_Yonaba
Hi Ivan, Robin, thanks so much for the advises.

I have digged into the source code of Box2d, and I agree with the way Catto dealt with the damping.
Here is an excerpt how of velocity is integrated inside a b2Island entity:

Code: Select all

	// Integrate velocities and apply damping.
	for (int32 i = 0; i < m_bodyCount; ++i)
	{
		b2Body* b = m_bodies[i];

		if (b->GetType() != b2_dynamicBody)
		{
			continue;
		}

		// Integrate velocities.
		b->m_linearVelocity += step.dt * (gravity + b->m_invMass * b->m_force);
		b->m_angularVelocity += step.dt * b->m_invI * b->m_torque;

		// Apply damping.
		// ODE: dv/dt + c * v = 0
		// Solution: v(t) = v0 * exp(-c * t)
		// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
		// v2 = exp(-c * dt) * v1
		// Taylor expansion:
		// v2 = (1.0f - c * dt) * v1
		b->m_linearVelocity *= b2Clamp(1.0f - step.dt * b->m_linearDamping, 0.0f, 1.0f);
		b->m_angularVelocity *= b2Clamp(1.0f - step.dt * b->m_angularDamping, 0.0f, 1.0f);
	}
Well, I did try to mimic that stuff...It was kinda easy to add a method for clamping vectors:

Code: Select all

-- Clamps a vector
-- v_min and v_max are instances from Vector class,
-- Assuming Vector.__lt was already implemented
function Vector:clamp(v_min,v_max)
	if self < v_min then return v_min end
	if v_max < self then return v_max end
	return self
end
And then integration was rewritten :

Code: Select all

-- Integrate physics 
function Object:integrate(world)
	local resultingAcceleration = (self:getAcceleration()+ world.gravity)
	local resultingVelocity = (resultingAcceleration*world.dt) + (self:getVelocity())
	local d = world.dt*world.damping
	d = vector_1 - d
	d = d:clamp(vector_0,vector_1)
	resultingVelocity = resultingVelocity * d
	self:setVelocity(resultingVelocity)
	self:setPosition(self:getPosition() + (resultingVelocity*world.dt))
end
Actually it runs, with no bug...But I am not really satisfied with the result...Moving is not smooth enough, to me.

About collisions, I choosed the simple way. I resolve them by rotating the velocity vector from an angle of 90°, while reducing this vector (the x-component at alpha percent of its own value). But it ran int weird things...Sometimes it works, but some other time, the item goes back in the opposite direction...
Please take into account i am trying to simulate basic concept, just enough for my game. I am not working towards something highly realistic.

Here you are a demo, stickied below. I'l be please if someone take a deep look at the source and provide me wise advises...Thanks in advance.

Re: Simulate physics integration

Posted: Fri May 04, 2012 10:25 am
by ivan
Hi again Roland!
Just want to point that in Box2D the damping constant is just a single number not a vector.
I looked at the code briefly and should mention that 'vector1' is (1, 1) and its length is actually about 1.41421356 = sqrt(1*1+1*1).
Also, vector1 is pointing in the north-east direction.
Therefore, Vector:clamp might give you odd results when the 'd' vector is pointed in a negative direction.
I think you don't need to clamp the vector at all in the case (just the numeric result of 1 - damping * delta)

Usually, when you want to clamp vectors, you have to check their length, something like:

Code: Select all

-- limits the length of a vector without changing its direction
function Vector:truncate(length)
  local d = math.sqrt(self.x*self.x + self.y*self.y)
  if d < length or d == 0 then
    return
  end
  -- get the inverse length
  local id = 1/d * length
  -- normalize and set new length
  self.x = self.x * id
  self.y = self.y * id
end

Re: Simulate physics integration

Posted: Fri May 04, 2012 5:29 pm
by Ellohir
Roland_Yonaba wrote:About collisions, I choosed the simple way. I resolve them by rotating the velocity vector from an angle of 90°, while reducing this vector (the x-component at alpha percent of its own value).
That is not how it works. Take a look at the first case on the image. A low throw causes the ball to jump suddenly. You should calculate the hit angle and reflect it on the rebound angle, as the second case.

PS: It's a quick paint sketch, angles are not accurate :P

Re: Simulate physics integration

Posted: Mon May 07, 2012 1:37 pm
by DelishusCake
It seems like you are taking the hard way around here. Messing with velocities is actually pretty easy:

Code: Select all

--the maximum speed the object can go
local maxSpeed = 100
--the x and y velocities
local vx,vy = body:getLinearVelocity()
--Do any messing arround with the velocities here:
--[[
if love.keyboard.isDown("left") then
  vx = vx - 5
end
]]
--clamp the velocity to 'maxSpeed'
if vx > maxSpeed then vx = maxSpeed
elseif vx < -maxSpeed then vx = -maxSpeed
end
body:setLinearVelocity(vx, vy)

Not sure if that was what you were asking for, so let me know if you need help with anything else.
NOTE: you don't need dt. Box2D takes care of the framerate-independent stuff itself.

Re: Simulate physics integration

Posted: Mon May 07, 2012 2:06 pm
by Roland_Yonaba
Hi DelishusCake,

I already got my answer. But anyway, that was not exactly what I was asking for...I just need my object to move by themselves, after they receive an impulse.
So I don't need to check the input here.

Although, I do agree with the fact that sometimes, a maximum speed need to be set.Thanks for pointing that out.
DelishusCake wrote:NOTE: you don't need dt. Box2D takes care of the framerate-independent stuff itself.
hey, I'm not using Box2D...

Re: Simulate physics integration

Posted: Tue May 08, 2012 12:33 am
by DelishusCake
Sorry I couldn't help more man, but I'm glad you found the answer :) . You were using the physics module, right? Box2D is the physics engine that provides the physics for the physics module.