- Home /

# Crosshair Sway

I am trying to find a way to randomize a camera's rotation with certain parameters to simulate a crosshair sway while zooming in. I am currently using mathf.sin to keep the sway smooth and randomizing the amplitude every so often. This works fine, however, when I zoom in and start the script, my camera rotation snaps to wherever the curve is during that frame. It also seems that the sin curve never stops even if the script is disabled, so when i zoom in at a random time the rotation snaps to the curves position. I think it's because I am editing the localRotation manually which makes it snap immediately. Is there anyway to start the curve from the center at 0,0,0 on enabling the script? Or is there a better way to go about smoothly randomizing camera rotation within parameters that I have overlooked?

```
using UnityEngine;
using System.Collections;
public class Sway : MonoBehaviour {
public float speed = 0.7f;
float maxRotationy = 1f;
float maxRotationx = 1f;
public float amplitude;
public bool holdBreath = true;
void OnEnable()
{
//make mathf.sin == transform.rotation.x/.y/.z?
}
void Update()
{
if (!holdBreath) {
transform.localRotation = Quaternion.Euler (maxRotationx * Mathf.Sin (Time.time * speed * 2) * amplitude, maxRotationy * Mathf.Sin (Time.time * speed), 0f);
if (transform.localRotation.eulerAngles.x <= 0.005f && transform.rotation.eulerAngles.x >= -0.005f) {
amplitude = Random.Range (-0.25f, 0.5f);
}
}
}
}
```

I also enable/disable the script completely with a "Zoom" button. But, even when the script is disabled the sin wave continues to run so when enabled the transform.rotation snaps to that wave position during that frame.

**Answer** by Cresspresso
·
Oct 08, 2016 at 09:49 PM

This is my first time answering a question on Unity Answers, so here goes.

The problem with the 'sine wave continuing to run' is that you are passing Time.time into the Mathf.Sin function.

One way to overcome this problem is to reset the camera's local rotation to look straight forward when holdBreath is true. To make the transition seem smooth, we can set a float 'fraction' to multiply by maxRotationx/y, so when fraction==0 the camera is centered, and when fraction==1 it is at maximum sway.

Add these fields below [ public bool holdBreath = true; ]

```
public float returnTime = 0.5f;
private float fraction = 0f;
```

Then add these in Update()

```
if (holdBreath)
fraction = Mathf.Clamp(fraction - 1f/returnTime * Time.deltaTime, 0f, 1f);
else
fraction = Mathf.Clamp(fraction + 1f/returnTime * Time.deltaTime, 0f, 1f);
```

Then change the original [ if (!holdBreath) ] to

```
if (fraction > 0f)
```

And then multiply the x and y components by [ fraction ] like so

```
transform.localRotation = Quaternion.Euler(maxRotationx * Mathf.Sin(Time.time * speed * 2) * amplitude * fraction, maxRotationy * Mathf.Sin(Time.time * speed) * fraction, 0f);
```

And if the script is disabled, we need to re-center the camera. Replace OnEnabled() with this

```
void OnDisable()
{
transform.localRotation = Quaternion.identity;
fraction = 0f;
}
```

The final script should look like this

```
using UnityEngine;
public class Sway : MonoBehaviour
{
public float speed = 0.7f;
float maxRotationy = 1f;
float maxRotationx = 1f;
public float amplitude;
public bool holdBreath = true;
public float returnTime = 0.5f;
private float fraction = 0f;
void OnDisable()
{
transform.localRotation = Quaternion.identity;
fraction = 0f;
}
void Update()
{
if (holdBreath)
{
fraction = Mathf.Clamp(fraction - 1f/returnTime * Time.deltaTime, 0f, 1f);
}
else
{
fraction = Mathf.Clamp(fraction + 1f/returnTime * Time.deltaTime, 0f, 1f);
}
if (fraction > 0f)
{
transform.localRotation = Quaternion.Euler(maxRotationx * Mathf.Sin(Time.time * speed * 2) * amplitude * fraction, maxRotationy * Mathf.Sin(Time.time * speed) * fraction, 0f);
if (transform.localRotation.eulerAngles.x <= 0.005f && transform.rotation.eulerAngles.x >= -0.005f)
{
amplitude = Random.Range(-0.25f, 0.5f);
}
}
}
}
```

'fraction' could be smoothed with an AnimationCurve, but those are the basics.

You were spot on with this answer for what I am trying to accomplish. The Time.time and fraction really made it work and there is no more snapping. Thank you for your response!

The only problem is when bool HoldBreath is true the crosshair is centered. I am trying to freeze/hold the exact position when HoldBreath was set true and then continue back on the sway once it is set false. If I set eulerangles to transform.rotation when holdbreath is true, it goes back to snapping.

I have reworked it from scratch. When breath is held, it will instantly stop moving, and when breath is no longer held it will continue from where it left off.

When the script is enabled (zoom in) it will begin its sway from a random position. When it is disabled (zoom out) it will re-center the camera.

I also changed the amplitude to be randomly chosen from just positive values; a range of both negative and positive values can make jagged movements.

```
using UnityEngine;
public class Sway : MonoBehaviour
{
public float speed = 0.7f;
float maxRotationy = 1f;
float maxRotationx = 1f;
public float amplitude;
public bool holdBreath = true;
private float timeElapsed = 0f;
void OnEnable()
{
timeElapsed = Time.time; // set to Time.time or any random value
UpdateRotation();
}
void OnDisable()
{
transform.localRotation = Quaternion.identity; // re-center camera when zoomed out
}
void Update()
{
if (!holdBreath)
timeElapsed += Time.deltaTime; // only increase elapsed time if not holding breath
UpdateRotation();
}
void UpdateRotation()
{
transform.localRotation = Quaternion.Euler(maxRotationx * Mathf.Sin(timeElapsed * speed * 2) * amplitude, maxRotationy * Mathf.Sin(timeElapsed * speed), 0f);
if (transform.localRotation.eulerAngles.x <= 0.005f && transform.rotation.eulerAngles.x >= -0.005f)
{
amplitude = Random.Range(0.1f, 0.5f);
}
}
}
```

Thank you again! It all works perfect. I'm not sure how or if I can Accept/Upvote the commented script, but thank you nonetheless. I truly didn't even think about adding a timer to keep track of the script time.

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

Can't display my Countdown timer text on my end menu. (newbie needing help) 1 Answer

MonoDevelop won't open on my mac 0 Answers

Integer value randomly multiples itself by 3 or 2 for seemingly no reason. 2 Answers

CollectPapers script doesn't work in Unity5 0 Answers

Array Declaration & Initialization- Inside and Outside Functions 1 Answer