Be the first to post for 'Protecting Against NaN'!

If you’re reading this, there probably aren’t very many posts yet. But don’t worry, you can be the first! Either create a new post or just reply to this one to say ‘hi’.

I’ve been patiently waiting for my lighting to generate, so I don’t want to disturb Unity right now, but it looks like we can use the Range() on the serialized field, but if we think there may be a time in the future where we generate the period in code rather than from the inspector, I also found this little treat in the float (class?):

[Range(0.00001f, 10f)] [SerializeField] float period = 2f;
//...later, i.e. in Update()
if (float.IsNaN(period)) period = 0.00001f;
4 Likes

I liked the shorter video to explain a new concept. It feels like we’re being taken into a side classroom for a moment, void of any distractions to concentrate on the new topic. I think these could be even more valuable as the course goes on and the sections get more complex.

3 Likes

I made a little more simple approach solving the challenge :smiley:

if(period > 0f) {} // move the obstacle
2 Likes

I have done this :

void Update () {
    // todo protect against period is 0.
    if (period != 0)
    {
        float cycles = Time.time / period; // grows continually from 0

        const float tau = Mathf.PI * 2; //about 6.28
        float rawSinWave = Mathf.Sin(cycles * tau); // goes from -1 to +1

        print(rawSinWave);

        movementFactor = rawSinWave / 2f + 0.5f;
        Vector3 offset = movementVector * movementFactor;
        transform.position = startingPos + offset;
    }
    else
    {
        print("Period set to 0 !");
    }
}

Seems to be working just fine. Don’t know if it encompasses every NaN cases though ! :open_mouth:

2 Likes

It should, since the only time you’re going to be dividing by zero is when period is zero! Though I may be missing some of the intricacies of Epsilon (there’s a phrase I never thought I’d say)…

I like the idea of just stopping the oscillations if period is set to zero, but also writing a log message so we can see that something unexpected occurred. Instead of using print, maybe it would make more sense use something like Debug.LogWarning()? Maybe that’s something else that’ll get touched on later in the course?

@ben I did like the shorter video format, personally. I like the idea of shorter videos that each cover an individual topic, rather than longer videos that try to cover two or three subjects at once. That said, at the rate at which you guys work to get these videos out, I think whatever makes your jobs easier is fine! :wink:

Another easy way to protect against NaN (or Inf) is to avoid the division altogether.

You can let the designer input the frequency of motion rather than the period. I don’t know if one is more natural than the other (we often think in frequency when talking about sound pitch, or frame rate so it’s not totally unnatural).

[Range(0, 3)]
[SerializeField]
float motionFrequency;

// Update is called once per frame
void Update () {
    float cycle = Time.time * motionFrequency;
    const float tau = Mathf.PI * 2f;
    
    motionFactor = 0.5f * (1.0f + Mathf.Cos(cycle * tau));

    transform.localPosition = initialPosition + motion * motionFactor;
}

I’ve specified an arbitrary range for the inspector input, there’s no use in making the frequency less than zero (it’s just going to be the same as specifying a positive number…). And then beyond a certain frequency the gameplay is just too hard so :).

I’ve noticed that if you play with the inspector value during gameplay but you die, the scene reloading causes you to lose the value you set. Maybe we’ll need to devise a way to keep the designer happy (maybe with a special designer/cheat mode that will not trigger a reload but will reset the scene to the start ?).

1 Like

Hi.

1 Like

I went with Range as well:

[Range(0.1f,1)] [SerializeField] float period = 0.5f;

@ben i rather short videos than long as a feedback. but still loving it :slight_smile:

I avoided the NaN by not dividing in the first place. Turns out that sin(x) = sin(x+tau) = sin(x+(n)tau). You just run a corrent variable to be +=time.DeltaTime*period and the resulting sin wave will be the same as if you did all the extra math, but with no NaN

1 Like

void Update ()
{
// todo protect against period is zero
float cycles;
if (period != 0f)
{
cycles = Time.time / period; // grows continually from 0
}
else
{
cycles = -0.25f; // causes, that the movementFactor will be 0, because sin(-0.25 tau) / 2F will be -0.5
}
const float tau = Mathf.PI * 2f; // about 6.28
float rawSinWave = Mathf.Sin(cycles * tau); // goes from -1 to +1

    movementFactor = rawSinWave / 2f + 0.5f;

    Vector3 offset = movementVector * movementFactor;
    transform.position = startingPos + offset;
}

Here is what I did:
void Update () {

if (period == 0) { return; } //Prevent game from flipping if period is 0

Another way I can think of is:

  1. Create a boolean
  2. Set the boolean to true in Start()
  3. Make the Update () code work only if the boolean is true ( if (hypothethicalBool == true))
  4. Also in Update () put if (period == 0 ) {hypothethicalBool = false}

UPDATE: Never mind. First method removes the slider.

All of these solutions forget what Ben talked about with float comparisons… a very inexact science…

if(period==0) {return;}

can actually fail to prevent a NaN…

instead, as Ben’s lecture suggested, use:

 if(period<=Mathf.epsilon) {return;}

Privacy & Terms