- Home /
Control the randomness?
So i have a basic function which uses Random.Range which selects between 0 - 12 and depending on what it chooses will change how many resources a tile has. I want to be able to do is adjust the rng so it's not completely random but I have control over how rare a certain amount of resources is.
So for example there might be 80% chance a gold tile drops with 3 gold on it and another 80% chance that a food tile with 2 spawns there. The problem I'm having is that if i than set the random.range to choose between 0 and 100 to get the random chance. Surely its always going to pick the if statement thats above the other. I want to verify that btw but I'm sure code will always read line by line till it finds code to execute or break out of the loop. Or if i have a 79% and 80% chance than surely there's only a 1% chance certainty that tile will spawn depending if its less than or more than if statement.
Current Tile Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Tile : MonoBehaviour
{
public int goldValue;
public int foodValue;
public int ironValue;
public Vector3 screenPos;
public Transform textTag;
//Who owns the tile
public string playerName;
public Color tileColor;
public bool owned = false;
public int ownersPlayerID;
[Header("Color values")]
public Color goldValue1Color;
public Color goldValue2Color;
public Color goldValue3Color;
public Color goldValue4Color;
public Color foodValue1Color;
public Color foodValue2Color;
public Color foodValue3Color;
public Color foodValue4Color;
public Color ironValue1Color;
public Color ironValue2Color;
public Color ironValue3Color;
public Color ironValue4Color;
void Start()
{
textTag = gameObject.transform;
RandomiseValue();
}
void Update()
{
screenPos = Camera.main.WorldToScreenPoint (textTag.position);
if (owned == true)
{
gameObject.GetComponent<MeshRenderer> ().material.color = tileColor;
}
}
private void RandomiseValue()
{
int rng = Random.Range (0, 12);
if (rng == 0)
{
goldValue = 0;
foodValue = 0;
ironValue = 0;
gameObject.GetComponent<MeshRenderer> ().material.color = Color.gray;
}
if (rng == 1)
{
goldValue = 1;
gameObject.GetComponent<MeshRenderer> ().material.color = goldValue1Color;
}
if (rng == 2)
{
goldValue = 2;
gameObject.GetComponent<MeshRenderer> ().material.color = goldValue2Color;
}
if (rng == 3)
{
goldValue = 3;
gameObject.GetComponent<MeshRenderer> ().material.color = goldValue3Color;
}
if (rng == 4)
{
goldValue = 4;
gameObject.GetComponent<MeshRenderer> ().material.color = goldValue4Color;
}
if (rng == 5)
{
foodValue = 1;
gameObject.GetComponent<MeshRenderer> ().material.color = foodValue1Color;
}
if (rng == 6)
{
foodValue = 2;
gameObject.GetComponent<MeshRenderer> ().material.color = foodValue2Color;
}
if (rng == 7)
{
foodValue = 3;
gameObject.GetComponent<MeshRenderer> ().material.color = foodValue3Color;
}
if (rng == 8)
{
foodValue = 4;
gameObject.GetComponent<MeshRenderer> ().material.color = foodValue4Color;
}
if (rng == 9)
{
ironValue = 1;
gameObject.GetComponent<MeshRenderer> ().material.color = ironValue1Color;
}
if (rng == 10)
{
ironValue = 2;
gameObject.GetComponent<MeshRenderer> ().material.color = ironValue2Color;
}
if (rng == 11)
{
ironValue = 3;
gameObject.GetComponent<MeshRenderer> ().material.color = ironValue3Color;
}
if (rng == 12)
{
ironValue = 4;
gameObject.GetComponent<MeshRenderer> ().material.color = ironValue4Color;
}
}
public void TileOwnedBy(string name, Color color, int ID)
{
playerName = name;
tileColor = color;
ownersPlayerID = ID;
owned = true;
Debug.Log ("Owners Name " + playerName);
}
Im sorry if i worded that funny but basically Im looking for is to control how random something is? Added in the code to show what I mean.
Answer by Zarenityx · Mar 21, 2019 at 08:03 PM
It would likely be better to decouple tile generation and tile resources. This will make it MUCH easier to design for because now your probabilities are all straightforward.
To use your example, you have an 80% chance of spawning gold and an 80% chance of spawning food. (I'm ignoring the quantities for now, I'll get to those later). Now, what you've TOLD it to do is have an 80% chance of spawning gold and an 80% chance of spawning food, but, that's not actually what ends up happening. The probability actually depends on which spawn you check first. From your code, it doesn't look like you ever have a tile that has multiple kinds of resource on it at the same time. Meaning, if the tile has gold, it doesn't have food.
So, let's say, you check gold first, then food. So you calculate gold, which has an 80% chance to be gold, and therefore 20% chance to be anything else. If it is something else, it's got an 80% chance to be food, but this only happens 20% of the time, so the tile really has a 16% chance of happening. That's not a lot of food.
Forgive me if this is not the case, and you can have multiple types of resources on one tile. Regardless, it'll still make it easier because you can work with the actual probabilities.
The solution:
Use a random chance to determine if there IS a tile to begin with. Not sure how you generate your worlds so I won't get into detail on this one.
Assuming you DO HAVE a tile:
have an array of the different things the tile can be and the probability (or rather, the weight) of these things that the tile can be.Add up all of these weights, and generate a random float between 0 and that sum.
Loop through the different possibilities, regenerating this random float, and check if the random number is less than the weight on that possibility. If it is, then make the tile that type and break out of the loop.
If you go through the entire loop and still don't have anything generated, the most technically accurate thing to do would be to repeat the loop, but eventually that just takes too much time. If, after a few tries (or even one, depending on the fidelity to probability you want), you can just choose one at random by picking an int between 0 and the number of possibilities, and use that. This is the same as what you're doing basically at this point.
You have your tile.
But what about the quantities?
You could in theory create a separate possibility for each quantity of each item, but that's tedious and not easy to extend. So, one way to improve this is to let each possibility have its own array of quantities with their own weights. Then:
Assuming you have a tile, and you have decided on what resource goes on it as per the above:
Sum up the weights in the array of quantities
Loop through again, like above, regenerating a random float between 0 and this sum, and determine what quantity to assign
Now, you have a tile with a percent to exist, a percent to be a certain resource, and a percent to be a certain quantity of said resource.
mmmhhh yeh that makes a lot of sense. I was looking into weights and stuff and it made sense for enemy loot bags and stuff of that sort but I wasn't totally sure on how to make it work for my game but you explaining this has sparked the old brain into gear.
So lets check i understand before i make an idiot of myself. which is quite common. lets say gold has a 50% and food has 40%. Add them together to get 90. i than use random.range of 0 to 90 than anything less than or 50 is gold and 50 and above is food. but now the question on my $$anonymous$$d is how would it never spawn something? I fear im missing something obvious ain't i xD.
just twigged in my head i think. but my brain is having a stupid :L. one of those days where things don't sink in
btw to make something clear a tile has to always spawn as its a chess inspired game so the full board has to spawn so a tile doesn't have a random chance to spawn but rather the resources on it do. sorry i didnt include that in the question/
Answer by fafase · Mar 22, 2019 at 06:47 AM
You have gold food and iron. Now let's say you want 80% chance getting food, 50% getting iron and 30% getting gold (considering rarity I'd say):
bool GetItem(int percent)
{
int rand = Random.Range(0,100); // 100 is excluded
return rand < percent; // is rand between 0 and percent
}
and you can now check for each:
void SetResource()
{
bool food = GetItem(80);
if(food){ AddFood(); }
bool iron = GetItem(50);
if(iron) { AddIron(); }
bool gold = GetItem(30);
if(gold) { AddGold(); }
}
You can extend the concept to have no gold as well
void SetGoldResource()
{
int rand = Random.Range(0,10);
if(rand < 2) { return; } // 20% chancefor no gold
else if(rand >=2 && rand < 6) { AddGold(1); } // 40% for 1
else if(rand >=6 && rand < 9) { AddGold(2); } // 30% for 2
else { AddGold(3); } // 10% for 3
}
You could look into an introduction to probability to see how to extend with more precision but this should be enough to begin with.
Thank you for your answer. I'll be trying this out along with different approaches as it seems I've got a few different approaches to try. The thing that jumps out to me about this approach is that its easily adjustable and shouldn't be too hard to implement so I'll be giving it a go later.
Your answer
![](https://koobas.hobune.stream/wayback/20220612193956im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Why is Random.Range exclusive for integers but inclusive for floats? 4 Answers
How to make Random.Range() step by a certain amount? 1 Answer
Hey! Im a beginner and need help in randomizing. (Im making a 2d game in Unity) 1 Answer