Simulate physics integration

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Simulate physics integration

Post 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... :(
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Simulate physics integration

Post 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.
Help us help you: attach a .love.
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Simulate physics integration

Post 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.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Simulate physics integration

Post 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. :)
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Simulate physics integration

Post 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.
Attachments
Test.love
(13.17 KiB) Downloaded 115 times
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Simulate physics integration

Post 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
User avatar
Ellohir
Party member
Posts: 235
Joined: Sat Oct 22, 2011 11:12 pm

Re: Simulate physics integration

Post 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
Attachments
Dibujo.PNG
Dibujo.PNG (4.95 KiB) Viewed 3785 times
DelishusCake
Prole
Posts: 8
Joined: Sat Mar 10, 2012 8:31 pm

Re: Simulate physics integration

Post 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.
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Simulate physics integration

Post 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...
DelishusCake
Prole
Posts: 8
Joined: Sat Mar 10, 2012 8:31 pm

Re: Simulate physics integration

Post 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.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 232 guests