Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Sarthak123 · Apr 20, 2015 at 10:46 AM · randomrandomizerandomizationrandom gen

Random Generation Algorithm Error

I am creating a 2d game where i am instantiating(Infinite Terrain Generation) blocks as "Rock". I have a script attached to my rocks, which identifies whether the rock will be an normal rock or ore, the attached script is -

 #pragma strict
 
 var ores : Sprite[]; // ore sprites
 var oreDat : int[]; // not relevant
 var oreHeal : int[]; // not relevant
 var oreChance : float[]; // stores chances for each ore
 var sel : float;
 
 private var health : int = 1;
 private var dat : int = 0;
 
 function Start()
 {
     sel = 0.0;
     gen();
 }
 function Mine() // not relevant
 {
     health--;
     if (health <= 0)
     {
         Destroy(gameObject);
     }
     
 }
 
 function gen()
 {
     sel = Random.value; // generates a random value between 0 and 1
     for (var i : int = (ores.Length-1); i >= 0; i--)
     {
         if (sel <= oreChance[i])
         {
             GetComponent(SpriteRenderer).sprite = ores[i];
             health = oreHeal[i];
             dat = oreDat[i];
             break;
         }
     }
 }

in my OreChance variable i have arranged chances of my ores ( in order coal, iron, gold, diamond) as 0.1, 0.001, 0.0005, 0.0001

It works fine but the error i encounter is, when i hit play and move it starts generating ores in a repetition, like iron after every 2 blocks, it varies everytime i hit play. Also i have noticed it creates ores even when the sel(selection chance) is more than ore chance.

this is what i get when i just start game, as you can see everything is fine... alt text

this is what happens when i walk ahead(any direction)...as you can see, ores are occuring in a repetition and even though the sel chance is greater than the ore chance. To say more specifically, the new blocks instantiated are exactly as previous blocks. alt text I have tried many solutions already, like using Random.Range ,etc. but every solutions gives this problem.

As already mentioned i am using infinite terrain generation, so if needed i can also attach it's script also.

snip1.png (343.3 kB)
snip2.png (358.6 kB)
Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image JoeStrout · Apr 20, 2015 at 05:28 PM 0
Share

What do your oreChance[] values look like? Unless these are sorted in increasing order, with the last one set to 1.0, this will not work. And in that case they're misnamed; they're not chances, they're the cumulative chance including all previous ores.

If they really are chance values, then the code is incorrect, because you're just comparing sel to each one. You should add "sel -= oreChance[i]" inside the for loop (but outside the if). And then of course you must make sure that your oreChance[i] values add up to 1.

avatar image Sarthak123 · Apr 21, 2015 at 05:20 AM 0
Share

I have already mentioned, oreChances are in order Coal, Iron, Gold, Diamond with their respective chances as 0.1, 0.001, 0.0005, 0.0001. And why should i set the last chance to 1, because by default my "Rock" is a rock, so if sel does not matches to any ore, it will remain a rock. I runnning the loop in reverse, where it checks the diamond first, and i am also using 'break' statement to prevent less valuable ore from instantiating if the sel matches with a high value ore...

but is this relatied to repetition ? also, can you please clarify sel -= oreChance[i]...

avatar image JoeStrout · Apr 21, 2015 at 01:22 PM 0
Share

O$$anonymous$$, sorry I missed it where you said it before. But yes, those are true probabilities, which means your code is wrong and you need to change it as described above. And you're right, if you're O$$anonymous$$ with it matching rock if it doesn't match anything else, then you don't need to include that (and the probabilities don't need to add up to 1). I'll post this as an answer so you can accept it. :)

avatar image JoeStrout · Apr 21, 2015 at 01:28 PM 0
Share

(Also note that it doesn't matter whether you loop over your ores forward or reverse.)

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Apr 21, 2015 at 04:26 PM

Your problem clearly is in the way you instantiate your chunks. You said you instantiate a prefab, but somehow you seem to replaced that reference with the chunk generated last. That means when you instantiate a new chunk you get a copy of your old chunk. Since you never set the base material explicitly ("rock" i guess), each tile will initially be what has been generated in the last chunk. Furthermore each new chunk will of course create new ores.

Solutions:

  • Don't overwrite your prefab reference. Keep in mind that a prefab can't hold a reference to itself. Self-references will be replaced with the instantiated reference when the prefab is instantiated. To fix this, either store the prefab reference golbally outside of the prefab, or reassign the reference after instantiating the prefab.

  • If you can't fix the old-chunk-instantiate problem, you should explicitly assign the "rock" sprite in Start to provide the same starting for the gen method.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sarthak123 · Apr 22, 2015 at 08:30 AM 0
Share

thank you so much... i think the self referencing was the problem as i mentioned in the comments of other answers, i was actaully instantiating the same prefab from it self, which was i think causing this, to fix this i have now created 2 prefabs ins$$anonymous$$d of one, and referenced them to one anotherr ins$$anonymous$$d of self referencing, this fixed the problem as far as i've noticed, i am still testing by changing the script to expicitly change it to "Rock" when no other chances match... thank you so much...

avatar image Sarthak123 · Apr 22, 2015 at 08:31 AM 0
Share

@Bunny83 can you please confirm me one thing, that creating 2 prefabs ins$$anonymous$$d of one to avoid self referencing is the right way of doing so or not...

avatar image Bunny83 · Apr 24, 2015 at 02:41 AM 0
Share

@Sarthak123: Well, there is no "right" or "wrong". Using two prefabs (which reference each other) is one way to prevent this problem. Another way is to use a manager object / singleton which just has a list of prefabs you might need somewhere else.

Another way, like i mentioned in my answer is to reassign the reference when you instantiate the object. Example:

 //  script that instantiates the first instance.
 public class SomeOtherScript : $$anonymous$$onoBehaviour
 {
     public PScript prefab;
     void CreateInstance()
     {
         var inst = Instantiate(prefab);
         // here we "fix" the reference in the new instance.
         inst.prefabReference = perfab;
     }
 
 }
 
 // script on the prefab
 public class PScript : $$anonymous$$onoBehaviour
 {
     public PScript prefabReference;
     void CreateNewInstance()
     {
         var inst = Instantiate(prefabReference) as PScript;
         // same if the instance creates a new instance
         inst.prefabReference = prefabReference;
     }
 }

avatar image Sarthak123 · Apr 24, 2015 at 07:30 AM 0
Share

will try... thnx :D

avatar image
1

Answer by JoeStrout · Apr 21, 2015 at 01:27 PM

OK, the problem is that in your loop, you are comparing your randomly-drawn number (from 0 to 1) to each of the probabilities. This doesn't work. Suppose, just for the sake of argument, that you had four ore types, all with an equal probability of 0.1. The first time through the loop, you'd compare sel to 0.1, and either it's < 0.1 or it's not. If it is, you pick the first ore. If not, you go on and compare sel to 0.1 again for the second ore... but it's still not < 0.1 (of course!). So you'll either get the first ore, or nothing, with this code.

The fix is easy: you need to add this inside your loop, but after the if-block:

 sel -= oreChance[i];

Now consider the example above, with four ores all with a 0.1 chance. Suppose you draw 0.35 as your sel value. Compare to the first ore: 0.35 < 0.1? Nope, so we subtract 0.1 from 0.35 and continue. Second ore: 0.25 < 0.1? Nope. Third ore: 0.15 < 0.1? Still nope. Fourth ore: 0.05 < 0.1? YES! So in fact anything in the range 0.3 - 0.4 would map to the fourth ore, exactly as you'd want in this case.

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sarthak123 · Apr 21, 2015 at 02:14 PM 0
Share

umm... there are 2 things, i am unclear of, yes, the above method you suggested, increases my ore chances, but you are wrong when you said you will get first or nothing, i am getting all kinds of ore even after not using the above method...and if my script matches with first, it never checks for second, i am using the break statement, it will break the loop...

you are right i can use loop in forward as well as reverse, but to use in reverse, i used the break statement, there's a reason why used it in reverse but nvm this is not important, my real problem is unsolved,

$$anonymous$$y real problem is,

blocks keep repetiting, i am instantiating them from the prefab so that might be the issue, i have uploaded the screen shots to clarify my problems, please help it's unsolved no matter what i do....

avatar image JoeStrout · Apr 21, 2015 at 02:32 PM 0
Share

You will get first or nothing IF you had four blocks with the same probability, as I said ("Suppose, just for the sake of argument, that you had four ore types, all with an equal probability of 0.1.") This was just an example to illustrate why your code was incorrect. The correction I've posted here will fix that.

avatar image JoeStrout · Apr 21, 2015 at 02:33 PM 0
Share

However, it appears that there is more than one problem here. The change I've suggested only fixes one problem.

As to the other problem: if it is fine at first, but then goes wrong when you walk around, then the problem is not in the code you have posted at all. It has something to do with what happens when you move around -- probably that "infinite terrain generation" script you mentioned. I suggest posting a new question focused on that.

avatar image Sarthak123 · Apr 21, 2015 at 02:46 PM 0
Share

actually, the seconds problem was the main from the start, this questions is focused on that, i found a working fix myself, what i was doing was, instantiating from a prefab, a single prefab, which in case was the cause of the problem i think... ins$$anonymous$$d of using single prefab i used 2 prefabs, both of them linked to one another(ins$$anonymous$$d of linking to themselves). This fixes the problem as far as i've noticed, but i would still like to know, why, how, what happened that caused this...

and yes, i never noticed you were absolutely right, when all the ores havfe same chance, my script wont work, thanks for pointing out that, but i wuld like to know about the "Second" problem as that is my main concern

avatar image Bunny83 · Apr 21, 2015 at 04:44 PM 0
Share

@JoeStrout: His code works fine. You just made the assumption that the probability values he uses should be (programmer) percentages (0-1). He just uses probability thresholds and since he's iterating over them in increasing order (he iterates backwards!!) he get's this percentages:

 Coal    0.010 - 0.050  --> 0.04 (4%)
 Iron    0.005 - 0.010  --> 0.005 (0.5%)
 Gold    0.001 - 0.005  --> 0.004 (0.4%)
 Diamond 0.000 - 0.001  --> 0.001 (0.1%)

It's certainly not a recommended way of handling probabilities but it does work. The problem, as i explained in my answer, is that he doesn't really handle the remaining 95% probably and he expects it to be "rock" when it actually isn't.

It's pretty much the same as printing on a piece of paper that isn't blank. The result will be a mixture of the newly printed stuff mixed with what was on the paper previously.

Show more comments
avatar image
1

Answer by Fappp · Apr 21, 2015 at 03:15 PM

Thank you! I had some fun with this one :)

What's important to consider is that Random.value or Random.Range isn't truly random. Randomness in computers is a topic on it's own and even has it's own specialized hardware.

More on that here: https://www.random.org/

I made a simple script that takes has a few random values, which in turn control two bools. Those all combined set the position of a gizmo ( or cube ) and the distance from this gizmo towards vector 3 zero defines the extended random value generated by this script ( after it's normalized and sin'd).

My point is, I believe repetition is showing because of limitations with the random values. Wonder what this script'll do to your 2d grid ^_^ ( in the script you need to press Return to get a new value )

 var randomValue : float;
 var randomRange : float;
 var randomRangeExtended : float;
 
 var randomPositionGizmo : Vector3;
 var rndPosVisual : GameObject;
 
 var pos : boolean;
 var xTrue : boolean;
 
 function Start () {
     randomValue = Random.value;
     randomRange = Random.RandomRange(0.0,1.0);
 }
 
 function Update () {
 
     var rndDir : float = Random.value;
     var rndX : float = Random.value;
     
     if ( rndDir >= 0.4999 ){
         pos = true;
     }
     else{
         pos = false;
     }
     if ( rndX >= 0.4999 ){
         xTrue = true;
     }
     else{
         xTrue = false;
     }
     
         if ( xTrue && pos){
             randomPositionGizmo.x -= rndDir;
         }
         if ( !xTrue && pos){
             randomPositionGizmo.z += rndDir;
         }
         if ( xTrue && !pos){
             randomPositionGizmo.x += rndDir * 3;
         }
         
         if ( !xTrue && !pos){
             randomPositionGizmo.z -= rndDir * 3;
         }
         
         rndPosVisual.transform.position = randomPositionGizmo;
         
 
     if ( Input.GetKeyDown(KeyCode.Return) ){
     
         randomValue = Random.value;
         randomRange = Random.RandomRange(0.0,1.0);
         randomRangeExtended = Mathf.Abs(Mathf.Sin(randomRange * Random.Range(0, Vector3.Distance( Vector3.zero, randomPositionGizmo) )));
     }
 
 }
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sarthak123 · Apr 21, 2015 at 03:52 PM 1
Share

hmm... nice concept... i was also curious about how computers generate randomness, and i also knew that there might be repetitions, but fixed repetitions and very quick repetitions like what i am experiencing are not related with randomness nature, this script proved that, i think it's something related with unity's prefab instantiation thing...

actually i was just playing around with my instantiation commands and i was able to fix my problem,

what i was doing was, instantiating from a prefab, a single prefab, which in case was the cause of the problem i think... ins$$anonymous$$d of using single prefab i used 2 prefabs, both of them linked to one another(ins$$anonymous$$d of linking to themselves). This fixes the problem as far as i've noticed, but i would still like to know, why, how, what happened that caused this...

i am still playing with the above script you gave, i will upload more results...

avatar image JoeStrout · Apr 21, 2015 at 04:13 PM 0
Share

There shouldn't be any problem instantiating prefabs as many times as you want, but there can be problems when a prefab has references to other prefabs. These references will still point at the other prefab in the instance, and so if you use that to change something, you're actually changing the prefab. Not sure if this is involved here, but your mention of "linking" makes me think it might be.

avatar image JoeStrout · Apr 21, 2015 at 04:14 PM 0
Share

And note that Unity's random number generator is very good. I don't think the quality of Random.range has anything at all to do with the problems you're seeing.

avatar image Sarthak123 · Apr 22, 2015 at 08:27 AM 1
Share

yes i have got my problem, it's prefab instantiation and self referencing, thank you everyone, i respect every answer...:)

avatar image Fappp · Apr 22, 2015 at 10:26 AM 0
Share

You're very welcome! Thank you for giving me ideas for randomization!

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Random objects in coordinates specific 1 Answer

Instantiate Prefab at random times but keep 3 from spawning 2 Answers

Random.Range is not changing? 1 Answer

Random.Range doesnt work anymore 4 Answers

RNG State Changes When Loop Iteration is Skipped? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges