Can't understand why variables have such values

I change the damage that is used in the bullet, I don’t understand why I get such values in console.

When damage is increased project crushes with this error:

FormatException: Input string was not in a correct format. System.Number.ThrowOverflowOrFormatException (System.Boolean overflow, System.String overflowResourceKey) (at :0) System.Number.ParseSingle (System.ReadOnlySpan`1[T] value, System.Globalization.NumberStyles styles, System.Globalization.NumberFormatInfo info) (at :0)

using UnityEngine;

public class Bullet : MonoBehaviour
{
public float _damage;//_damage = 1

private float _currentDamage;

private void Start()
{
    _currentDamage = _damage;
}

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.TryGetComponent(out Enemy enemy))
    {
        enemy.GetDamage(_currentDamage);// works right and attacks by value of _damage
        Destroy(gameObject);
    }
}

public void IncreaseDamage(float damageMultiplier)
{
    float damageLong = _currentDamage * damageMultiplier;

    Debug.Log(_currentDamage + " " + damageMultiplier);//shows: 0 1.2

    string str = damageLong.ToString("#.##");

    Debug.Log(str);//shows: "nothing"

    _currentDamage = float.Parse(str);
}
}

What is calling IncreaseDamage, and how is it being called? Perhaps you have an infinite loop causing the float to overflow?

1 Like

May i ask why we are calculating a number, just to convert it to a string, to format it, and then parse it back to a number? I assume you want to get rid of all but 2 decimal places. But why? You arent actually multiplying with the damageMultiplier then anymore, but a value thats on average slightly smaller. Shouldnt the actual damage value represent the correct result of your calculation? If you then display that damage value somewhere, then you would want to format it to a more humanly readable format. Why do you care about truncating a value thats only used internally for calculations, to make it less accurate?

The actual content of the function, other than the number truncation, can be summarized as:

_currentDamage *= damageMultiplier;

If you, for some reason, want to truncate the number right there, you might want to stick to math, not strings, since strings are kinda slow in comparison. How to round off a float to 2 decimal places? | Microsoft Learn

To actually debug your code i would suggest printing more values first, then testing what might go wrong. You wrote that _currentDamage is 0, and damageMultiplier is 1.2, so is damageLong 0 as we would expect? If so, does your ToString formatting line also crash if you execute it individually, somewhere else, on a hardcoded float with value 0f? I doubt we would see a formatting issue or an overflow error with a value of 0f (tho i didnt check for cornercases), but since you never actually printed the value of damageLong im just guessing around here.

2 Likes

It’s called from other script, when button is pressed:

    public void Power()
    {
        if (_slime.points > _powerPrice)
        {
            _bullet.IncreaseDamage(1.2f);
        }
    }

Yes i did this strange lines just to leave two decimal place. I checked, yes damageLong is equal to 0.

1 Like

I initialize _damage value in inspector, but as i understand main problem will happen because this script attached to bullet which appears and get destroyed with its script, so value _currentDamage won’t be recorded anywhere, my idea was to increase damage other time but for every bullet its going to be different value as i understand, so i should change construction of increasing damage

I believe this is a language barrier problem, but do you want damage to increase for all bullet? Or are you explaining that you dont want that? Unrelated to that, my main question was why you truncate the number to 2 decimal places, instead of simply leaving it with whatever precise value it would have after the calculation.

Yes i want increase damage for all bullet, i truncate the number to 2 decimal place because i show this number in UI when bullet damages enemy.

A FormatException means that the string being generated is incorrectly formatted. One potential reason may be your culture info (ie commas instead of periods). Try seeing if this fixes the problem for you:

using System.Globalization;
public void IncreaseDamage(float damageMultiplier)
{
    float damageLong = _currentDamage * damageMultiplier;

    Debug.Log(_currentDamage + " " + damageMultiplier); //shows: 0 1.2

    string str = damageLong.ToString("#.##", CultureInfo.InvariantCulture);

    Debug.Log(str); //should now show a value

    _currentDamage = float.Parse(str, CultureInfo.InvariantCulture);
}

Alternatively you can truncate the digits with some simple math (though this can show floating point inaccuracies):

public void IncreaseDamage(float damageMultiplier)
{
    float damageLong = _currentDamage * damageMultiplier;

    Debug.Log(_currentDamage + " " + damageMultiplier); //shows: 0 1.2

    float truncatedDamage = Mathf.Round(damageLong * 100f) / 100f;
    // The above line rounds the damage to two decimal places.

    Debug.Log(truncatedDamage); //should now show a value

    _currentDamage = truncatedDamage;
}
3 Likes

I mentioned this before, but you should not adjust the actual float value just because you eventually want to display it. You need to differentiate between the internal value, which you want to be precise and fast, and its external representation, which you may adjust however you want. One has nothing to do with the other, and the visual representation should not in any way affect the internal value. Grab the accurate value when you want to display it simply display the formatted string, instead of adjusting the actual underlying value.

1 Like

As everyone said before: You shouldn’t truncate using strings. This is both prone to error, as well as bad for performance. If you absolutely have to truncate (e.g. to ensure consistency) there are functions such as Math.Truncate & Math.Round.
That said; I’m guessing you’re outputting .ToString("#.##") with a ‘.’, whereas the float.Parse(str) is expecting a ‘,’.
Using CultureInfo.InvariantCulture, like @Ryiah suggested, should resolve this.

1 Like

I’ve done it like this:

_slimeShooting.damage = (float)(Math.Round((double)longDamage, 2));