Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 unity_800tOTWh-Hus0A · Jan 14, 2021 at 11:01 PM · rotationquaternionangleslocalrotationtilting

How can I pitch and roll a circular platform without releasing vertical/horizontal input?

Greetings developers!

I have a simple goal in mind: control the pitch (x) and roll (z) of a circular platform (built using a sphere with scale 10, -0.1, 10) to balance a sphere on top of it.

However, I wish to limit the rotation both in the x and z axes (ideally the y axis is frozen), so that the platform cannot go beyond a certain tilt angle (50f) in any direction.

The code below works, but not exactly as desired: the moment the platform reaches the tilt angle, the 'if' statement no longer holds and the platform gets stuck, forcing me to release all keys to restore the original rotation of the platform (0, 0, 0).

My wish is that, once the platform has reached the tilt angle limit (or approached it), I may keep tilting the platform on the axis which has not reached the limit.

alt text

I hope the GIFs can better express what my desired result is. In the first one (above), I am showing the as-is behavior, in the second one, I am showing the desired behavior (I used a simple work-around setting the max tilt angle to 80 giving the impression that the platform does not get stuck at the 50 limit and I can keep rotating within my desired limit).

I have been stuck on this for days, can anyone help?

Thanks in advance, and please let me know if I can provide any additional info to make the question clearer. Cheers!

alt text

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class KeyController : MonoBehaviour
 {
     Quaternion originalRotation;
     Rigidbody m_Rigidbody;
     bool restoreRotation = false;
     [SerializeField] float tiltAngle = 50f;
 
     float h;
     float v;
 
     private void Start()
     {
         originalRotation = transform.rotation;
         m_Rigidbody = GetComponent<Rigidbody>();
     }
 
     void FixedUpdate()
     {
         m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotation;
         m_Rigidbody.constraints = RigidbodyConstraints.FreezePosition;
 
         if (!Input.GetKey(KeyCode.LeftArrow) & !Input.GetKey(KeyCode.RightArrow) & !Input.GetKey(KeyCode.UpArrow) & !Input.GetKey(KeyCode.DownArrow) & !restoreRotation)
         {
             restoreRotation = true;
         }
 
 // If I am not holding down any key, take me back to original rotation 0, 0, 0
         if (restoreRotation & !Input.anyKey)
         {
             transform.rotation = Quaternion.Lerp(transform.rotation, originalRotation, Time.deltaTime * 2);
 
             if (transform.rotation == originalRotation)
             {
                 restoreRotation = false;
             }
         }
         else if (restoreRotation & Input.anyKey)
         {
             restoreRotation = false;
         }
 // If I am holding down the left, right, up and/or down key
         else if (!restoreRotation)
         {
             h = Input.GetAxis("Horizontal") * tiltAngle;
             v = -Input.GetAxis("Vertical") * tiltAngle;
 
             if (Quaternion.Angle(originalRotation, transform.localRotation) <= tiltAngle)
             {
                 transform.localRotation *= Quaternion.AngleAxis(h * Time.deltaTime, new Vector3(0, 0, 1));
                 transform.localRotation *= Quaternion.AngleAxis(v * Time.deltaTime, new Vector3(1, 0, 0));
             }
         }
     }
 }


tobe.gif (487.9 kB)
asis.gif (481.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

1 Reply

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

Answer by Eno-Khaon · Jan 15, 2021 at 11:31 AM

Well, there are actually a few things that can be addressed here.

First, if you're holding ANY key whatsoever, the platform won't rotate back to its original orientation.

Second, you're getting pretty lucky that this works by modifying transform.localRotation when using the physics system. While it should mean that it's not necessarily applying meaningful/appropriate force against the ball it's supporting while it's actively rotating, it's also relying on small rotations per physics frame to not simply pass through the ball.

Finally, there's also a much simpler way that you can track the rotation in this scenario. You even have the variables available to support it, but didn't really use them in that manner (h and v).


So, let's get to implementation, then.

First, as a matter of principle, because Input values are provided during Update() (specified because the new input system isn't strictly limited to that), my example will apply input there.

Then, you can use Rigidbody.MoveRotation() to provide discrete rotations in FixedUpdate() while honoring physics interactions.
 public float maxAngle; // The maximum angle of rotation allowed
 public float tiltSpeed; // Rotation speed, up to maxAngle
 public float returnSpeed; // Speed to return to original orientation
 Vector2 currentInput; // The current frame's input to apply to the total
 Vector2 totalInput; // The combined totals from rotation inputs
 
 void Update()
 {
     currentInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
 }

 void FixedUpdate()
 {
     // If no input is being provided, ease total input(s) toward 0
     if(Mathf.Approximately(currentInput.sqrMagnitude, 0.0f))
     {
         // Time.deltaTime is implicitly converted to Time.fixedDeltaTime
         // when called inside FixedUpdate()
         totalInput = Vector2.MoveTowards(totalInput, Vector2.zero, returnSpeed * Time.deltaTime);
     }
     else
     {
         // If there's input, apply it to the running total here
         totalInput += currentInput * Time.deltaTime * tiltSpeed;
         // If the total vector length exceeds the maximum, adjust it
         if(totalInput.sqrMagnitude > maxAngle * maxAngle)
         {
             totalInput = totalInput.normalized * maxAngle;
         }
         // Note that this approach should move smoothly toward the current
         // input, while not aligning to cardinal directions easily. 
         // There are many ways to design this, so this is simply
         // one of many options available
     }
     // Now, regardless of how the totalInput has changed, the rotation can be
     // set at this point (add restrictions as desired)
     m_Rigidbody.MoveRotation(Quaternion.AngleAxis(totalInput.x, Vector3.forward) * Quaternion.AngleAxis(totalInput.y, Vector3.left));
 }


I apologize in advance if there are any mistakes. I know that prototyping things when tired won't necessarily end well (especially when untested), but wanted to get this typed up anyway.

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 unity_800tOTWh-Hus0A · Jan 15, 2021 at 02:14 PM 0
Share

Hi Eno-Khaon,

Thank you so much for the explanation and for providing the implementation code as well. Really appreciated the patience, clarity and logic of it all. I simply had to add a reference to m_Rigidbody and declare m_Rigidbody = GetComponent() in Start() to make the code work - and it does so exactly as I asked.

If you don't $$anonymous$$d, can you indulge me with another answer and/or explanation? One challenge I intend to add to the game are heavy, falling objects meant to destabilize the platform while balancing the ball. So, I created a HeavyCube (100 mass) and let it drop from a certain height. The issue is that with Rigidbody.$$anonymous$$oveRotation(), the collision is not registered correctly, and the cube simply goes through the platform. alt text Instead, the collision worked well when I used transform.localRotation. alt text Any ideas as to why this happens and/or how to redress this issue? Thanks in advance :)

EDIT

I noticed that the moment I comment the last line of code you provided (i.e. m_Rigidbody.$$anonymous$$oveRotation(Quaternion.AngleAxis(totalInput.x, Vector3.forward) Quaternion.AngleAxis(totalInput.y, Vector3.left));*), the physics go back to acting as expected (like in the second GIF).

moverotationcollision.gif (154.1 kB)
localrotationcollision.gif (379.0 kB)

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

153 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

Related Questions

Child versus Parent rotations 3 Answers

Calculating angles to a target and turning towards it 1 Answer

Recording hand gestures and playing it back on same hand model 1 Answer

How Do I accurately rotate a player 180 degrees about the Z axis? 1 Answer

Rotation using Quaternion.Lerp 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