I am a unity newbie, can I get some help?
So basically I created a pendulum, but i added some function where, if it reached the maximum height possible, the Y axis of the pendulum will rotate by 180 degrees but the Y axis wasn't rotating.
Here's the code:
using UnityEngine;
public class PendulumScript : MonoBehaviour
{
[SerializeField] public float speed = 1.5f;
public float limit = 75f;
public bool randomStart = false;
private float random = 0;
private bool limitReached = false;
private Quaternion originalRotation;
void Awake()
{
if (randomStart)
{
random = Random.Range(0f, 1f);
}
// Save the original rotation
originalRotation = transform.localRotation;
}
void Update()
{
float angle = limit * Mathf.Sin(Time.time + random * speed);
transform.localRotation = Quaternion.Euler(0, 0, angle);
if (!limitReached && (angle == limit))
{
// Rotate around the Y-axis by 180 degrees
transform.Rotate(0, 180 * Time.time, 0);
limitReached = true;
limit *= -1; // turns limit into negative
}
else if (limitReached && (angle == -limit))
{
// Reset to original rotation which is Y = 0
transform.localRotation = originalRotation;
limitReached = false;
limit *= -1; // turns limit into positive
}
}
}
i was trying the rotation using if !limitreached and else if limitreached
and it does rotate but flickering since its doing the rotation all the time, thats why I added another condition, but it appears the best condition that i could think of is not working, im hoping to figure out on whats wrong with the (angle == limit)
condition that it's not being satisfied or maybe what really is the reason why its not working.
So if I got that right what you want is actually two rotations
There are various issues with your approach
This
transform.localRotation = Quaternion.Euler(0, 0, angle);
Does NOT only rotate on the Z axis
! It rather hard resets y = 0
.
Never compare float
using ==
!
Due to precision limits this might never ever be true
Your condition is also only true
during max one single frame.
You rather want to trigger a continuous rotation around Y
I also think that
Time.time + random * speed
is not quite what you wanted to use but rather e.g.
(Time.time + random) * speed
And
transform.Rotate(0, 180 * Time.time, 0);
Does NOT rotate by 180° ... the more time has passed the more it will rotate here!
I would actually treat this as two individual rotations and handle them separately:
public class PendulumScript : MonoBehaviour
{
public float speed = 1.5f;
public float limit = 75f;
public bool randomStart = false;
public float yRotationSpeed = 45.0f; // degrees per second
private float rotationZ;
private float rotationY;
private bool performingYFlip;
private float time;
private float targetYRotation;
void Awake()
{
// instead of selecting a random sin value
// I would rather select a random start time
// This way you have a clear check when enough time has passed to
// perform the flip
if(randomStart)
{
// sinus range is in radians => full cycle every 2π
time = Random.Range(0f, 2 * Mathf.PI) * speed;
// if required could also adjust the initial targetYRotation based on the random time here
}
}
void Update()
{
// simply increase the timer by the time passed since last frame
time += Time.deltaTime * speed;
// calculate Z rotation as before
rotationZ = Mathf.Sin(time) * limit;
// Use approximate equality for angles
// note that due to the sinus even this might never be true within a frame
//if(Mathf.Approximately(rotationZ, limit))
// so you might even use a wider range like e.g.
if(!performingYFlip && Mathf.Abs(rotationZ - limit) <= /*Some Threshold in angles*/ 5f)
{
// initiate a flip
performingYFlip = true;
targetYRotation += 180f;
}
if(performingYFlip)
{
// continuous Y rotation as long as performingYFlip remains true
yRotation = Mathf.MoveTowards(yRotation, targetYRotation, yRotationSpeed * Time.deltaTime);
if(Mathf.Approximately(yRotation, targetYRotation))
{
performingYFlip = false;
}
}
// and finally apply both rotations together
transform.rotation = Quaternion.Euler(0, yRotation, zRotation);
}
}