Predicting Trajectory - Zero Gravity with linearDamping on Physics Body

I am trying to figure out a way to modify the code from this awesome tutorial to predict Trajectory within a zero gravity environment. (Code from Brent Sorrentino below)

http://www.coronalabs.com/blog/2013/04/09/physics-radial-gravity-and-predicting-trajectory/

Full code here:

https://www.dropbox.com/sh/8km5lze9gg4ey6z/mPVzcZwVUp/PredictingTrajectory/PredictingTrajectory.zip

My key problem is determining how to display the object slowing down during the “prediction” phase of the code:

If you run this code is successfully follows the correct path.

If you un-comment out the linearDamping=.3 line then the physics object will slow down.  Any suggestions on how I can modify the prediction code to account for linearDamping?

-- Physics Demo: Predicting Trajectory | Version: 1.0 -- Sample code is MIT licensed, see http://www.coronalabs.com/links/code/license -- Copyright (C) 2013 Corona Labs Inc. All Rights Reserved. -- SPECIAL THANKS to Matt Webster (a.k.a. "HoraceBury") for the trajectory calculations! local physics = require("physics") ; physics.start() ; physics.setGravity( 0,0) ; physics.setDrawMode( "normal" ) display.setStatusBar( display.HiddenStatusBar ) --set up some references and other variables local ox, oy = math.abs(display.screenOriginX), math.abs(display.screenOriginY) local cw, ch = display.contentWidth, display.contentHeight --set up terrain and background local wallL = display.newRect( -ox, -oy, 40, ch+oy+oy ) physics.addBody(wallL, "static", { bounce=0.4, friction=1.0 } ) local wallR = display.newRect( cw-40+ox, -oy, 40, ch+oy+oy ) physics.addBody(wallR, "static", { bounce=0.4, friction=1.0 } ) local wallB = display.newRect( -ox, ch-40+oy, cw+ox+ox, 40 ) physics.addBody(wallB, "static", { bounce=0.2, friction=1.0 } ) local wallT = display.newRect( -ox, -oy, cw+ox+ox, 40 ) physics.addBody(wallT, "static", { bounce=0.2, friction=1.0} ) local msg = display.newText( "Touch, drag, and release to launch projectiles", 0, 0, "ContenuBook-Display", 40 ) msg:setTextColor(255,255,255,220) ; msg.x, msg.y = cw/2,110 local prediction = display.newGroup() ; prediction.alpha = 0.2 local line local function getTrajectoryPoint( startingPosition, startingVelocity, n ) --velocity and gravity are given per second but we want time step values here local t = 1/display.fps --seconds per time step at 60fps local stepVelocity = { x=t\*startingVelocity.x, y=t\*startingVelocity.y } --b2Vec2 stepVelocity = t \* startingVelocity local stepGravity = { x=t\*-.5, y=t\*0 } -- Applying Linear Inpulse return { x = startingPosition.x + n \* stepVelocity.x + 0.5 \* (n\*n+n) \* stepGravity.x, y = startingPosition.y + n \* stepVelocity.y + 0.5 \* (n\*n+n) \* stepGravity.y } --startingPosition + n \* stepVelocity + 0.25 \* (n\*n+n) \* stepGravity end local function updatePrediction( event ) display.remove( prediction ) --remove dot group prediction = display.newGroup() ; prediction.alpha = 0.2 --now recreate it local startingVelocity = { x=event.x-event.xStart, y=event.y-event.yStart } for i = 1,360 do --for (int i = 0; i \< 180; i++) local s = { x=event.xStart, y=event.yStart } local trajectoryPosition = getTrajectoryPoint( s, startingVelocity, i ) -- b2Vec2 trajectoryPosition = getTrajectoryPoint( startingPosition, startingVelocity, i ) local circ = display.newCircle( prediction, trajectoryPosition.x, trajectoryPosition.y, 5 ) end end local function moveStone() proj:applyLinearImpulse(-.046,0,proj.x, proj.y ) -- this duplicated in predicted trajectory above end function fireProj( event ) if ( event.xStart \< -ox+44 or event.xStart \> display.contentWidth+ox-44 or event.yStart \< -oy+44 or event.yStart \> display.contentHeight+oy-44 ) then display.remove( prediction ) return end proj = display.newImageRect( "object.png", 64, 64 ) physics.addBody( proj, { bounce=0.2, density=4.0, friction=5, radius=14 } ) proj.x, proj.y = event.xStart, event.yStart local vx, vy = event.x-event.xStart, event.y-event.yStart proj:setLinearVelocity( vx,vy ) -- proj.linearDamping = .3 Runtime:addEventListener("enterFrame",moveStone); end local function screenTouch( event ) local eventX, eventY = event.x, event.y if ( event.phase == "began" ) then line = display.newLine( eventX, eventY, eventX, eventY ) line.width = 4 ; line.alpha = 0.6 elseif ( event.phase == "moved" ) then display.remove( line ) line = display.newLine( event.xStart, event.yStart, eventX, eventY ) line.width = 4 ; line.alpha = 0.6 updatePrediction( event ) else display.remove( line ) updatePrediction( event ) fireProj( event ) end return true end Runtime:addEventListener( "touch", screenTouch )

Hi Byron,

Is the idea to give the object an “air drag” kind of effect? I imagine it’s possible, but it’ll require some very advanced mathematic calculations. You might want to check out the “More advanced drag models” section here:

http://en.wikipedia.org/wiki/External_ballistics#Drag_resistance_modeling_and_measuring

Brent

P.S. - to give credit where credit is due, while I “enhanced” this trajectory demo a bit, the underlying code is credit of Matt Webster, a.k.a. “HoraceBury”. You’ll see him around the forums, often chiming in on physics-related topics. You can thank him for the Corona-fication of these known formulas which brought about this trajectory prediction code. :slight_smile:

Thanks Brent…  

I am actually building a curling app…where heavy rocks roll down ice.  I want the player to be able to see the trajectory of their shot before they take it… 

What I really need is to calculate the trajectory from the destination backwards…  so technically I need to determine the velocity, angle and apply a linear pulse on the stone (representing the curl of the stone)…  

I’ve got it figured out with a physics object…but I’m very close to abandoning the idea of prediction trajectory of the stones.

B

A curling app… that’s going to be tricky indeed (for the trajectories). Since this isn’t going to be gravity-based, can you factor in other directions of “gravity” into the formula to simulate a subtle drag of the stone? For example, a tiny force applied in the opposite direction, not from “above” as gravity would do… just food for thought.

I actually use linearDamping on the stone to simulate the friction of the ice… it works perfectly.

Like I said… the physics to take the shot, curl and stop on the ice works slick.

My trouble is only with the non-physics code to predict what the physics code will do…I can’t get them to match.

One idea I am toying with is to record the trajectory for every possible velocity of the physics object and store it in a table.

As the player selects the weight and angle of the shot I will simply loop through the table and plot the trajectory, store it in a display object and then rotate the display object to match the angle…

Any better ideas?

Thanks in advance… you don’t know how much I appreciate the help.

B

If you look at my code (your code)… 

I changed the following lines of code:

physics.setGravity( 0,0) \<- removed gravity local stepGravity = { x=t\*-.5, y=t\*0 } \<- added -.5 gravity representing the stone curling &nbsp;

This function curls the physics object the same as above when it is released.

local function moveStone() &nbsp; &nbsp; proj:applyLinearImpulse(-.046,0,proj.x, proj.y ) end Runtime:addEventListener("enterFrame",moveStone);

Everything above works perfectly… the trajectory matches… the only problem is that I have to stop the stone from moving over the ice:

proj.linearDamping = .3

When I add this the trajectory no longer matches…   any suggestions?

Do you have any idea how linearDamping is calculated?  

I could reverse engineer the damping effect on the predicted trajectory?

Well, at the basic level, it’s a force in the opposite direction based on the damping coefficient, in meters per second. But reverse-translating that from the Box2D world could be tricky…

Did you search around on Stack Overflow? There are usually some interesting tidbits and suggestions on there, even if they’re aimed at another language or development platform… and if you find one written in Javascript or Obj-C, you might be able to to convert it to Lua (depending on your familiarity with those languages).

I think I found a basic solution… it’s not perfect, but close enough for my purposes.

proj.linearDamping=.3

I simply multiplied  n * stepVelocity.x by .5 

return { x = (startingPosition.x) + (n \* stepVelocity.x \* .5) + (0.5 \* (n\*n+n) \* stepGravity.x), y = (startingPosition.y) + (n \* stepVelocity.y \* .5) + (0.5 \* (n\*n+n) \* stepGravity.y) }

If anyone know the formula for calculating linearDamping, please post it here…

Thanks in advance…

B

Here is a version that I am looking at from this site:

http://www.cocos2d-iphone.org/forum/topic/85982

//trajectory 'point at timestep n' formula taking linear damping into account b2Vec2 getTrajectoryPoint( b2Vec2 startingPosition, b2Vec2 startingVelocity, float n /\*time steps\*/, float linearDamping, float dt ) { b2Vec2 stepVelocity = dt \* startingVelocity; // m/s b2Vec2 stepGravity = dt \* dt \* m\_world-\>GetGravity(); // m/s/s //h4 = h + v( d + d^2 + d^3 + d^4) // + a(4d + 3d^2 + 2d^3 + d^4) float d = b2Clamp(1.0f - dt \* linearDamping, 0.0f, 1.0f); float vd = 0; float ad = 0; for (int i = 0; i \< n; i++) { float p = pow(d,i+1); vd += p; ad += (n-i) \* p; } return startingPosition + vd \* stepVelocity + ad \* stepGravity; }

Here is the solution…  figured it out late last night

Predicted Trajectory with linearDamping

local function getTrajectoryPoint (startingPosition, startingVelocity, n, linearDamping, dt) function clamp( val, low, high ) if (val \< low) then return low end if (val \> high) then return high end return val end stepVelocity = { x=dt\*startingVelocity.x, y=dt\*startingVelocity.y } local stepGravity = { x=dt\*0, y=dt\*0 } d = clamp(1.0 - dt \* linearDamping, 0.0, 1.0); vd = 0; ad = 0; for i = 0,n do p = math.pow(d,i+1); vd = vd + p; ad = ad + ((n-i) \* p); end print(vd) return { x = startingPosition.x + vd \* stepVelocity.x + ad \* stepGravity.x, y = startingPosition.y + vd \* stepVelocity.y + ad \* stepGravity.y } end

Awesome, great work! I’m going to test it out later today. This is a useful addition to the demo.

Brent

Thanks Brent!

Now I have to figure out how to predict the applyLinearImpulse that provides the “curl” effect.

I am sure there is a simple solution, but I’ve racked my brain too long on this already. :slight_smile:

-Byron Fillmore

Hi Byron,

Is the idea to give the object an “air drag” kind of effect? I imagine it’s possible, but it’ll require some very advanced mathematic calculations. You might want to check out the “More advanced drag models” section here:

http://en.wikipedia.org/wiki/External_ballistics#Drag_resistance_modeling_and_measuring

Brent

P.S. - to give credit where credit is due, while I “enhanced” this trajectory demo a bit, the underlying code is credit of Matt Webster, a.k.a. “HoraceBury”. You’ll see him around the forums, often chiming in on physics-related topics. You can thank him for the Corona-fication of these known formulas which brought about this trajectory prediction code. :slight_smile:

Thanks Brent…  

I am actually building a curling app…where heavy rocks roll down ice.  I want the player to be able to see the trajectory of their shot before they take it… 

What I really need is to calculate the trajectory from the destination backwards…  so technically I need to determine the velocity, angle and apply a linear pulse on the stone (representing the curl of the stone)…  

I’ve got it figured out with a physics object…but I’m very close to abandoning the idea of prediction trajectory of the stones.

B

A curling app… that’s going to be tricky indeed (for the trajectories). Since this isn’t going to be gravity-based, can you factor in other directions of “gravity” into the formula to simulate a subtle drag of the stone? For example, a tiny force applied in the opposite direction, not from “above” as gravity would do… just food for thought.

I actually use linearDamping on the stone to simulate the friction of the ice… it works perfectly.

Like I said… the physics to take the shot, curl and stop on the ice works slick.

My trouble is only with the non-physics code to predict what the physics code will do…I can’t get them to match.

One idea I am toying with is to record the trajectory for every possible velocity of the physics object and store it in a table.

As the player selects the weight and angle of the shot I will simply loop through the table and plot the trajectory, store it in a display object and then rotate the display object to match the angle…

Any better ideas?

Thanks in advance… you don’t know how much I appreciate the help.

B

If you look at my code (your code)… 

I changed the following lines of code:

physics.setGravity( 0,0) \<- removed gravity local stepGravity = { x=t\*-.5, y=t\*0 } \<- added -.5 gravity representing the stone curling &nbsp;

This function curls the physics object the same as above when it is released.

local function moveStone() &nbsp; &nbsp; proj:applyLinearImpulse(-.046,0,proj.x, proj.y ) end Runtime:addEventListener("enterFrame",moveStone);

Everything above works perfectly… the trajectory matches… the only problem is that I have to stop the stone from moving over the ice:

proj.linearDamping = .3

When I add this the trajectory no longer matches…   any suggestions?

Do you have any idea how linearDamping is calculated?  

I could reverse engineer the damping effect on the predicted trajectory?