- Home /
Random Numbers and Array Assignments
OK, this is most likely an easy one.
I have a gameObject with 10 children (asteroid meshes).
I have a script that "targets" any of the 10 children successfully (prints debug.log msgs saying "Asteroid Targeted").
I also have an "AsteroidLogic" script (the targeting script reads data from this). Basically, all the Logic script does is give you a composition percentage of the asteroid (e.g: 60% noble content).
I have two problems:
How do I make it so that clicking on EACH asteroid gives me DIFFERENT random values? Currently, they're ALL saying %36 percent, or ALL saying 80%. Each roid should be different.
How do I STORE these values? Should I store them in the parent object? Correlate them to unique gameObject ids? Use an array? Hash table? When I say "STORE", I mean if someone leaves the asteroid field, and it is destroyed -- but they later return to the same field. Once the prefab is re-instantiated, Ideally the values should be the same as the last visit.
I'll point out that these two scripts are the product of other Unity Answers/Forums threads, and while they might be cool, I assure you I am not very good at this, so to get to this point was a miracle to say the least.
TARGET SCRIPT:
// Found at:
// http://forum.unity3d.com/threads/84582-Enemy-health-only-to-appear-when-target-is-clicked-on.
static var playerTarget : Transform;
function Update() {
//check if the left mouse has been pressed down this frame
if (Input.GetMouseButtonUp(0)) {
//empty RaycastHit object which raycast puts the hit details into
var hit : RaycastHit;
//ray shooting out of the camera from where the mouse is
var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, hit, 55000)){
if (hit.collider.gameObject.CompareTag("Asteroid")) {
//print out the name if the raycast hits something
playerTarget = hit.collider.transform;
var mf: MeshFilter = playerTarget.GetComponent(MeshFilter);
bounds = mf.mesh.bounds;
corners = new Vector3[8];
var asteroidLogic : AsteroidLogic = gameObject.GetComponent("AsteroidLogic");
var objectName : AsteroidLogic = gameObject.GetComponent("AsteroidLogic");
Debug.Log( playerTarget.name + " is " + asteroidLogic.worthyCompoundRemainder + " percent noble, " + hit.distance + " meters." );
}
else {
Debug.Log(hit.collider.name + " no tag");
}
}
}
}
ASTEROID LOGIC script:
static var worthyCompoundRemainder : int;
static var objectName : String;
static var inertCompoundPercentage = Random.Range(0, 100);
function Start () {
}
function Update () {
for(var n = 0; n < 10; n++) {
worthyCompoundRemainder = 100 - inertCompoundPercentage;
}
}
I would love any help, thanks!
PS - edited with help from Eric5h5 to be more visually pleasing.
Answer by Chris D · Jul 26, 2011 at 11:12 PM
static var inertCompoundPercentage = Random.Range(0, 100);
You'll only ever have one value of this variable at one time. If you want each asteroid to have it's own value, don't make this and your worthyCompoundRemainder
static.
For taking the values between visits, however, you could use a static variable in the form of a collection or list. For a good run down of which type you should use, check out this wiki entry. It depends on what kind of data you want to hold on to.
And thanks for the link - I've read that earlier, still trying to digest it, lol.
Please add comments on your question rather than adding answers (otherwise it looks like you're getting tons of answers).
The reason you're getting that error is because you're attempting to assign the random range directly in the constructor. Ins$$anonymous$$d of how you have it set up, try putting it in Start().
As a supplement to my answer above, remember that you need to store each unique value you're generating. As it stands, you're just assigning (100 - aRandomNumber) 10 times and doing nothing with it.
Sorry, hit the wrong Button.
I did in fact, try putting it in "Start", just after I realized I sent the old copy - sorry =)
The message stopped telling me to try putting it in "Start", however the RandomRangeInt error remained.
I am playing with different permutations now.
thanks,
Strange, I figured that was all tied together. Can you post the full text of the new error?
Actually there is no new error. =) It went away. One of the issues is 'technically' solved, but now I am struggling with the second issue: how to create an array, and store each integer as a member of said array. I am lousy with (code) but worse with arrays, lol.
See my later post (below) on the current symptoms. We're getting close =D
Thanks
Answer by subcon · Jul 26, 2011 at 11:20 PM
Unfortunately, doing that breaks the whole thing.
Updated AsteroidLogic.js:
var worthyCompoundRemainder : int;
static var objectName : String;
var inertCompoundPercentage = Random.Range(0, 100);
function Start () {
}
function Update () {
for(var n = 0; n < 10; n++) {
worthyCompoundRemainder = 100 - inertCompoundPercentage;
}
}
I now get this over and over once PLAY is hit:
ArgumentException: RandomRangeInt can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.Random.Range (Int32 min, Int32 max)
AsteroidLogic..ctor () (at Assets/Scripts/AsteroidLogic.js:4)
Thanks,
Please don't post comments as answers, but you should only define variables outside functions, and not run code like Random.Range(0, 100);
O$$anonymous$$, some progress made thanks to your last comment. I think my #1 is solved.
static var worthyCompoundRemainder : int;
static var objectName : String;
function Start () {
}
function Update () {
for(var n = 0; n < 10; n++) {
var inertCompoundPercentage = Random.Range(0, 100);
worthyCompoundRemainder = 100 - inertCompoundPercentage;
}
}
NOTE: the first line needs to be static, otherwise I get:
NullReferenceException: Object reference not set to an instance of an object
ClickToTarget3.Update () (at Assets/Scripts/ClickToTarget3.js:23)
... which breaks the targeting script.
$$anonymous$$oving on ... now I get a random number for each asteroid .... but now #2 takes effect. I cannot seem to get the array syntax right to store these values.... the result Is that I click on one asteroid, and it generates a new number. I click on the same roid again, and I get a new random number. I think storing these values, once I get it right, should solve this.
Thanks,
Ok, so.
Take your initialization code out of Update, put it into Start. This will ensure that the randomization only runs the once.
For the null reference,
it means you're not allowing your other script proper access to the variables in this one. This line:
Debug.Log( playerTarget.name + " is " + asteroidLogic.worthyCompoundRemainder + " percent noble, " + hit.distance + " meters." );
is the culprit. It doesn't have to be static, it just has to be defined/accessible. You're trying to access it as if there's only one value for
see below.WorthyRemainder
but (once done properly) there isn't/won't be.
O$$anonymous$$, I am severely puzzled now.
Your first suggestion was to take my initialization code out of Update and put into start. Doing this returned me to problem #1 - the random number was constant across all roids (every roid was 56%).
Second, the variables in the "culprit" line are in fact defined - they're read from the definitions in the AsteroidLogic script (there are two scripts). So maybe I am just not fully understanding your second comment.
To confirm that it is in fact "defined/accessible", I did a Debug.Log print of the value, and it returns something.
So, again, confused :S
Thanks again,
Yes, the script was attached to every asteroid, so the GetComponent thing did technically work =)
I tried your above code (called it AsteroidLogic2), but now I am back at the same point where all roids are the same. $$anonymous$$ore interestingly, they're all saying "0" noble content now, I'm trying to figure out why.
I'll check back soon, hopefully with some findings of my own.
Thanks again,
Answer by Chris D · Jul 27, 2011 at 04:17 PM
var worthyCompoundRemainder : int; //public but not static
var objectName : String; //as of now you're not doing anything with this
var inertCompoundPercentage : int; //public but not static
function Start () {
inertCompoundPercentage = Random.Range(0, 100); //make sure random code is in it's proper place (i.e. here)
worthyCompoundRemainder = 100 - inertCompoundPercentage;
}
function Update () {
//whatever other logic you want your asteroids to have
}
This code needs to be attached to each asteroid gameObject.
Sorry for that comment above; it's not a very good (or accurate) explanation. It was my end of day and my brain was a little fried.
Taking another look through your amassed code, there's a number of things going wrong. In your targeting script, you're calling var asteroidLogic : AsteroidLogic = gameObject.GetComponent("AsteroidLogic");
which, if this script is attached to each asteroid, would be fine. I suspect this is not the case, however as this targeting script looks like it's supposed to be associated with the camera or some player-type object. That code is assuming that there's a component called "AsteroidLogic" attached to the current gameObject
and, if that's not the case, will assign a null value to it (leading to the null reference exception you see when you try to call on it below).
var playerTarget : GameObject;
function Update() {
//check if the left mouse has been pressed down this frame
if (Input.GetMouseButtonDown(0)) {
//empty RaycastHit object which raycast puts the hit details into
var hit : RaycastHit; //pretty sure you don't actually need this
//ray shooting out of the camera from where the mouse is
var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, hit, 55000)){
if (hit.collider.gameObject.CompareTag("Asteroid")) {
//print out the name if the raycast hits something
playerTarget = hit.collider.gameObject;
var mf: MeshFilter = playerTarget.GetComponent(MeshFilter);
bounds = mf.mesh.bounds;
corners = new Vector3[8]; // not sure what all this stuff is doing
var asteroidLogic : AsteroidLogic =
gameObject.GetComponent("AsteroidLogic");
Debug.Log( playerTarget.name + " is " +
asteroidLogic.worthyCompoundRemainder
+ " percent noble, " + hit.distance + " meters." );
}
else {
Debug.Log(hit.collider.name + " no tag");
}
}
}
}
This is the version of the code I was talking about. The new comments system wasn't showing it for me and I figure it's pretty much my answer anyways, so here it is as a proper answer : )
O$$anonymous$$, trying your code verbatim I get "null reference exception" when attempting to click on a roid.
Then I updated the GetComponent target to AsteroidLogic2 (which is the sum of your earlier update to AsteroidLogic). The error then went away, but all asteroids reported 0 noble content when targeted (though your AsteroidLogic2 script DID in fact show proper ratios in the inspector.
I even added:
var worthyCompoundRemainder : AsteroidLogic =
gameObject.GetComponent("AsteroidLogic2");
.... thinking it was needed for "asteroidLogic.worthyCompoundRemainder", but made no difference (still zero, but no errors).
This is making me dizzy, how 'bout you? =)
Thanks for sticking with me through this. I am optimistic that this can be duplicated (or re-used somehow) for other purposes too, so hopefully a lot of people will benefit from this thread as I have.
I'm going to have to try setting up a demo scene for myself tonight. I'll report back when I can.
Couldn't figure it out Chris? I see your last post was removed .....
Your answer
Follow this Question
Related Questions
Random LookAt or Random Target 2 Answers
Random Number Generator 4 Answers
Randome Number for Dice 2 Answers
How to prevent picking the same combination in array? 1 Answer
Generate random number 4 Answers