I am generating a random number between a range but I want the number to not be 0. It can be 0.1, 0.2...etc but not 0. How do I do this?
public float selectedValue;
void Start()
{
selectedValue = Random.Range(-0.5f, 0.5f);
}
Keep finding random values until its value is not zero
float RandomNumExceptZero (float min, float max){
float randomNum = 0.0f;
do {
randomNum = Random.Range (min, max);
} while (randomNum == 0.0f );
return randomNum ;
}
Building on the suggestion of #Psi you could do this:
public float selectedValue;
void Start()
{
selectedValue = Random.Range(float.MinValue, 0.5f)*(Random.value > 0.5f?1:-1);
}
Random.Range() takes in 2 arguments in which the second argument is exclusive. You can use it for your advantage by excluding the value 0. The logic used is to find a random value between -0.5f and 0 (exclusive). Use another randomizer to get either a positive value or a negative value
public float selectedValue;
void Start()
{
selectedValue = Random.Range(-0.5f, 0);
int sign = Random.Range(0, 2);
// the value sign can be either 0 or 1
// if the sign is positive, invert the sign of selectedValue
if(sign) selectedValue = -selectedValue;
}
I just want to point out that there are 2,113,929,216 (*) float values in the interval [-0.5, 0.5) which gives a ≈ 0.000000047305 % chance that exactly 0.0f will be generated.
(*) found by brute force with C++ std::next_after but both implementation should follow IEEE 754 so I don't expect to be language differences in this regard, unless Unity somehow doesn't use subnormal numbers.
Well, just make if{} in Update() to pick another random number with same function if it is 0.0f. No way it will get 0.0f two times in a row
Related
I am generating a random floating value between 1.00 and 5.00. Sometimes the value comes as 1.08 or 3.09. I do not wish to have this, instead it should be 1.00 or 3.00 when it comes to such a case. That is whenever there is a decimal with 0 soon after, the value should always be .00.
Such that if X.0Y is a value, the final value should be X.00.
Example: value = 3.08;
output final value = 3.00
public float selectedValueRange;
void Start(){
selectedValueRange = Random.Range (1.0, 5.0+ 1.0f);
selectedValueRange = Mathf.Round (selectedValueRange * 100.0f) * 0.01f;
}
You can get rid of everything after the decimal point and then check if the difference between the new value and the previous number is less than 0.1f which means your number is in this format x.0y. If it is then reassign the new value as the random value. Something like the following code:
int number = (int)selectedValueRange;
if(selectedValueRange-number < 0.1f){
selectedValueRange = (float)number;
}
I am trying to create a program that will spawn balls from the top randomly at random times. The problem is it is not fast enough, but if I change the value to like 1/2 it spawns 50 super fast.
using System.Collections.Generic;
using UnityEngine;
public class SpawnAstroids : MonoBehaviour
{
public GameObject astriod;
public float xBounds, yBounds;
public int playerPoints = 0;
public int enemyPoints = 0;
void Start()
{
StartCoroutine(SpawnRandomGameObject());
}
IEnumerator SpawnRandomGameObject()
{
yield return new WaitForSeconds(Random.Range(1,2)); //Random.Range(1/2, 2)
Instantiate(astriod, new Vector2(Random.Range(-xBounds, xBounds), yBounds), Quaternion.identity);
StartCoroutine(SpawnRandomGameObject());
}
}
Unity C# requires that you specify whether your decimal is specifically a float or a double. Add in f to the end of each decimal number. For example: Random.Range(0.5f, 2);
(Minor Note that Random.Range is inclusive vs exclusive depending on whether you use integers or floats.)
Similarly when you define a Vector2 bob = new Vector2(0.5f,0);, the f is also needed to denote explicitly that it is a float.
Random.Range has two overloads.
public static float Range(float minInclusive, float maxInclusive);
and
public static int Range(int minInclusive, int maxExclusive);
you are passing in
Random.Range(1, 2);
which are two int values so the second overload is used where the result will be an int between 1 and 2 - 1 ... not many options here ;)
Also your attempt
Random.Range(1/2, 2);
are again int values! 1/2 is an integer division which results in 0! So this random can either return 0 or 1.
What you rather want to do is passing in float values like e.g.
Random.Range(1f, 2f);
which can result in any floating point value between 1 and 2 or accordingly
Random.Range(0.5f, 2);
or back to your attempt
Random.Range(1 / 2f, 2);
which now uses a float division and thereby the result is automatically a float so the first overload will be used.
In general btw there is no need to call a Coroutine recursively, you can simply loop forever and also note that Start itself can be a Coroutine like e.g.
private IEnumerator Start()
{
while(true)
{
yield return new WaitForSeconds(Random.Range(0.5f, 2f));
Instantiate(astriod, new Vector2(Random.Range(-xBounds, xBounds), yBounds), Quaternion.identity);
}
}
This is the code I wrote to spawn something randomly btw two positions but it always spawns it in the "spawnpoint2" and IDK what to do
{
public Transform spawnpoint1;
public Transform spawnpoint2;
public GameObject enemyprefab;
private void Start()
{
InvokeRepeating("spawn", 3f, 5f);
}
void spawn()
{
float randomizer= Random.Range(0f, 3f);
if (randomizer == 1f)
Instantiate(enemyprefab, spawnpoint1);
else
Instantiate(enemyprefab, spawnpoint2);
}
}
THis is the float version of the method Random.Range. You will have 1.0f sometimes, but it's pretty rare.
You would better use the int version.
// Random.Range(0f, 3f); // float version
Random.Range(0, 3); // int version
If you try to get a floating point number between 0 and 3 (inclusive) there is really a small possibility to get exactly 1.0 between all the possibile intermediate values.
You should use the integer version from Random.Range, but this version has the upper limit excluded so you should use 4 as the upper limit to get any value from 0 to 3
While it seems secondary (you check only for 1 so you will get the 1 even if the upper limit were 2) using an upper limit of 3 changes the frequences of 1 results vs other numbers and so your spawnpoint1 will be more frequent.
void spawn()
{
int randomizer= Random.Range(0, 4);
if (randomizer == 1)
Instantiate(enemyprefab, spawnpoint1);
else
Instantiate(enemyprefab, spawnpoint2);
}
I'm building a knob that can only be turned to some fixed zones..
Now I'm using math clamp for one of these zones:
float clampedAngle = Mathf.Clamp(angle, -250f, 0f);
I want it to work for multiple zones, like this:
clampedAngle = Mathf.Clamp(angle, -250f, -230f);
clampedAngle = Mathf.Clamp(angle, -100f, -45f);
clampedAngle = Mathf.Clamp(angle, -30f, 0f);
Unfortunately the code above does not work, as it will clamp to the last value. How can I clamp a value to multiple valid zones?
The tricky part of this problem is determining which range to clamp to. One approach is to find the nearest min/max bound to the value, then clamp according to the corresponding range.
Assuming that your ranges are represented as an array of value pairs (two-value arrays), we can join them together and find the nearest min/max value by adapting the approach in this answer. Then, it's fairly easy to work backwards to determine which range the min/max value is from, and clamping accordingly:
// Clamps given value to nearest of given min/max pairs
private float ClampToNearestRange(float value, float[][] ranges)
{
// First, let's flatten the values into a single list
List<float> flattenedRanges = ranges.SelectMany(item => item).ToList();
// Now, we'll find the closest value in the list, and then get its index
float nearestValue = flattenedRanges.Aggregate((x,y) => Mathf.Abs(x-value) < Mathf.Abs(y-value) ? x : y);
int valueIndex = flattenedRanges.IndexOf(nearestValue);
// With the value index, we can deduce the corresponding range index
int rangeIndex = (valueIndex % 2 == 0) ? valueIndex / 2 : (valueIndex - 1) / 2;
// Finally, we'll clamp according to the range we selected
return Mathf.Clamp(value, ranges[rangeIndex][0], ranges[rangeIndex][1]);
}
You would then use the method like so:
// First, declaring your ranges somewhere in your class
float[] range1 = new float[]{0, 60};
float[] range2 = new float[]{80, 100};
float[] range3 = new float[]{150, 200};
float[][] ranges;
Start ()
{
ranges = new float[][]{range1, range2, range3};
float clampedAngle1 = ClampToNearestRange(120, ranges); // returns 100
float clampedAngle2 = ClampToNearestRange(126, ranges); // returns 150
float clampedAngle3 = ClampToNearestRange(170, ranges); // returns 170
}
Note: This does use LINQ, meaning if you need to do this often you might want to expand the logic into more Unity-friendly loops. Won't be as succinct, but it could affect your game performance.
Hope this helps! Let me know if you have any questions.
Bear with me for a minute.
I have a method that should add or subtract a fixed value, depending on a given input.
I know that my max value is 1.0f, the min value is 0.0f. The fixed value is 0.1f.
Now if the input value is 1.0f the method should subtract until the value is 0f. If the input value is 0f the method should add 0.1f until the value is 1.0f.
So a working method for 0f to 1f would be:
void Foo(float input) {
float step = .1f;
for (float i=0f; i<=1f; i += step) {
input = i;
}
}
Obviously I could have an if-statement checking the input value, but is there another way to achieve this within one method? I feel like I'm just missing a very basic arithmetical operation here.
just a suggestion
I think step could be adjusted to be positive or negative based on the initial value, and use a do-while so it runs the first time, until it hits the final value.
Based on your code
void Foo(float input) {
float step = input == 0f ? .1f : -0.1f;
do
{
input = input + step
} while (input > 0f && input < 1.0f);
}
If you want to really avoid using an if statement at all for the step, you can actually derive it from the input directly. In turn you might get some extra numerical errors, but as you're using floats already this might not be of your concern.
void foo(float input)
{
float step = (.5f - input)/5.f;
do
{
input += step;
} while (input > 0.0f && input < 1.0f);
}
Running it on my machine gives me
foo(1.0f) --> -7.45058e-08
foo(0.0f) --> 1