Page 1 of 1

[SOLVED] Continual torque changes body angle beyond expected range

Posted: Thu Jul 02, 2020 12:54 am
by lostboii
I am using love.physics:applyTorque to rotate a body towards the mouse location. I've tried a few different approaches, and while this one is complex its worth noting that this seems to happen even in much more minimal setups. I based this code almost 1:1 on this post: https://stackoverflow.com/questions/261 ... ng-torques

The problem with this code and a far simpler implementation whereby torque was applied at game launch and continued indefinitely, I get the same result: body:getAngle() will count down (which I didn't expect at all) or up from zero infinitely based on the direction of the torque. For example, after a full rotation from angle 0, I expected it to return to 0 but it continues to count in the same direction forever, unless you reverse the torque at which point it counts the other way. I confirmed this by printing the angle to the screen and observing applied torque.

I may be misunderstanding what getAngle() is even supposed to return, because my understanding of radians is that they should never be negative in this context, and should only be between 0-6.284[[...] but I think I'm more likely not understanding how applyTorque is impacting the body's angle and why. This is the very first time I've used either getAngle() or applyTorque(), prior to this I always just pointed my sprite directly at the mouse but I wanted to incorporate physics instead.

The reason this is problematic to my program is that I determine the sprite based on the body's angle by checking if the angle is within a range, but as soon as the body makes a full positive rotation or any negative rotation from 0, that logic stops responding as I never expect the angle to be more than 2*π

Code: Select all

function updateTorque()
  local twoPi = 2.0 * math.pi -- small optimisation 

  -- returns -1, 1 or 0 depending on whether x>0, x<0 or x=0
  function _sign(x)
    return x>0 and 1 or x<0 and -1 or 0
  end

  -- transforms any angle so it is on the 0-2Pi range
  local _normalizeAngle = function(angle)
    angle = angle % twoPi
    return (angle < 0 and (angle + twoPi) or angle)
  end

  local tx, ty = cam:mousePosition()
  local x, y = player.body:getPosition()
  local angle = player.body:getAngle()
  local maxTorque = player.maxTorque
  local inertia = player.body:getInertia()
  local w = player.body:getAngularVelocity()

  local targetAngle = math.atan2(ty-y,tx-x)

  -- distance I have to cover
  local differenceAngle = _normalizeAngle(targetAngle - angle)

  -- distance it will take me to stop
  local brakingAngle = _normalizeAngle(_sign(w)*2.0*w*w*inertia/maxTorque)

  local torque = maxTorque

  -- two of these 3 conditions must be true
  local a,b,c = differenceAngle > math.pi, brakingAngle > differenceAngle, w > 0
  if( (a and b) or (a and c) or (b and c) ) then
    torque = -torque
  end

  player.body:applyTorque(torque)
end
My sprite logic which swaps the sprite depending on which directional force is being applied and which angle the body is facing, note that I use a variation of this for all four forces (x, -x, y, -y) and swap the sprite accordingly. As shown, this never expects the angle to be anything beyond the normal radians so it ends up hitting the else statement after a full positive rotation and hits the else statement after a negative rotation immediately.

Code: Select all

      if player.body:getAngle() > 3.93 and player.body:getAngle() < 5.5 then
        player.sprite = sprites.shipLeft
      elseif player.body:getAngle() < 3.93 and player.body:getAngle() > 2.36 then
        player.sprite = sprites.shipFront
      elseif player.body:getAngle() < 2.36 and player.body:getAngle() > 0.79 then
        player.sprite = sprites.shipRight
      else
        player.sprite = sprites.shipRear
      end

Re: Continual torque changes body angle beyond expected range

Posted: Thu Jul 02, 2020 1:31 am
by pgimeno
lostboii wrote: Thu Jul 02, 2020 12:54 am I may be misunderstanding what getAngle() is even supposed to return, because my understanding of radians is that they should never be negative in this context, and should only be between 0-6.284[[...] but I think I'm more likely not understanding how applyTorque is impacting the body's angle and why.
This is not related to your problem but your expectation is wrong. Floats have the habit of being more precise near zero and lose precision the bigger they are (in absolute value), therefore most functions that work with angles work in the range -pi..pi to avoid this loss of precision. math.atan2(-1, 0) returns -pi/2, for example.

As for your problem, since you haven't provided a test case and making one takes more time than I can spare right now, I'll just suggest you to try this:

Code: Select all

float angle = player.body:getAngle() % (2*math.pi)
player.body:setAngle(angle)
If that doesn't work as you expect, maybe try this instead:

Code: Select all

float angle = player.body:getAngle() % (2*math.pi)
float omega = player.body:getAngularVelocity()
player.body:setAngle(angle)
player.body:setAngularVelocity(omega)
Obviously untested, so no guarantees.

Re: Continual torque changes body angle beyond expected range

Posted: Thu Jul 02, 2020 2:10 am
by lostboii
Your first suggestion worked perfectly, thank you. I realized after posting this that setAngularVelocity also exhibited the behavior so I figured it must be related to the angle. I don't think I fully understand why this fixes it yet, but I will parse your response a few more times and try to get a better understanding. Mathematics is not at all my strength. Thanks again! Edit: I learned what modulo does and how it's applied here, very cool!