I have a mad scheme for making an object move using applyForce and momentum. )Arrgh, results suggest that we need to file a bug report.)
We have established, more or less, that when we use the
applyForce function on an entity, the force vector provided is applied for an interval equal to one DeltaTime, one draw cycle. There seem to be exceptions to this. I have seen two: one case is that sometimes I see a force of zero applied, and very rarely, I’ve seen double the expected amount.
I plan to ignore these variances, and proceed as if
applyForce applies the force for a period of time DeltaTime.
In real world physics, and fake-world physics as well, objects have momentum. Mathematically,
momentum = mass * velocity
This is often written, for reasons only physicists know, as:
p = m*v
My own theory is:
- Physicist 1
- What shall we call momentum? How about “m”?
- Physicist 2
- Can’t use “m”, that’s mass. How about “n”?
- Physicist 1
- Used in counting one to n. Maybe “o”?
- Physicist 2
- Looks too much like zero. Let’s use “p”.
- Physicist 1
- “p” it is. (They clink glasses and drink.)
Note that momentum is a vector quantity. The momentum of something of mass 2 moving straight up at speed 1 is
<0,2,0>, while if it is moving to the right, momentum is
It turns out, of course, that the momentum of something of mass one, moving at speed two, to the left, is
<-2,0,0>. If those two things collide, the two momentums (momenta?) will cancel out and both objects will stop. The light object can stop the heavy one if it is going fast enough. If it were going even faster, the light object would push the heavy one back and keep on moving, although slowed down.
We saw that in the Michigan-Ohio game as Michigan’s runners pushed through or dragged two or three would-be blockers and tacklers. Go Blue.
Now it turns out, through a bit of math that we won’t explore here, that
impulse = change in momentum
F*t = m*Δv
applyForce is an impulse, with time t = DeltaTime (we believe). So it changes the momentum of the object to which it is applied, and we have seen that it mostly changes it by DeltaTime times the force applied. (Our sample ball had mass one, so that we could easily see these figures.)
Netting this all out, suppose we have an object of mass m, moving with vector velocity
v. And suppose we want it to be moving with a new vector velocity,
w. It turns out that if we take the new vector
w - v, and whack the object hard enough with a force in that direction, it will, when all is said and done, be moving with velocity
How hard is hard enough? If I’m not mistaken–which is always a possibility–we need to scale the vector up by the mass, and we need to adjust for the time the force will be applied.
I think we need to hit the object with
force = m*(w-v)/DeltaTime
Let’s try to make that concrete with a Codea program.
I’ll spare you the long story of what happened. I’ve spent hours playing with
applyForce and asking questions about it on the forum. I am pretty confident in the program I’ll show below, and I think it shows the following:
- Usually, the amount of force required to reverse the object is 0.5 times the object’s linear velocity, divided by DeltaTime. I believe this is telling me that the physics cycle time is 1/60th of a second, not the draw cycle time, which varies. I think physics time needs not to vary lest things change speed visibly on the screen.
- Sometimes, *on both my fast iPads, every 7 or 8 seconds,
applyForce, called inside
draw, has no effect, and for a while thereafter, it has no effect. Then, 7 or 8 seconds later, it again starts to work.
drawtakes effect, subject to the problem #2 above. Generally, using
scene:updatedoes not take effect, but sometimes it does.
Toggling the provided parameter switches the program from applying force in
draw to applying it inside the
update method of the
Reporter, that is, inside
Here’s the program that I plan to submit as a bug report.
-- CoCraTu-008 function setup() scene = craft.scene() depth = 0 scene.physics.gravity = vec3(0,0,0) createBall() scene.camera:add(OrbitViewer, vec3(0,0,0), 60, 0, 1000) Delay = 2 BallTime = 0 Whacks = 0 parameter.boolean("ApplyInScene", true) end function update(dt) scene.debug:line(vec3(-10,depth-1,0), vec3(10,depth-1,0), color(255)) scene:update(dt) end function draw() if not ApplyInScene then reverse("in draw") end update(DeltaTime) scene:draw() reporter:draw() end function reverse(message) BallTime = BallTime + DeltaTime if BallTime >= Delay then local oldv = BallBody.linearVelocity local newv = - oldv -- turn him around local mass = BallBodyMass local force = mass*(newv-oldv)*60 -- guess at physics time = 1/60 BallBody.sleepingAllowed = false BallBody.awake = true BallBody:applyForce(force) Whacks = Whacks + 1 print(message.. " whack ", Whacks, force) BallTime = 0 end end function createBall() Ball = scene:entity() BallBody = Ball:add(craft.rigidbody, DYNAMIC, 1) -- mass 1 BallBodyMass = 1 BallBody.linearVelocity = vec3(0,2,0) BallBody.sleepingAllowed = false Ball.position = vec3(0,depth,0) Ball:add(craft.shape.sphere, 1) Ball.model = craft.model.icosphere(1) Ball.material = craft.material(asset.builtin.Materials.Standard) Ball.material.diffuse = color(255,0,0) reporter = Ball:add(Reporter) end Reporter = class() function Reporter:init(entity) self.entity = entity self.lastDrawTime = ElapsedTime self.lastFixTime = ElapsedTime self.deltaDrawTime = 0 self.deltaFixTime = 0 self.applyDuration = 0 self.maxDuration = 0 end function Reporter:update() if ApplyInScene then reverse("in scene") end self.deltaDrawTime = ElapsedTime - self.lastDrawTime self.lastDrawTime = ElapsedTime if self.deltaDrawTime > self.maxDuration then self.maxDuration = self.deltaDrawTime end end function Reporter:draw() pushStyle() textAlign(LEFT) textMode(LEFT) fill(255) text("Draw Time "..self.deltaDrawTime, 400, 100) text("Vel "..BallBody.linearVelocity.y, 400, 80) text("Duration "..self.applyDuration, 400, 60) text("Max Duration "..self.maxDuration, 400, 40) if BallBody.awake then text("Awake", 400,20) else text("Asleep", 400, 20) end popStyle() end
I’ll add the comments 1,2,3 above as well.
Here’s a movie showing what happens.
So, Therefore … What?
I guess that for now, further demonstration of how to work with momentum in Codea Craft is off the table. We’ll probably move on to the voxel capability in upcoming articles.
When Simeon and John show me the error of my ways, or fix the problem, we might return to this topic. I think there’s some interesting stuff we could do with applying force and torque in a game context.
But for now, the bear has bitten us.