I have a Controller class which has a list of GameObjects which are indeed prefabs (in my code called turtlesTypePrefab).
As you can see here, the prefabs I use have sprites inside them with animations (what I'm saying is FirstTurtle has an animator, SecondTurtle as well and so on, and they are all part of my prefab called ThreeTurtles).
So now in my code I want to change the value of a boolean inside one of these animators of my prefab.
Inside of my controller I have:
public GameObject[] turtlesTypePrefab;
And then in my update method I want to do something like:
void Update()
{
for (int i = 0; i < turtles.Length; i++)
{
for (int j = 0; j < turtles[i].Count; j++)
{
GameObject turtle = turtles[i][j];
if (turtle != null)
{
MoveTurtle(turtle, i);
// THIS DOESNT WORK
anim = turtle.GetComponent<FirstTurtle>().GetComponent<Animator>();
anim.SetBool("diving", true);
}
}
}
}
Any ideas?
If each turtle gameobject has its own animator component what you can do is initialize the parent animator from treeturtle gameobject GetComponentInChildren().
What you want to do is to access the one of the children animator via code from the parent. Here is an example
// this script will be attached to the parent
anim = GetComponentInChildren<Animator>();
You used this line of code which the one below:
anim = turtle.GetComponent<FirstTurtle>().GetComponent<Animator>();
The problem with it, is that FirstTurtle is a child gameobject not a component. So you can't really get FirstTurtle as a component. Using GetComponent() only work if you want to use the animator the gameobject you are working on. So I'll suggest you use GetComponentinChildren.
Related
I'm trying to make a script that will dynamically change the near clip plane's distance based on how close the camera is to "nodes" that I place down. The only issue is that I am not sure how to refer to the near clip plane field on the camera component in the C# script in order to change it during runtime. Image of the camera component for reference.
Also, here is the script so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NodeManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
List<Transform> nodeArray = new List<Transform>;
var parentNode = transform;
Transform[] children = GetComponentsOnChildren<Transform>();
foreach (Transform child in children)
{
nodeArray.Add(child);
}
List<float> distanceMagnitudes = new List<float>;
}
// Update is called once per frame
void Update()
{
for(var i = 0; i < parentNode.childCount; i++)
{
Vector3 offset = nodeArray[i].position - this.position;
distanceMagnitudes[i] = offset.sqrMagnitude;
}
float distanceToClosest = sqrt(distanceMagnitudes.min());
if(distanceToClosest < 10)
{
parentNode.Find("Camera Offset").Find("Main Camera").
}
}
}
First of all try not to use Find("Main Camera") to get camera in your scene instead define the camera before and set it's value in the Start() method like this or make it public and set it in the inspector
Camera mainCamera;
private void Start()
{
// find by type if you will only have one camera always
mainCamera = FindObjectOfType<Camera>();
// find by tag if you might have several cameras
mainCamera = GameObject.FindWithTag("Your Camera Tag").GetComponent<Camera>();
}
You can get the near clip wherever by..
mainCamera.nearClipPlane = 1.0f; //Your Value
Im using the following Camera script (link) for all players. The script zooms in and out to capture all players. There are 4 players total in game. Testing with 2 right now. I cannot get the child object of the network player (the Kitty_Orange's transform) to automatically attach to the camera.
Child object has the Player tag.
https://learn.unity.com/tutorial/camera-control?projectId=5c5149c5edbc2a001fd5be95#5c7f8528edbc2a002053b398
I have a GameSetupController.cs that instantiates the player into the scene. This seems the most appropriate place to add the transform of the avatar to the camera. When player enters game scene I get a null reference.
Error when trying to dynamically add transforms to Camera m_Targets transform array.
WITH DEBUG
Debug.Log("CC.m_Targets.Length" + CC.m_Targets.Length); //Troubleshooting
CC.m_Targets = new Transform[players.Length]; // array of size 1-4
NullReferenceException: Object reference not set to an instance of an object
GameSetupController.CreatePlayer () (at Assets/InfoGamerPhoton/Scripts/GameSetupController.cs:33)
GameSetupController.Start () (at Assets/InfoGamerPhoton/Scripts/GameSetupController.cs:14)
WITHOUT DEBUG
CC.m_Targets = new Transform[players.Length]; // array of size 1-4
NullReferenceException: Object reference not set to an instance of an object
GameSetupController.CreatePlayer () (at Assets/InfoGamerPhoton/Scripts/GameSetupController.cs:34)
GameSetupController.Start () (at Assets/InfoGamerPhoton/Scripts/GameSetupController.cs:14)
CameraControl.cs
public Transform[] m_Targets; // All the targets the camera needs to encompass. [HideInInspector]
GameSetupController.cs
using Photon.Pun;
using System.IO;
using UnityEngine;
public class GameSetupController : MonoBehaviour
{
private CameraControl CC;
public GameObject[] players;
// This script will be added to any multiplayer scene
void Start()
{
CC = GetComponent<CameraControl>();
CreatePlayer(); //Create a networked player object for each player that loads into the multiplayer scenes.
}
private void CreatePlayer()
{
Debug.Log("Creating Player");
PhotonNetwork.Instantiate(Path.Combine("PhotonPrefabs", "PhotonPlayer"), Vector3.zero, Quaternion.identity);
players = GameObject.FindGameObjectsWithTag("Player");
if (players.Length == 0)
{
return;
}
for (int i = 0; i < players.Length; i++)
{
Debug.Log("players.Length" + players.Length); //Troubleshooting
Debug.Log("CC.m_Targets.Length" + CC.m_Targets.Length); //Troubleshooting
CC.m_Targets = new Transform[players.Length]; // array of size 1-4
Debug.Log(CC.m_Targets.Length);
Debug.Log(players.Length);
CC.m_Targets[i] = players[i].transform;
Debug.Log("m_Targets : " + CC.m_Targets[i]);
Debug.Log("players : " + players[i]);
}
}
}
My Temp Solution - inside CameraControl.cs
private void FixedUpdate()
{
m_Targets = new List<Transform>();
//ADDS PLAYERS TO THE M_TARGETS LIST!
players = GameObject.FindGameObjectsWithTag("Player");
foreach (GameObject child in players)
{
//Debug.Log(child.gameObject.transform.GetChild(0));
m_Targets.Add(child.gameObject.transform.GetChild(0));
}
Your CC object is null, that's where the Null references are coming from. GetComponent will only find Components attached to the same GameObject as the script invoking it. If the objects are added to the scene statically in editor, you can use [SerializeField] attribute to make the private object visible in inspector and assign the reference manually. Find methods are generally expensive, so if you can avoid using them by storing the references in a common place or setting them up beforehand, that's the recommended approach.
I have a list of Gameobject where I am trying to enable and disable child objects based on a case. The problem is when I try to use SetActive or active I am getting a UnityEngine.Transform does not contain a definition for active and SetActive errors
public List<Transform> components;
for(int i = 0; i <= components.Count ; i++)
{
if(index == i)
{
components[i].Find("amount").SetActive(false);
components[i].Find("confirm").active = true;
}
}
SetActive is used for the gameobject, not the transform.
Simply access the gameobject of the transform instead:
components[i].Find("amount").gameobject.SetActive(false);
I have in the Hierarchy two ThirdPersonControllers.
And i create new c# script file then dragged the script to the first ThirdPersonController.
It should clone more 10 ThirdPersonControllers of the first ThirdPersonController.
This is the script:
using UnityEngine;
using System.Collections;
public class Multiple_objects : MonoBehaviour {
public GameObject prefab;
public GameObject[] gos;
void Awake()
{
gos = new GameObject[10];
for(int i = 0; i < gos.Length; i++)
{
GameObject clone = (GameObject)Instantiate(prefab, Vector3.zero, Quaternion.identity);
gos[i] = clone;
}
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
In the Inspector of the ThirdPersonController in the script area in the Prefab i selected the ThirdPersonController.
But when running the game the Unity the whole program is frozed i had to use Task Manager to shut it down.
I know its the script the problem since i tried it without the script and it was fine.
What i want to do is instead 2 ThirdPersonControllers to have when running the game 10 or 20 ThiredPersonControllers each one in another position by using the c# script.
Screenshot of my Hierarchy:
From what I'm seeing looks like the prefab you are initializing has the "Multiple_objects" Script, so this means every new instance is going to execute that script and create 10 more and so on.
Try putting "Multiple_objects" Script on another GameObject thats not going to be dynamically initialized. (ex: An empty GameObject, Main Camera, Directional Light).
So I have this code attached to a Quad.
public class ShapeGrid : MonoBehaviour {
public GameObject[] shapes;
void Start(){
GameObject[,] shapeGrid = new GameObject[3,3];
StartCoroutine(UpdateGrid());
}
IEnumerator UpdateGrid(){
while (true) {
SetGrid ();
yield return new WaitForSeconds(2);
}
}
void SetGrid(){
int col = 3, row = 3;
for (int y = 0; y < row; y++) {
for (int x = 0; x < col; x++) {
int shapeId = (int)Random.Range (0, 4.9999f);
GameObject shape = Instantiate (shapes[shapeId]);
shape.AddComponent<ShapeBehavior>();
Vector3 pos = shapes [shapeId].transform.position;
pos.x = (float)x*3;
pos.y = (float)y*3;
shapes [shapeId].transform.position = pos;
}
}
}
The script above generates Game Objects at run time, to which I assigned another script:
public class ShapeBehavior : MonoBehaviour {
void OnMouseDown(){
Debug.Log ("Destroy");
Destroy (gameObject);
}
}
The problem is, sometimes the OnMouseDown() executes, sometimes it does not. I cannot figure out why , and how to fix it.
There are plenty of possible reasons.
Collider conflict. OnMouseDown() is raycasting under the hood. If the ray from the mouse position strikes another collider (visible or not), you don't get the OnMouseDown() call.
Distance from the camera. The OnMouseDown implementation uses a depth limit for raycasting which may cause the object to not register the clicks.
RigidBody. OnMouseDown works completely differently if there is a RigidBody somewhere in the hierarchy. It actually won't call OnMouse functions on the clicked object but it will instead call them on the RigidBody's game object instead (yet another bug).
Collider missing. OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider, so you have to add collider to your object.
Multiple cameras. Due raycasting, having several cameras may cause a problem.
Collider is colliding with another collider on the mouse position.
Just wild bug. Closing and reopening Unity Editor as the last hope.
If nothing of this doesn't help you should implement IPointerDownHandler interface and use it instead of OnMouseDown.
Probably you have to add colliders to all of objects because OnMouse events are based on collisions. Here is detailed info: Unity Docs - OnMouseDown
Edit: after some talks we find out that the problem was caused by Instantiate method.
It's allways a better way to fill all of parameters in Instantiate method e.g
Instantiate(prefab, Vector3.zero, Quaternion.Identity)
if you want, you could change any of these parameters after instantiating object.