Search code examples
javascriptthree.jsrotationphysijs

Turning objects so they reset their y-rotation in Three.js


Using three.js, I'm creating a game with cars that move in a specific direction, depending on their y-rotation. An example would be 90 degrees. I use object.translateZ() to move them forward but I've run into a problem.

I'm using physijs to simulate the cars. Cars that run into each other may change their y-rotation (because of the crash) and I want to find a way for the cars to slowly change their rotation back to the original rotation like they are turning to get back on the road. Without this my city is very chaotic.

Here's the code that I'm already using (this is just part of it):

var targetRotation = 90
var rotation = car.mesh.rotation.y * 180 / Math.PI //to convert to degrees

I want to find a way to slowly change the car's rotation so it's the same as the target rotation.

Any help is appreciated! (but some sort of function would be perfect)


Solution

  • I've done stuff like this before in other systems (2D, not Three.js), and essentially all you want to do is gradually increment the angle until you reach something close enough to the target angle. Usually this means the float is less than the turning speed you're incrementing by (so you don't "overshoot" the value).

    The amount of the increment depends on how quickly you want them to turn.

    You also want to check if it's better to increase the angle or decrease (do you turn clockwise or counterclockwise) depending on if you're closer to 360 or 0. This prevents the car from turning the "long way" around. You can find this out by seeing if the difference is greater/less than 180.

    We can use the modulus operator to get the "real" angle between -360/360.

    var currentAngle = car.mesh.rotation.y * 180 / Math.PI; //car's angle in degrees
    var targetAngle = 90; //preferred angle *this time* ;)
    var turningSpeed = 1; //one degree per update (wayyy to high for real stuff, usually)
    currentAngle = currentAngle % 360; //get the 0-360 remainder
    if ( Math.abs(targetAngle - currentAngle) >= turningSpeed) {
      var addto = 0
      if (targetAngle - currentAngle < 0) {
        addto = 360
      }
      if ( targetAngle - currentAngle + addto <= 180 ) { 
        currentAngle += turningSpeed;  
      }
      else {
         currentAngle -= turningSpeed;
      }
    }
    else { currentAngle = targetAngle; } //we're close enough to just set it
    car.mesh.rotation.y = ( currentAngle * Math.PI ) / 180; // back to radians!