- Home /
One script on multiple game objects problem
I have a script attached to three similar game objects. These game objects have to check if another game object is within reach using Physics.CheckSphere. The problem is that if only one game object checks that there is no enemy in reach the condition is met. What I want is for all three game objects to detect that there is no enemy in reach to meat the condition.
function Start () {
InvokeRepeating("CheckReach",0.0,2.0);
}
function CheckReach(){
if(!Physics.CheckSphere(transform.position,10.0,sphereIn)&& SphereLogic.fuel<=0.0){
gameOverGUI.active=true;
}
}
the problem is that the condition is met if only one game object is true. I want the condition to be met only if all three game objects return true.
Thanks.
From the API : Returns true if there are any colliders touching the sphere defined by position and radius in world coordinates
so by this, all you need is one collider. It sounds like you want to find if all three are within the sphere, and then check if a variable on each object is true, is this correct?
sorry, I was looking at the code more than the text. I think you are going to need a manager that has a reference to all three objects, and if all report no enemies, then initiate gameOverGUI.
Either that, or have every object find every other object, and when the condition is met they all agree to gameOverGUI. The problem there is you have 3 scripts calling the same thing. I would think about the manager approach =]
Hi alucardj,sorry for the unformatted code. Let's say we have 3 radars at different places checking for planes within a radius using CheckSphere. $$anonymous$$y problem is that when just one radar returns that there is no plane in reach the condition is met(even though the remaining 2 have planes within reach). What I want is that all 3 radars return no planes in reach for the condition to be met. Thank you.
yep, I thought as much. $$anonymous$$y last comment and the answer is basically saying that you need a manager, a master script that looks at all the radars, and checks if all of them are saying "nope, all clear". The answer is in C#, if you need help I can convert it.
Answer by FadyDev · Dec 13, 2012 at 10:15 AM
SOLVED Ok, thanks guys. I couldn't make it with classes. So I created an empty gameObject exposed an array of gameObjects to represent the radars and a hashtable to check for boolean values like this
var radars:GameObject[];
var gameOverGUI:GameObject;
private var sphereIn:LayerMask=1<<21;
function Start () {
InvokeRepeating("CheckReach",0.0,2.0);
}
function CheckReach(){
var noReach=new boolean[radars.Length];
var h:Hashtable;
h=new Hashtable();
for(var i:int=0;i<radars.Length;i++){
if(!Physics.CheckSphere(radars[i].transform.position,10.0,sphereIn)&& SphereLogic.fuel<=0.0){
noReach[i]=true;
}
h.Add(radars[i],noReach[i]);
}
if(h.ContainsValue(false)){
gameOverGUI.active=false;}
else{
gameOverGUI.active=true;
}
}
The good thing about this script is that you can specify the number of radars in the inspector. I used a hashtable to store keys and values, then I checked if for "false" values to see if every radar can't reach any plane.
Note that active is deprecated and you might prefer to use enabled.
Also, why not returning the function once you get one false since that is enough to stop?
Just for info, this answer has a worst case of 2*O(n) meaning that for an array of 10 radars you get a worst case of 20 cycles because you iterate twice through the whole array. You can actually reduce it to O(n) and iterate only to the point where you hit a false. But are you interested in knowing how?
It will never exceed 4 radars. It is always between 1 and 4. But hey it is always good to learn new tricks.
As I said, you are iterating through the whole array here:
for(var i:int=0;i<radars.Length;i++)
and then again here:
if(h.ContainsValue(false))
Actually the second one iterates all over only in the worst case but in algorithm you always consider the worst case.
The common notation is O(n) meaning the number of cycles is depending on n. There may be O(n^2) or O(log n) or O(n^n) or else. They only define how good is your algorithm. Yours are O(n) + O(n) = 2O(n) That is because they both only depends on how many elements in the array.
Now this:
for(var tr : Transform in go){
if((tr.position-_transform.position).sqr$$anonymous$$agnitude>distSqr){
gameOverGUI.active=false;
return;
}
}
gameOverGUI.active=false;
has a maximum of O(n) only. You will only iterate once through the whole array and only if all of them are true or the last one is false. Simply because if one of them is not within range,, the function is returned.
On top of that I do not know the implementation of SphereCast but I would think it might be slightly more expensive that a simple sqr$$anonymous$$agnitude since it needs to check the distance to get collider components, check the layer.
Now your game might not need all that now, but one day you might create the next WoW...:)
Yes , I moved "if(h.ContainsValue(false))" out of the loop. Thanks for the info.
Answer by jogo13 · Dec 13, 2012 at 07:20 AM
You may want to create a 'manager' type gameobject class who oversees all three gameobjects. If you change `CheckReach()` to return a `bool` it could call all three at once.
Rough Example Class:
public class manager : MonoBehaviour {
radar r1;
radar r2;
radar r3;
void Update(){
if(r1.CheckReach() && r2.CheckReach() && r3.CheckReach()) //condition met
{
handle_conditions_met();
}
}
I am a little confused on the double upvote and answer for that one...
the question is " I want the condition to be met only if all three game objects return true." so in a way what is the function to get all three to be checked. This answer is just putting the three functions in a row but no particular implementation of the CheckReach...at least it seems to me.
Also, he says," I wanted a script to work no matter what the number of radars is in each level", this is working for 3 and if you add any, you need to modify the script.
Now what if one of the radar is destroyed? You script crashes and you get Null reference exception.
Also the code is wrong since CheckReach is not a function of GameObject.
I updated the code to be radars and not gameobjects, that was a mistake. :)
Answer by fafase · Dec 13, 2012 at 01:05 PM
You could simply check from the guy itself
import System.Collections.Generic;
var go = new List.<Transform>();
var distSqr:float = 100;
var _transform:Transform;
var within :boolean;
function Start(){
var gos = GameObject.FindGameObjectsWithTag("GO");
for(var g : GameObject in gos)
go.Add(g.GetComponent(Transform));
_transform = GetComponent(Transform);
InvokeRepeating("Check",0.01f,2.0f);
}
function Update(){
if(within)print("All in");
else print("Not in all");
}
function Check(){
for(var tr : Transform in go){
if((tr.position-_transform.position).sqrMagnitude>distSqr){
within = false;
return;
}
}
within = true;return;
}
EDIT: Now it will go for as many items you can add. The function simply iterate through the list of transform. When the distance is too large, within is set to false, the function returns. If all are smaller than distSqr, the whole loop iterates, the function leaves the for loop and ends up with within = true;.
EDIT AGAIN: Ok I tested it now and it does work for sure. My bad, I had a few typos mistakes... But now it is 100% working. I can even remove radars at runtime, it s still running. Concerning distSqr, you need to think in terms of squared value. So if you want to check a distance of 5m, distSqr is 5*5 = 25.
Note that in the answer everything is optimized with caching of the transform, use of sqr$$anonymous$$agnitude to avoid sqr root and time-spaced calls with InvokeRepeating.
This script will work for a constant number of radars. I wanted a script to work no matter what the number of radars is in each level.If someone could help in iterating through the boolean array to negate the condition if only one "false" value is found.
fafase thanks for your effort but the script above gave me a long list of errors for reasons I am not sure about,especially in the List declaration line.
I changed it. I was missing the dot. Also make sure to add the import at the top.