Unity X-Axis rotation quirk - unity3d

I have a script that rotates an object whilst a button is pressed. The rotation plane depends on which axis is selected in the Dropdown menu. The script works mostly fine for the Y and Z axis, but has unexpected behaviour on the X-Axis.
When holding in the left rotate button, the volume will rotate to -90 and get 'stuck'. I then hold in the right rotate button and it doesn't go further than 90 before getting stuck again. What's even weirder is that quite often after getting stuck in a particular direction and switching to the alternate direction, instead of the volume going back the other way, it continues in the direction it was going had it not gotten stuck in the first place. This causes the left and right rotation buttons to be swapped around.
Here is the code with all the main operations.
public void Update()
{
axis = axisDropdown.value;
Vector3 originalRot = transform.eulerAngles;
if (buttonHeld)
{
if (rotateRight)
{
if (axis == 0)
{
originalRot.x += 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else if (axis == 1)
{
originalRot.y += 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else if (axis == 2)
{
originalRot.z += 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else
{
print("Error: Selected axis option is invalid");
}
}
else
{
if (axis == 0)
{
originalRot.x -= 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else if (axis == 1)
{
originalRot.y -= 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else if (axis == 2)
{
originalRot.z -= 1;
transform.rotation = Quaternion.Euler(originalRot);
}
else
{
print("Error: Selected axis option is invalid");
}
}
}
}
I have read of other similar problems to mine, but they all seem to be slightly different so any help would be appreciated.

This is indeed caused by the gimbal lock effect. It occurred because I was trying to alter the Euler angles of my object rather than just rotating around the quaternions.
Here is the working code to avoid the issue:
public void Update()
{
axis = axisDropdown.value;
Vector3 originalRot = transform.eulerAngles;
if (buttonHeld)
{
if (rotateRight)
{
if (axis == 0)
{
transform.RotateAround(volume.transform.position, Vector3.right, 50 * Time.deltaTime);
}
else if (axis == 1)
{
transform.RotateAround(volume.transform.position, Vector3.up, 50 * Time.deltaTime);
}
else if (axis == 2)
{
transform.RotateAround(volume.transform.position, Vector3.forward, 50 * Time.deltaTime);
}
else
{
print("Error: Selected axis option is invalid");
}
}
else
{
if (axis == 0)
{
transform.RotateAround(volume.transform.position, Vector3.left, 50 * Time.deltaTime);
}
else if (axis == 1)
{
transform.RotateAround(volume.transform.position, Vector3.down, 50 * Time.deltaTime);
}
else if (axis == 2)
{
transform.RotateAround(volume.transform.position, Vector3.back, 50 * Time.deltaTime);
}
else
{
print("Error: Selected axis option is invalid");
}
}
}
}

Related

Unity 2d C# character flipping but weapon doesn't

It was made so that when my character look to a side its model would flip from right to left. The problem is that the weapon that he carries doesn't and it just upside down.
For reference in visuals use the game Nuclear Throne.
The code for my character is this:
void Update
{
if (mousePos.x < transform.position.x && FacingRight)
{
Flip();
}
else if (mousePos.x > transform.position.x && !FacingRight)
{
Flip();
}
}
void Flip()
{
FacingRight = !FacingRight;
transform.Rotate(0f, 180f, 0f);
}
and for the weapon, which I put in the Aim empty game object
void Update()
{
Vector2 direction = (PointerPosition - (Vector2)transform.position).normalized;
transform.right = direction;
Vector2 scale = transform.localScale;
if(direction.x < 0)
{
scale.y = -1;
}
else if (direction.x > 0)
{
scale.y = 1;
}
transform.localScale = scale;
}
For when my weapon looks left my y scale to be -1 and to cause the weapon to flip.

Frame-rate independent pushForce?

I'm working with a CharacterController and added the ability to push Rigidbodies. The problem is however that the pushing is frame-rate dependent. How would I be able to make it frame-rate independent? I have tried adding Time.deltatime, but this makes pushing not possible, I might be adding it wrong though.
Here's the code that adds force to rigidbodies;
void OnControllerColliderHit(ControllerColliderHit hit)
{
Rigidbody body = hit.collider.attachedRigidbody;
if (body == null || body.isKinematic)
return;
if (hit.moveDirection.y < -.3f)
return;
Vector3 pushDirection = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);
body.velocity = pushForce * pushDirection;
}
As far as I know it has something to do with the last 2 lines of code.
Edit(The code for pushing):
public void PushStates() {
// Creating the raycast origin Vector3's
Vector3 forward = transform.TransformDirection(Vector3.forward) * distanceForPush;
Vector3 middle = controller.transform.position - new Vector3(0, -controller.height / 2, 0);
// Inspector bool
if (pushRay)
{
Debug.DrawRay(middle, forward, Color.cyan);
}
// Force the pushForce and movementSpeed to normal when the player is not pushing
pushForce = 0f;
movementSpeed = walkSpeed;
// Draws a raycast in front of the player to check if the object in front of the player is a pushable object
if (Physics.Raycast(middle, forward, out hit, distanceForPush))
{
if (InputManager.BButton() && playerIsInPushingTrigger)
{
PushableInfo();
playerIsPushing = true;
anim.SetBool("isPushing", true);
if (hit.collider.tag == "PushableLight")
{
pushForce = playerPushForceLight;
movementSpeed = pushSpeedLight;
}
else if (hit.collider.tag == "PushableHeavy")
{
pushForce = playerPushForceHeavy;
movementSpeed = pushSpeedHeavy;
}
// Checks the players speed now instead off movement. This is neccesary when the player is pushing a pushable into a collider.
// The player and pushable never stop moving because of force.
if (currentSpeed < 0.15f)
{
//Removes all remaining velocity, when the player stops pushing
pushableObjectRB.velocity = Vector3.zero;
pushableObjectRB.angularVelocity = Vector3.zero;
anim.SetFloat("pushSpeedAnim", 0f);
}
else
{
// Calls a rotation method
PushingRot();
if (hit.collider.tag == "PushableLight")
{
anim.SetFloat("pushSpeedAnim", pushSpeedAnimLight);
}
else if (hit.collider.tag == "PushableHeavy")
{
anim.SetFloat("pushSpeedAnim", pushSpeedAnimHeavy);
}
}
}
else
{
anim.SetBool("isPushing", false);
pushForce = 0f;
movementSpeed = walkSpeed;
playerIsPushing = false;
}
}
else
{
anim.SetBool("isPushing", false);
playerIsPushing = false;
}
// Setting the time it takes to rotate when pushing
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (stateInfo.fullPathHash == pushStateHash)
{
turnSmoothTime = maxTurnSmoothTimePushing;
}
else
{
turnSmoothTime = 0.1f;
}
}
You were right, you need to multiply by Time.deltaTime which is the time elapsed since last rendered frame.
As this number is really small (has you have 60+ fps) you'll also need to increase the value (multiply it by 100, 1000...)

Rotate unity gameobject smoth in the other direction

i want to rotate (actually just to the left and right side) an object by swiping over the screen. I have working code already but when i swipe from the left to the right of my screen, the whole movement is kind of lagging.
The object has the following script.
Any help is appreciated... this is driving me crazy.
Thank you for your time!
[ICODE]void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Debug.Log("Dragging Detected");
Vector2 newTouchPosition = Input.GetTouch(0).position;
float dis = (Vector2.Distance((Vector2)oldTouchPositions[0], newTouchPosition)) / 4;
if (((Vector2)oldTouchPositions[0])[0] < newTouchPosition[0])
{
//Debug.Log("Left"); dunno if correct
vertical = (vertical - velcoidadeDeGiro * dis) % 360;
transform.localRotation = Quaternion.AngleAxis(vertical, Vector3.up);
oldTouchPositions[0] = newTouchPosition;
}
else
{
//Debug.Log("Right");
vertical = (vertical - velcoidadeDeGiro * dis) % 360;
transform.localRotation = Quaternion.AngleAxis(vertical, Vector3.down);
oldTouchPositions[0] = newTouchPosition;
}
}
}[/ICODE]

How to have an object flip directly on right or left arrow in unity?

I am trying to get a GameObject to face right when I press the right arrow and then face left when I press left arrow.
What I currently get is the image to flip back and forth over and over again. It won't just stay facing left or right.
On occasion it will switch to the left and stay that way even though I am pressing right. I am sure there is a better way to do this.
public bool isFacingRight;
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow))
{
petAnimate.AnimationName = "run_loop";
} else
{
petAnimate.AnimationName = "start_loop_2";
}
if (Input.GetKey(KeyCode.RightArrow)) {
isFacingRight = true;
}
if (Input.GetKey(KeyCode.LeftArrow)) {
isFacingRight = false;
}
Flip();
}
void Flip()
{
if (isFacingRight == true)
{
transform.Rotate(0, 0, 0);
}
if (isFacingRight == false)
{
transform.Rotate(0, 180, 0);
}
}
You can simply times the X scale by -1. Multiplying by -1 will just turn everything backwards :)
void Flip()
{
// Switch the way the player is labelled as facing
isFacingRight = !isFacingRight;
// Multiply the player's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
Note that this method will work on whichever arrow key you press (left or right). If your character is facing right in your scene, set your bool to true, otherwise set it to false
void Flip()
{
if (isFacingRight == true)
{
transform.localScale = new Vector3(.2f, .2f, 0);
}
if (isFacingRight ==false)
{
transform.localScale = new Vector3(-.2f, .2f, 0);
}
}

How to check rotation of an object in Unity3d?

I'm a unity3d learner. I have a problem with rotation of an object. I want to rotate objects about 40 degrees along the z axis. If the objects rotation has reached 40 degrees, I want something to happen. Here is my code.
foreach(Touch touch in Input.touches) {
if(touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled) {
var target = Quaternion.Euler (0, 0,-40);
transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
if (transform.rotation.eulerAngles.z == -40) {
toggle = true;
speech = "blah blah blah";
snake = man;
}
}
}
The if(transform.rotation.eulerAngles.z == -40) line of code is not working. So I don't know if the rotation degree has reached 40 degree or not. How do I check if the rotation degree has reached 40 degrees?
I don't understand your code intent.
EulerAngles is not set negative only positive value(Vector3)
-if(eulerAngles.z == -40) is not work you try change value -40 -> 320
If you want scenario ontouch -> object rotation -> event
try this code.
float rotTime = 1f; // rotation duration
Vector3 rotValue = new Vector3(0, 0, -40f); // rotation value
void Update () {
foreach (Touch touch in Input.touches)
if (touch.phase == TouchPhase.Began) OnTouchEvent();
}
void OnTouchEvent()
{
StopCoroutine("rotationCoroutine");
StartCoroutine("rotationCoroutine");
}
IEnumerator rotationCoroutine()
{
float startTime = Time.time;
Vector3 startRot = transform.eulerAngles;
Vector3 endRot = startRot;
endRot += rotValue;
while (Time.time - startTime <= rotTime)
{
transform.eulerAngles = Vector3.Slerp(startRot, endRot,(Time.time - startTime) / rotTime);
yield return null; // wait 1 frame
}
//rotation end
MyAction();
}
void MyAction()
{
Debug.Log("rotation end");
//toggle = true;
//speech = "blah blah";
//snake = man;
}
Good Luck :D