Unity - Decrease/Increase the "Z axis" angle axis on Update() - c#

[See my answer below! Thanks for the comments]
What is the best way to Decrease/Increase an angle without using "eulerAngles"?
I need turn my transform between 30 and 325, according to my "Y axis".
If it is less than zero we reduce the value of "Z axis" is greater if we increase the value of "Z axis".
I already tried:
if ( airPlanePlayerRigidbody2D.velocity.y < 0 ) {
var rotationVector = airPlanePlayerTransform.rotation;
rotationVector.z -= 2f;
Vector3 vec = new Vector3(rotationVector.x,rotationVector.y,rotationVector.z);
airPlanePlayerTransform.rotation = Quaternion.Euler(vec);
}
And:
public void Rotate(float angle)
{
airPlanePlayerTransform.Rotate(0, 0, angle); // this rotate forever
}
Thank you in advance.
UPDATE
In fact I already have a code that does what I need, but it is too long. I'm looking for some simpler. The result I want is this:
A more smoothed animation:Smooth animation down
And what I can do so far with the comments posted here, is this:Without animation

I think eulerAngeles is a good way to go with, and I successfully did the similar rotation effect in Unity by using eulerAngeles. You probably didn't find the correct way when you used it.
I used something like that:
Vector3 newRotationAngles = transform.rotation.eulerAngles;
if (Input.GetKey(KeyCode.LeftArrow)) {
newRotationAngles.z += 1;
} else if (Input.GetKey(KeyCode.RightArrow)) {
newRotationAngles.z -= 1;
}
transform.rotation = Quaternion.Euler (newRotationAngles);
Output: when you press the left/right arrow keys, the gameObject will rotate, but it is not always rotating. Hope this is helpful.

You want something like this:
public float maxAngle = 325f; // Max Angle for Z Axis
public float minAngle = 30f; // Min Angle for Z Axis
public float rotationDelta = 1f; // you can control your rotation speed using this
float tempAngle;
void Update()
{
// If AirPlane is rising, velocity in y is greater than 0
if(rigidbody2D.velocity.y > 0)
{
tempAngle = Mathf.LerpAngle(transform.eulerAngles.z, maxAngle, Time.time * rotationDelta);
}
// If AirPlane is falling, velocity in y is less than 0
else if(rigidbody2D.velocity.y < 0)
{
tempAngle = Mathf.LerpAngle(transform.eulerAngles.z, minAngle, Time.time * rotationDelta);
}
// If AirPlane is going straight in horizontal.
else
{
tempAngle = 0;
}
transform.eulerAngles = new Vector3(0, 0, tempAngle);
}

Researching the topic, I managed to get the result. Thanks for the replies.
if (airPlanePlayerRigidbody2D.velocity.y < 0) { //falling
var myNewQuaternion = Quaternion.Euler (new Vector3 (0, 0, -30));
var myQuaternion = Quaternion.Euler(new Vector3(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z));
transform.rotation = Quaternion.Slerp (myQuaternion , myNewQuaternion , speed );
}
else if (airPlanePlayerRigidbody2D.velocity.y > 0) { // rising
var myNewQuaternion = Quaternion.Euler (new Vector3 (0, 0, 30));
var myQuaternion = Quaternion.Euler(new Vector3(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z));
transform.rotation = Quaternion.Slerp (myQuaternion , myNewQuaternion , speed );
}

Related

Moving from one place to another over time (or rotating) in Unity

I have a problem with moving from one place to another in Unity over time. I would like my character to move from current position to current + 1 on Y. Unfortunately, looks like it does not get the current position properly or something, since if I debug what I wrote, it says that the magnitude is always 1, so the point is moving with me. Shouldn't it just check the current position and add 1 to Y, move to that position and then check again? I have no idea what's wrong with this code, or if it's strictly connected with how Unity checks positions and things in real time?
public bool moving = false;
private Vector3 dir;
void FrontMovement()
{
Vector3 movement = new Vector3(-Mathf.Sin(transform.eulerAngles.z * Mathf.PI / 180), Mathf.Cos(transform.eulerAngles.z * Mathf.PI / 180), 0f); // always moving front, even after rotation
if (moving == false)
{
dir = movement - transform.position;
moving = true;
return;
}
transform.Translate(dir.normalized * Time.deltaTime);
if(dir.magnitude <= Time.deltaTime)
{
Debug.Log("Finished movement");
moving = false;
}
}
void FixedUpdate()
{
Debug.Log(dir.magnitude);
FrontMovement();
}
I would also like to know how to do rotations over time.
https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
lerp also works for rotations
// Movement speed in units per second.
public float speed = 1.0F;
// Time when the movement started.
private float startTime;
// Total distance between the markers.
private float journeyLength;
void StartMoving() {
// Keep a note of the time the movement started.
startTime = Time.time;
Vector3 modifiedPosition = transform.position;
transform.position.y += 1.0f;
// Calculate the journey length.
journeyLength = Vector3.Distance(transform.position, modifiedPosition.position);
moving = true;
}
// Move to the target end position.
void Update()
{
if (moving) {
// Distance moved equals elapsed time times speed..
float distCovered = (Time.time - startTime) * speed;
// Fraction of journey completed equals current distance divided by total distance.
float fractionOfJourney = distCovered / journeyLength;
// Set our position as a fraction of the distance between the markers.
transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fractionOfJourney);
if (fractionOfJourney >= 1.0f) {
moving = false;
}
}
}
You could use Coroutine + Vector3.Lerp to move with a specified amount of time:
public IEnumerator MoveToPosition(Transform transform, Vector3 position, float timeToMove)
{
var currentPos = transform.position;
var t = 0f;
while(t <= 1f)
{
t += Time.deltaTime / timeToMove;
transform.position = Vector3.Lerp(currentPos, position, t);
yield return null;
}
transform.position = position;
}
you call the coroutine in Start Method
StartCoroutine(MoveToPosition(transform, newposition, timeToMove))
You could use the same logic for Rotating, with Quaternion.Lerp or Slerp and Quaternion.LookRotation, of course you have lot of sample with rotation over time on WEB!! google is your friend...
public IEnumerator RotateToDirection(Transform transform, Vector3 position, float timeToRotate)
{
var startRotation = transform.rotation;
var direction = position - transform.position;
var finalRotation = Quaternion.LookRotation(direction);
var t = 0f;
while (t <= 1f)
{
t += Time.deltaTime / timeToRotate;
transform.rotation = Quaternion.Lerp(startRotation, finalRotation, t);
yield return null;
}
transform.rotation = finalRotation;
}

Quaternion.Lerp clock rotation

I am trying to rotate the hand of the clock on click, but nothing is actually happening, none of the arrows is actually moving so I probably did something wrong... any help would be much appreciated, thank you
script below
public class Clock : MonoBehaviour {
public GameObject minuteHand;
public GameObject hourHand;
private Quaternion targetRotation;
float speed = 0.1f;
void Start()
{
targetRotation = transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
minuteHand.transform.rotation = Quaternion.Lerp(minuteHand.transform.rotation, targetRotation, Time.deltaTime * speed);
}
} }
Your code is only executed exactly in one single frame when the mouse button goes down.
Also that is not how Lerp works. Lerp expects a factor between 0 and 1 and interpolates both values. If you multiply your speed (0.1) and the Time.deltaTime which for 60FPS has a value of about 1/60f = 0.017f you get a resulting factor of about 0.0017f => You will always stay pretty close to the first value
especially since additionally your targetRotation always equals the current transform.rotation!
I assume what you wanted is: Every click move the minute 6° ahead (360°/60 minutes = 6°/minute).
Once a full circle is done move the hour 30° ahead (360°/12 hours = 30°/hour)
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
// Store original orientations
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// First calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12)
{
hours = 0;
}
}
// Now update the rotations with the new time
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
minuteHand.transform.rotation = targetMinuteRotation;
hourHand.transform.rotation = targetHourRotation;
}
}
}
This would make the clock "jump" to the target rotations. If what you rather wanted is a smooth rotation (what I assume from the usage of Lerp) I would probably use a Coroutine for that:
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
float speed = 0.1f;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// cancel the current routines
StopAllCoroutines();
// calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12) hours = 0;
}
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
// This time instead of directly setting the values start coroutines
// to rotate the hands smoothly according to the given speed
StartCoroutine (RotateTo(minuteHand, targetMinuteRotation));
StartCoroutine (RotateTo(hourHand, targetHourRotation));
}
}
// rotate the given object to the given target rotation
// according to the given speed
private IEnumerator RotateTo(GameObject obj, Quaternion targetRotation)
{
var targetTransform = obj.transform;
var current = targetTransform.rotation;
// I your are not rotating on the Z axis change this accordingly to your needs
var difference = targetRotation.eulerAngels.z - current.eulerAngles.z;
if(Mathf.Approximately(0, difference)) yield break;
var duration = difference / speed;
var timePassed = 0f;
while(timePassed <= duration)
{
var factor = timePassed / duration;
targetTransform.rotation = Quaternion.Lerp(current, targetRotation, factor);
timePassed += Time.deltaTime;
yield return null;
}
// t be sure set the final rotation once in the end
targetTransform.rotation = targetRotation;
}
}
Typed on smartphone but I hope the idea gets clear
For me only this works. You can't modify speed to make it even slower, but it looks fine (may be it will be helpful to someone)
float speed = 0.1f //how fast rotate
private void FixedUpdate()
{
nextRot = hour * -30;
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, nextRot), speed);
}

eulerAngles from Vector3 results in strange rotation

I'm trying to change the eulerAngle X of a camera rotation while keeping y and z at 0.
However, the following IEnumerator results in strange eulerAngles like 10, -74.653, 0.
I don't understand how the y value can change within the following function:
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
for (float t = 0f; t < duration; t += Time.deltaTime)
{
float f = Mathf.Lerp(camera.transform.eulerAngles.x, 10, t / duration);
Vector3 vNew = new Vector3(f, 0, 0);
camera.transform.eulerAngles = vNew;
yield return 0;
}
}
Isn't this strange? I never change the Y and Z values!
I only want to change the X rotation (eulerAngle.x) from its current value to 10.
Thank you for the help!
You are setting the eulerAngles but that will result in different localEulerAngles which are indicated by the red box in your image. If the object has any ancestors that are rotated, they will probably not match!
To fix your immediate problem, you could use localEulerAngles instead of eulerAngles:
float f = Mathf.Lerp(camera.transform.localEulerAngles.x, 10, t / duration);
Vector3 vNew = new Vector3(f, 0, 0);
camera.transform.localEulerAngles= vNew;
The problem with this is that it does not account for the ability to go from 359 degrees around to 0 degrees. Better yet would be to use Quaternion.Euler and Quaternion.Slerp to use Quaternions rather than Euler angles:
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
Quaternion startRotation = camera.transform.localRotation;
Quaternion goalRotation = Quaternion.Euler(10f, 0f, 0f);
for (float t = 0f; t < duration; t += Time.deltaTime)
{
camera.transform.localRotation = Quaternion.Slerp(startRotation, goalRotation, t/duration);
yield return 0;
}
camera.transform.localRotation = goalRotation;
}
Unity uses two representation of rotation, position, eulerAngles, etc
one is in worldspace
the other is in local space
The values not including local in their name are in world space.
If your object has than any parents that are rotated/scaled/translated you won't see the values you set in Unity since the Transform inspector displays the local coordinates.
If you want to set the local coordinates to the exact values instead use localPosition, localRotation or localEulerAngles instead.
For me it looks like you want to rotate the Camera around its local x axis by 10° in 0.5 secons.
So I think you could instead do it like
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
float initialRotationX = camera.transform.localEulerAngles.x;
float targetRotationX = 10;
for (float t = 0f; t < duration; t += Time.deltaTime)
{
float currentX = Mathf.Lerp(initialRotationX, targetRotationX, t / duration);
camera.transform.localEulerAngles = new Vector3(currentX , 0, 0);
// Which would be the same as using
// camera.transform.localRotation = Quaternion.Euler(new Vector3(currentX, 0, 0));
yield return null;
}
// to be sure you have no overshooting you could set the target rotation fix here as well
camera.transform.localEulerAngles = new Vector3(targetRotation, 0 ,0);
// or
// camera.transform.localRotation = Quaternion.Euler(new Vector3(targetRotation, 0, 0));
}

How to move 2D Object within camera view boundary

I have a scene that my camera doesn't follow my player. When player reaches the end of camera I want player to can't go further (out of camera view). How can I do this?
My codes for movement
public class PlayerBlueController : MonoBehaviour {
public float speed;
private float x;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
x = Input.GetAxis ("Horizontal") / 100 * speed;
transform.Translate (x,0,0);
}
}
As you can see from this. It gets out of camera's view.
I noticed you used a Collider2D. You should be using Rigidbody2D.MovePosition instead of transform.Translate or you'll likely run into issues when transform.Translate is used.
1.Take the final move position and convert it to new position in ViewPortPoint with Camera.main.WorldToViewportPoint
2.Apply a limit with Mathf.Clamp to the result in #1.
3.Convert the ViewPortPoint back to world point with Camera.main.ViewportToWorldPoint.
4.Finally, move it with Rigidbody2D.MovePosition.
The code below is modified from this answer to include restriction to screen boundary.
Move without Rigidbody:
Use only if collision and physics are NOT required:
public float speed = 100;
public Transform obj;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
Vector3 newPos = obj.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
obj.position = Camera.main.ViewportToWorldPoint(camViewPoint);
}
Move Object with Rigidbody2D:
Use if collision and physics are required:
public float speed = 100;
public Rigidbody2D rb;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
//rb.MovePosition(rb.transform.position + tempVect);
Vector3 newPos = rb.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
Vector3 finalPos = Camera.main.ViewportToWorldPoint(camViewPoint);
rb.MovePosition(finalPos);
}
image not respond .
but you can check player location
x = Input.GetAxis ("Horizontal") / 100 * speed;
if(gameobject.transform.x > someValue)
x=0
gameobject will be OBJECT in scene that u attach class to it.
another way is place 2 empty gameobject with collider as invisibleWall and get collider to player
Possible solution is:
1.Get the coordinates of your screen cornes (top left, top right, bottom left, bottom right). You can get this coordinates using Screen.height and Screen.width.
2.Convert this coordinates using the camera you need with Camera.ScreenToWorldPoint.
3.Get your player coordinates and check that they are inside the rect which is formed by 4 coordinates of the screen corners.
You need to limit your transform's position based on the edges of the camera. Here is an answer describing the different coordinate systems in unity
You're probably looking to do something like this:
float xMin = Camera.main.ViewportToWorldPoint(Vector3.zero).x;
float xMax = Camera.main.ViewportToWorldPoint(Vector3.one).x;
Vector3 currentPos = transform.position;
float dx = Input.GetAxis ("Horizontal") / 100 * speed;
Vector3 desiredPos = new Vector3(currentPos.x + dx, currentPos.y, currentPos.z);
Vector3 realPos = desiredPos;
if(desiredPos.x > xMax)
realPos.x = xMax;
else if(desiredPos.x < xMin)
realPos.x = xMin;
transform.position = realPos;
Read up here for more info on ViewportToWorldPoint(), it's extremely useful to become comfortable with the different coordinate spaces and how you can convert between them.

Keeping my object from rolling out of the screen

I am using the tilt function on a phone to control an object to roll left and right. I do not want it roll anything beyond the screen width.
As in the simple illustration below, the dotted lines represent the width of the screen. The 'O' is the object and the Max signs indicate the maximum point the object is allowed to roll to.
Max--------O--------Max
But currently using my code, the object still rolls out of the screen. Also tried testing both height n width and ended up the same result where the object rolls out of the screen. Please advice what I am doing wrong. Thank you.
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
if (!(Mathf.Round(dir.x) > Mathf.Round(Screen.width/2)) || !(Mathf.Round(dir.x) < -Mathf.Round(Screen.width/2)))
{
transform.Translate(dir * speed);
}
}
**Updated
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
//transform.Translate(dir * speed);
if (transform.position.x < 0)
{
transform.position = new Vector3(0, this.transform.position.y, this.transform.position.z);
}
else if (transform.position.x > Screen.width)
{
transform.position = new Vector3(Screen.width, this.transform.position.y, this.transform.position.z);
}
else
{
transform.Translate(dir * speed);
}
}
I think thereare several ways you can go about checking the transfomrs position.
first off if you were using a 2d camera you could use a method like
leftBounds = Camera.x - (Camera.pixelWidth/2);
however because ortho camera angles are not set at any particulare size at x distace from camera they are hard to calculate.
i have seen some instances were coliders on the camera just outside the render rand were placed as camera children
adding a colision mask to only affect the appropriate game object would be best.

Categories

Resources