[SOLVED] Continual torque changes body angle beyond expected range

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
lostboii
Prole
Posts: 6
Joined: Sun Jun 28, 2020 4:00 pm
Location: North Carolina, US

[SOLVED] Continual torque changes body angle beyond expected range

Post 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
Last edited by lostboii on Thu Jul 02, 2020 2:11 am, edited 2 times in total.
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Continual torque changes body angle beyond expected range

Post 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.
lostboii
Prole
Posts: 6
Joined: Sun Jun 28, 2020 4:00 pm
Location: North Carolina, US

Re: Continual torque changes body angle beyond expected range

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

Who is online

Users browsing this forum: No registered users and 3 guests