- Home /
Accesing components on multiple objects in c#?
Hi there.
What I'm trying to do is to have triggers in the scene that will allow the player to rotate the camera around him, only when he is inside one of those objects colliders.
I have multiple object that all have the same script attached (in this instance named RotateArea.cs).
And I want to access all those objects from another objects script component (CameraRotator.cs).
Is there a way in Unity to access all of those at the same time? I'm currently using FindGameObjectWithTag, as it gets an error as soon as I use FindGameObjectsWithTag. Appearently I can't use .GetComponent after a FindGameObjectsWithTag.
What to do?
CameraRotator
using UnityEngine;
using System.Collections;
public class CameraRotator : MonoBehaviour
{
public float rotateTime = 1.0f;
private bool _isTweening = false;
private CrunchPlatformColliders _cruncher;
private DisablePlayer _disablePlayer;
RotateArea rotateFunction;
void Start ()
{
_cruncher = GetComponentInChildren<CrunchPlatformColliders>();
GameObject player = GameObject.FindGameObjectWithTag("Player");
_disablePlayer = player.GetComponentInChildren<DisablePlayer>();
rotateFunction = GameObject.FindGameObjectWithTag("rotateZone").GetComponent<RotateArea>();
}
void Update(){
if(rotateFunction.isInRotateZone)
{
if (Input.GetKeyDown(KeyCode.Z))
{
rotateTween(90);
}
if (Input.GetKeyDown(KeyCode.X))
{
rotateTween(-90);
}
}
}
private void rotateTween(float amount)
{
if (_isTweening == false)
{
_isTweening = true;
// _cruncher.setPlayerPos();
_disablePlayer.disable();
Vector3 rot = new Vector3(0,amount, 0);
iTween.RotateAdd(gameObject, iTween.Hash(iT.RotateAdd.time, rotateTime, iT.RotateAdd.amount, rot, iT.RotateAdd.easetype, iTween.EaseType.easeInOutSine, iT.RotateAdd.oncomplete, "onColorTweenComplete"));
}
}
private void onColorTweenComplete()
{
_isTweening = false;
_disablePlayer.enable();
_cruncher = GetComponentInChildren<CrunchPlatformColliders>();
//_cruncher.crunchCollidersToPlayer();
}
}
RotateArea
using UnityEngine;
using System.Collections;
public class RotateArea : MonoBehaviour {
public bool isInRotateZone = false;
public GUIText referencetotext;
// Use this for initialization
void OnTriggerEnter ()
{
isInRotateZone = true;
referencetotext.text ="Press Z or X to change lane";
}
void OnTriggerExit()
{
isInRotateZone = false;
referencetotext.text ="";
}
// Update is called once per frame
void Update () {
}
}
Any help is appreciated
What error are you getting exactly? I would guess that it's not finding any object tagged 'rotateZone' and you get a null pointer exception.
It says: "Assets/Scripts/Camera/CameraRotator.cs(18,82): error CS1061: Type UnityEngine.GameObject[]' does not contain a definition for
GetComponent' and no extension method GetComponent' of type
UnityEngine.GameObject[]' could be found (are you missing a using directive or an assembly reference?)"
@StigC - FindGameObjectsWithTag() returns an array of colliders. You have to use a loop to go through and get the component on each one. The compiler is complaining because you tried to call GetComponent() on the whole array rather than an element in the array.
Answer by robertbu · Mar 11, 2014 at 12:29 AM
Let me write about your problem in general first. The way you are approaching this problem is down toward the bottom of the list of my choices. So if you can define the zone as a distance from a point, my first choice would be to have both RotateArea and CameraRotator use distance from a point to do its calculations.
Second choice would be to put OnTriggerEnter() and OnTriggerExit() on the player. This could could check for the kind of object (tag), and then set a flag. Your camera script could then read the information from the player.
My third choice would be to use Events and Delegates and have the RotateAreas communicate to the CameraRotator script. Here is a link for more info on Events and Delegates:
http://answers.unity3d.com/questions/600416/how-do-delegates-and-events-work.html
So here is a specific answer to your question:
At the top of the file:
RotateArea[] ras;
In Start():
GameObject[] gos = GameObject.FindGameObjectsWithTag("rotateZone");
ras = new RotateArea[gos.Length];
for(int i = 0; i < gos.Length; i++) {
ras[i] = gos[i].GetComponent<RotateArea>();
}
At the end of Start() you will have an array of references to all of your RotateAreas. So in the body of your script you can add this function:
bool CanRotate() {
foreach (RotateArea ra in ras) {
if (ra.isInRotateZone)
return true;
}
return false;
}
Just call this function when you want to determine if you should be able to rotate or not.
I've tried and tried ins$$anonymous$$d of asking instantly. But I can't get this to work...
Is this javascript? Where should I put the bool CanRotate()... ?
At the end of Start() you will have an array of references to all of your RotateAreas.
How? I really have no clue how.
Thanks.
This is C#. Here is my suggestion integrated into the code that you posted:
using UnityEngine;
using System.Collections;
public class CameraRotator : $$anonymous$$onoBehaviour
{
public float rotateTime = 1.0f;
private bool _isTweening = false;
private CrunchPlatformColliders _cruncher;
private DisablePlayer _disablePlayer;
RotateArea[] ras;
void Start ()
{
_cruncher = GetComponentInChildren<CrunchPlatformColliders>();
GameObject player = GameObject.FindGameObjectWithTag("Player");
_disablePlayer = player.GetComponentInChildren<DisablePlayer>();
GameObject[] gos = GameObject.FindGameObjectsWithTag("rotateZone");
ras = new RotateArea[gos.Length];
for(int i = 0; i < gos.Length; i++) {
ras[i] = gos[i].GetComponent<RotateArea>();
}
}
void Update(){
if(CanRotate())
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Z))
{
rotateTween(90);
}
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.X))
{
rotateTween(-90);
}
}
}
private void rotateTween(float amount)
{
if (_isTweening == false)
{
_isTweening = true;
// _cruncher.setPlayerPos();
_disablePlayer.disable();
Vector3 rot = new Vector3(0,amount, 0);
iTween.RotateAdd(gameObject, iTween.Hash(iT.RotateAdd.time, rotateTime, iT.RotateAdd.amount, rot, iT.RotateAdd.easetype, iTween.EaseType.easeInOutSine, iT.RotateAdd.oncomplete, "onColorTweenComplete"));
}
}
private void onColorTweenComplete()
{
_isTweening = false;
_disablePlayer.enable();
_cruncher = GetComponentInChildren<CrunchPlatformColliders>();
//_cruncher.crunchCollidersToPlayer();
}
bool CanRotate() {
foreach (RotateArea ra in ras) {
if (ra.isInRotateZone)
return true;
}
return false;
}
}
Thank you so very much! Really appreciate it. It helps a lot seeing how it's supposed to be set up. I really didn't understand how to use bool CanRotate, or what to make of the void Update. Thanks alot!
Answer by TropicalTrevor · Mar 16, 2014 at 04:59 PM
this is C#. sadly I don't really know UnityScript so you may need someone to translate this to js ;)
In your RotateArea script you can declare a static variable such as
public static List<RotateArea> areas = new List<RotateArea>();
then in RotateArea.Awake() you will get this:
if(!RotateArea.areas.Contains(this));
RotateArea.areas.Add(this);
then in any other script you can access RotateArea.areas and know about all the currently existing rotate areas
to do this cleanly you will need to have an OnDestroy function in RotateArea that handles the deletion of the object:
void OnDestroy(){ RotateArea.areas.Remove(this); }
I like this method because it is contained within the RotateArea script and allows more generic access of these objects without ever resorting to Find functions.
Also Events can be a problem because when you use event listeners it becomes very difficult to debug, you can't really see what objects are listening to what events of what other objects and this way your code becomes fairly unclear.
Your answer
Follow this Question
Related Questions
C# GetComponent Issue 2 Answers
C# GetComponent / change values throught other script 3 Answers
how to make one script change a variable in another scipt 2 Answers
Accessing Enumeration from another script issue 1 Answer
Getcomponent error? 1 Answer