Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Serge144 · Jan 05, 2019 at 12:53 PM · unity 5camera-movementbulletcamera rotateanswers

Camera following a cannonball that is mouse controlled.

So a cannonball is fired in a 3D world. This cannonball is fired by first instacianting it and then setting some initial velocity into its rigidbody component. The cannonball is controlled with the mouse by first obtaining float x = Input.getAxis("Mouse X") and then adding force to the rigidbody: rb.AddForce(Vector3.right * x * 50f); Also, i added some torque to the ball in order to give it a more natural spinning effect. The figure below shows two situations with a top-down view of the 3D world. The first situation (A) is what is currently happening, the ball is controlled with the mouse but the camera stays fixed always facing forward. What i want is for situation B to happen, where the camera rotates slightly looking into where the ball is going to. So how i can i rotate the camera slightly in order to make it look into the direction of where the ball is heading (Situation B)? Again, the cannonball has some spinning effect to it by adding some torque and the camera is following the cannonball with a Vector3 offset like this: camera.position = cannonBall.transform.position + offset, updating it in a coroutine; Thank you in advance.

alt text

camerahelp.png (10.4 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Ady_M · Jan 05, 2019 at 02:34 PM

Version 1

 

 public Vector3 cameraDirection;
 public float cameraDistance = 10; // Replaces your "offset" variable
 public float cameraRotateDelay = 0.93f; // Decrease this value if the camera rotates too slowly
 
 public Camera camera;
 public Rigidbody ballRigidbody;
 
 // Every frame:
 
 float d = cameraRotateDelay;
 cameraDirection = (d * cameraDirection + (1-d) * ballRigidbody.velocity.normalized).normalized;
 
 camera.transform.rotation = Quaternion.LookRotation (cameraDirection);
 camera.transform.position = ballRigidbody.position - cameraDirection * cameraDistance;

 

Version 2

 

In this version, cameraDirection and cameraDistance are calculated in Awake using the Camera's initial position and an empty object called "Ball SpawnPoint" inside the Cannon object. You can now position the camera wherever you want, but don't bother rotating it yourself. It will look at Ball SpawnPoint on Awake.

 

To keep the initial camera rotation:

 // Replace this:
 cameraDirection = (ballSpawnPoint.transform.position - camera.transform.position).normalized;

 // With this:
 cameraDirection = camera.transform.forward;

 

I have replaced Rigidbody.position with Rigidbody.transform.position. I had forgotten that using Rigidbody.position gives different results.

 

For some reason, the first frame after firing messes up the camera position. It jumps down a little and then starts following correctly. As a workaround, I created a property called ballFramesAirborne which increases each frame while the ball is airborne. I prevent the camera from updating if ballFramesAirborne is zero.

 

The full code:

 public  float     ballInitialSpeed = 20;
 public  Transform ballSpawnPoint;            // An empty child object of the Cannon
 public  Rigidbody ballRigidbody;
 private bool      ballIsAirborne = false;    // Camera will only move and rotate if this is true
 private int       ballFramesAirborne = 0;    // Read about this in the updateCamera() method.

 public  Camera    camera;
 private Vector3   cameraInitialDirection;    // Is set only once. Used every time you fire.
 private Vector3   cameraDirection;           // Changes each frame.
 public  float     cameraDistance = 10;
 public  float     cameraRotateDelay = 0.90f; // (0.0 .. 1.0) Decrease this value if the camera rotates too slowly


 private void Awake ()
 {
     // Disable and hide the ball
     ballRigidbody.gameObject.SetActive (false);

     // Get cameraDirection and cameraDistance from current state of the camera
     // (Allows you to set up the initial state of the camera in the editor)
     cameraDirection = (ballSpawnPoint.transform.position - camera.transform.position).normalized;
     cameraDistance = Vector3.Distance (ballSpawnPoint.transform.position, camera.transform.position);
     
     // Save the camera's initial position, so we can use it next time we fire
     cameraInitialDirection = cameraDirection;
 }


 public void fire ()
 {
     ballIsAirborne = true;
     ballFramesAirborne = 0;
     ballRigidbody.gameObject.SetActive (true);
     ballRigidbody.transform.position = ballSpawnPoint.position;
     ballRigidbody.velocity = transform.forward * ballInitialSpeed;

     cameraDirection = cameraInitialDirection;
 }


 public void updateCamera ()
 {
     // The first frame after firing messes up the camera position.
     // ballFramesAirborne is used to fix that.

     if (ballIsAirborne == false || ballFramesAirborne == 0)  return; // Skip the rest of the code

     float d = cameraRotateDelay;
     cameraDirection = (d * cameraDirection + (1-d) * ballRigidbody.velocity.normalized).normalized;

     camera.transform.rotation = Quaternion.LookRotation (cameraDirection);
     camera.transform.position = ballRigidbody.position - cameraDirection * cameraDistance;
 }


 private void Update ()
 {
     if (Input.GetMouseButtonDown (1))
     {
         fire ();
     }
 }


 private void LateUpdate ()
 {
     updateCamera ();

     // DEV >> Draw a line in the Scene View indicating where the camera is looking
     Debug.DrawRay (camera.transform.position,  camera.transform.forward * 100,  Color.magenta,  0,  false);

     // DEV >> Draw a line in the Scene View indicating the velocity vector of the ball
     Debug.DrawRay (ballRigidbody.transform.position,  ballRigidbody.velocity.normalized * 100,  Color.blue,  0,  false);

     ballFramesAirborne ++;
 }














Comment
Add comment · Show 13 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Serge144 · Jan 05, 2019 at 03:13 PM 0
Share

woa, magic.., thank you!

avatar image Ady_M Serge144 · Jan 05, 2019 at 03:41 PM 0
Share

You're welcome :) I'm sure you've already figured this out, but don't forget to do cameraDirection = ballRigidbody.velocity.normalized right after setting the initial velocity.

avatar image Serge144 · Jan 05, 2019 at 04:14 PM 0
Share

@Ady_$$anonymous$$ how could i keep that offset when the camera starts following the ball? this is because i wanted a smooth transition when the cannon fires and then the camera starts following the ball.

avatar image Ady_M Serge144 · Jan 05, 2019 at 05:11 PM 0
Share

Do you mean the camera is initially standing still and then accelerates to follow the cannon ball?

avatar image Serge144 Ady_M · Jan 05, 2019 at 05:12 PM 0
Share

yes, the camera is initially behind the cannon and slightly above, then when the cannon fires the camera starts following the ball

Show more comments
avatar image
0

Answer by Serge144 · Jan 12, 2019 at 09:06 PM

updating my solution, which is now simpler. I basically do this: when the camera starts following the ball it will follow starting from its position and direction, and then, over time, the position of the camera is slowly moved in such way that the camera direction is aligned with the ball movement (as Ady sugested). The speed of this transition may also be set. This way there's a smooth transition of the camera from its idle state and follow-ball state.

 public class CameraController : MonoBehaviour
 {
     CannonBall cannonBall;
     Rigidbody rb;
     Vector3 savedCameraPos;
     Vector3 cameraDirection;
     Vector3 offset;
     Quaternion savedCameraRot;
     int ballFramesAirbourne = 0;
     float ballToCamDistance;
     float cameraRotateDelay = 0.65f;
     float timer = 1.75f;
 
     //Coroutine that makes the camera follow the cannonball across multiple frames
     IEnumerator Transition()
     {
         savedCameraPos = transform.position; //save the position of the camera
         savedCameraRot = transform.rotation; //save the rotation of the camera 
         float startTime = Time.time;
         while (timer > 0)
         {
             //do not udpate the camera on the first frame because the velocity vector of the ball is not initialized for some reason
             if (ballFramesAirbourne == 0) {
                 Debug.DrawRay(new Vector3(0,0,0), rb.transform.position + offset, Color.yellow, 0, false);
                 ballFramesAirbourne++;
                 yield return null;
             }
             
          //calculate the cameras direction and update the positions and rotations
          cameraDirection = (cameraRotateDelay * cameraDirection + (1 - cameraRotateDelay) * rb.velocity.normalized).normalized;
          transform.rotation = Quaternion.LookRotation(cameraDirection);
          transform.position = cannonBall.transform.position + offset;
 
          //When the camera starts following the ball, it will start in its initial position
          //but then, over time, the camera will transition to be aligned with the camera.
          Vector3 newPos = rb.transform.position - cameraDirection * ballToCamDistance;
          float timeFrac = (Time.time - startTime) / timer;
          transform.position = Vector3.Lerp(transform.position, newPos,timeFrac * 5f);
 
          timer -= Time.deltaTime;
          yield return null;
         }
         timer = 1.75f;
         StartCoroutine("Return");
     }
 
     //returns the camera into the initial position and initial rotation
     IEnumerator Return()
     {
         float speed = 100f;
         float step = speed * Time.deltaTime;
         while (!(transform.position == savedCameraPos) || (Quaternion.Angle(transform.rotation,savedCameraRot) > 2))
         {
             transform.position = Vector3.MoveTowards(transform.position, savedCameraPos, step);
             transform.rotation = Quaternion.RotateTowards(transform.rotation, savedCameraRot, step);
             yield return null;
         }
         CannonController.unlockCannon();
     }
 
     //initializes the transition coroutine
     public void followCannonBall(CannonBall cb)
     {
         cannonBall = cb;
         rb = cb.GetComponent<Rigidbody>();
         cameraDirection = transform.forward;
         ballToCamDistance = Vector3.Distance(transform.position, cannonBall.transform.position); //this can be on Start since the Distance is always the same
         offset = transform.position - cb.transform.position;
         ballFramesAirbourne = 0;
         StartCoroutine("Transition");
     }
     
 }


Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Ady_M · Jan 08, 2019 at 11:58 PM 0
Share

Great work. Good luck with the project! :)

avatar image
0

Answer by Serge144 · Jan 13, 2019 at 02:46 PM

Updating my answer which is basically @Ady_M answer but with a small addition so that there's a smooth transition between the cameras idle state and the follow-ball state. I basically did this: when the camera starts following the ball, it begins with its initial position and direction, then, over time, the camera is moved in such way that it stays aligned with the ball direction. The speed of this transition may also be set.

 public class CameraController : MonoBehaviour
 {
     CannonBall cannonBall;
     Rigidbody rb;
     Vector3 savedCameraPos;
     Vector3 cameraDirection;
     Vector3 offset;
     Quaternion savedCameraRot;
     int ballFramesAirbourne = 0;
     float ballToCamDistance;
     float cameraRotateDelay = 0.65f;
     float timer = 1.75f;
 
     //Coroutine that makes the camera follow the cannonball across multiple frames
     IEnumerator Transition()
     {
         savedCameraPos = transform.position; //save the position of the camera
         savedCameraRot = transform.rotation; //save the rotation of the camera 
         float startTime = Time.time;
         while (timer > 0)
         {
             //do not udpate the camera on the first frame because the velocity vector of the ball is not initialized for some reason
             if (ballFramesAirbourne == 0) {
                 Debug.DrawRay(new Vector3(0,0,0), rb.transform.position + offset, Color.yellow, 0, false);
                 ballFramesAirbourne++;
                 yield return null;
             }
             
          //calculate the cameras direction and update the positions and rotations
          cameraDirection = (cameraRotateDelay * cameraDirection + (1 - cameraRotateDelay) * rb.velocity.normalized).normalized;
          transform.rotation = Quaternion.LookRotation(cameraDirection);
          transform.position = cannonBall.transform.position + offset;
 
          //When the camera starts following the ball, it will start in its initial position
          //but then, over time, the camera will transition to be aligned with the camera.
          Vector3 newPos = rb.transform.position - cameraDirection * ballToCamDistance;
          float timeFrac = (Time.time - startTime) / timer;
          transform.position = Vector3.Lerp(transform.position, newPos,timeFrac * 5f);
 
          timer -= Time.deltaTime;
          yield return null;
         }
         timer = 1.75f;
         StartCoroutine("Return");
     }
 
     //returns the camera into the initial position and initial rotation
     IEnumerator Return()
     {
         float speed = 100f;
         float step = speed * Time.deltaTime;
         while (!(transform.position == savedCameraPos) || (Quaternion.Angle(transform.rotation,savedCameraRot) > 2))
         {
             transform.position = Vector3.MoveTowards(transform.position, savedCameraPos, step);
             transform.rotation = Quaternion.RotateTowards(transform.rotation, savedCameraRot, step);
             yield return null;
         }
         CannonController.unlockCannon();
     }
 
     //initializes the transition coroutine
     public void followCannonBall(CannonBall cb)
     {
         cannonBall = cb;
         rb = cb.GetComponent<Rigidbody>();
         cameraDirection = traansform.forward;
         ballToCamDistance = Vector3.Distance(transform.position, cannonBall.transform.position); //this can be on Start since the Distance is always the same
         offset = transform.position - cb.transform.position;
         ballFramesAirbourne = 0;
         StartCoroutine("Transition");
     }
     
 }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

195 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How can I rotate my camera when player has rigidbody? 0 Answers

How to make camera mouse orbit not jittery? 0 Answers

Adjust camera orientation through code 0 Answers

Camera isn't following mouse in FPS 0 Answers

Why Do I Have Camera Stutter? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges